Florian Paul Schmidt
Pensé en documentar la información que tengo sobre cómo utilizar un sistema Linux con un kernel apropiativo —N. del T.; Preemptive en el original— a tiempo real como sistema de trabajo con audio y MIDI. Así puedo referirme a esta documentación en lugar de repetirla una y otra vez en discusiones.
Todo lo que sigue se aplica a los kernels -rt con el modelo apropiativo completo —N. del T.; complete preemption en el original—. En mi opinión es la mejor forma de operar con un kernel -rt si se quiere en control más estricto sobre prioridades y latencias. Procede un aviso y es que los drivers binarios y los módulos para nVidia podrían ser incompatibles con este tipo de kernel. Utilícese el driver nv de las X11 en su lugar. Aún si el módulo binario fuese compatible, no habría garantías de que encaje en el modelo particular de este kernel y podría destruir las bajas latencias que el resto del código del kernel nos garantiza.
El sistema de audio y MIDI
En un sistema de audio y MIDI típico basado en Linux encontramos varios componentes clave:
* JACK, el kit de conexiones de audio. Facilita servicios de audio y por supuesto utiliza la tarjeta de sonido. La IRQ de la tarjeta de sonido requiere un tratamiemto especial —es decir, una alta prioridad— para no ser interrumpida por otras cargas del sistema —el disco duro o la red—. JACK es la opción favorita para este trabajo dado que permite conectar las aplicaciones de audio las unas con las otras. Además está diseñado para el trabajo a tiempo real desde el primer día. Con un sistema correctamente configurado pueden lograrse latencias ridículamente bajas, p.ej. tamaños de buffer de 8 ó 16 muestras a 48 KHz.
* ALSA, facilitando servicios de audio a JACK y el acceso al MIDI vía alsa-seq.
* Algún secuenciador MIDI como rosegarden, muse o seq24 que utilice JACK y alsa-seq.
* Algunos sintetizadores software —al final, clientes JACK— manejados por el secuenciador MIDI
* Más hardware que precisa de una IRQ para funcionar —red, disco duro, etc.—
* El resto del software, como el gestor de ventanas, el escritorio y otras utilidades.
Cualquier kernel -rt en combinación con realtime lsm o rt_limits facilita al usuario herramientas que le permiten un trabajo cómodo que asegura:
* Operación de audio sin problemas, y con «sin problemas» me refiero a sin problemas. Por ejemplo, puedo fácilmente compilar un kernel mientras trabajo con audio a 32 muestras por buffer.
* Sincronización MIDI exacta.
Claro está que habrá que ajustar el sistema para obtener el mejor resultado. Podría ser necesario llegar a modificar algunas aplicaciones.
Configuración de audio
Podemos simplificar y decir que cuanto más alta sea la prioridad de una tarea más posible es que se ejecute sin molestias. Con un kernel -rt se tiene la posibilidad de que ciertos manejadores de IRQ tengan menos prioridad que aplicaciones que corren en el espacio de usuario. Es posible, por ejemplo, correr jackd con una prioridad mayor que la de cualquier manejador de IRQ que podría interrumpir el trabajo con audio, como el disco duro o la red. Es necesario el parámetro -P de jackd para esto.
En un kernel -rt, por defecto todos los manejadores de IRQ tienen prioridades entre 40 y 60, así que hacer que jackd se ejecute con una prioridad de 70 parece una buena elección.
jackd -R -P 70 -d alsa ...
Sólo que si queremos que el manejador de la IRQ de la tarjeta de sonido tenga una prioridad más alta que jackd, dado que la IRQ de la tarjeta de sonido es al final la que gobierna el funcionamiento de JACK. Utilizamos así la utilidad chrt para cambiar esto. En mi sistema la tarjeta de sonido tiene la IRQ 4, comprueba /proc/interrupts en tu máquina para averiguar la tuya.
chrt -f -p 82 `pidof "IRQ-4"`
—N. del T.; Comprueba las distintas prioridades asignadas así:—
top -b -H -n 1 | grep -i irq | sort -n -k3
Una prioridad de 82 está bien por encima de la concedida a jackd. Dado que jackd ejecuta hilos además de su bucle principal, es necesario vigilar esto. Por ejemplo, implementa un watchdog que se ejecuta a una prioridad 10 superior a la del bucle principal. Es decir, a 80 en nuestro caso. Los hilos de proceso de cliente, en cambio, corren con una prioridad 1 inferior a la del bucle principal, 69 en nuestro caso.
La parte audio de nuestro sistema queda cubierta. Con esta configuración consigo operar con tamaños de buffer ridículamente bajos con JACK y mi M-Audio Delta 66 —hasta 8 muestras por periodo, reconociendo algún problema con el cambio de contextos forzando tanto mi sistema— Y ahora, ¿qué pasa con MIDI? ¿Cómo lo hacemos funcionar aquí?
Configuración MIDI
Tenemos que saber una cosa o dos sobre cómo la planificación a tiempo real funciona para afinar esta parte. La clase de planificación utilizada por la mayor parte de aplicaciones de audio es SCHED_FIFO. Se trata de una clase especial con niveles de prioridad estáticos de 1 a 99 y que garantiza que las tareas que la utilizan pueden conservar la CPU tanto tiempo como requieran, siempre que otra tarea SCHED_FIFO de mayor prioridad no la reclame. Por supuesto esto significa que un programa lo suficientemente puñetero puede bloquear el sistema simplemente acaparando toda la CPU siempre que no haya otra tarea con una prioridad mayor que pase por encima. Así que las tareas que tienen más prioridad ahora en nuestro sistema son los hilos de jackd y el manejador de la IRQ de la tarjeta de sonido.
El procesado de audio se realiza por lotes y para ilustrarlo permítaseme asumir que utilizamos un tamaño de buffer muy grande, digamos de 1 segundo —no sé si alguna tarjeta de sonido permite un buffer de este tamaño, pero para ilustrar el argumento supongamos que sí—. Se trata de 48.000 muestras a 48 KHz. Asúmase también que los clientes JACK están cargando realmente el sistema. Por ejemplo que el indicador DSP de jackd muestra un 50%. Esto significa que cada segundo el sistema completo se detiene para que jackd y sus clientes se tomen ese medio segundo para realizar sus procesos. Es fácil adivinar que el efecto en la sincronización MIDI va a ser terrible.
En realidad MIDI necesita más «tiempo real» que el audio. El audio se procesa en lotes de tamaño respetable —entre 1 y 50 ms dependiendo del tamaño de buffer utilizado—. Pero cuando un secuenciador MIDI necesita enviar un evento a un puerto, debe hacerlo con garantías de que llegará a tiempo a su destino —hay una excepción derivada de la implementación del secuenciador MIDI en ALSA, el cual permite aplazar eventos hasta un tiempo posterior, y de la que se derivan los problemas de ALSA con el MIDI—. El procesado MIDI, en cambio, es ligero comparado con el de audio. El bucle principal de un secuenciador MIDI necesita ejecutarse muchas veces por segundo para ser capaz de procesar eventos MIDI con una resolución lo suficientemente detallada. Así que la parte MIDI de un secuenciador debería correr con una prioridad mayor que jackd. La interfaz alsa-seq permite que los eventos MIDI sean aplazados para ser entregados en un momento preciso, lo que aligera el requisito de «debo enviarlo ahora mismo». Pero se trata de una funcionalidad compleja de gestionar y no demasiados programadores la utilizan. Así que tiene mucho más sencillo configurar el sistema para que los datos MIDI tengan una entrega inmediata.
El artículo completo es Configura y optimiza Linux para audio y MIDI visto en Linux AV.