Ir al contenido

Dispositivos y latencia

La latencia es el tiempo entre que algo ocurre (una tecla, un knob que gira, tu voz en el micrófono) y lo oyes. El motor calcula 64 muestras cada vez, pero la tarjeta de sonido pide un buffer entero de golpe: ese buffer, más lo que añade el sistema, es la latencia. Buffers más pequeños dan menos retraso pero menos tiempo para calcular cada uno; si es demasiado pequeño, el sonido cruje.

Bloques de 64 muestras llenando las cuatro casillas de un buffer de 256 que luego va a los altavoces
Un buffer de 256 muestras son 5,3 ms a 48 kHz: cuatro bloques del motor.

Sin ajustes, audio.Engine() usa la mejor API de audio del sistema, su dispositivo por defecto a su propia frecuencia de muestreo y el buffer más pequeño que suena sin cortes en una máquina normal:

Sistema API de audio (host) Buffer Latencia a 48 kHz
Windows WASAPI (ASIO si se compila con él) 256 muestras (WASAPI en modo compartido puede elegir el suyo) ~5–10 ms
macOS CoreAudio 128 muestras ~3 ms
Linux PulseAudio, que también llega a PipeWire; ALSA si no hay servidor de sonido 256 muestras ~5 ms

audio.recommended_settings() devuelve estas elecciones para la máquina actual.

from pyzed import audio
audio.hosts() # ['PulseAudio', 'ALSA']: las APIs disponibles aquí
audio.default_host() # 'PulseAudio'
for d in audio.devices(): # los dispositivos del host por defecto (o devices("ALSA"))
print(d.name, d.outputs, d.inputs, d.sample_rate, d.buffer_range)
engine = audio.Engine(
host="ALSA", # una API de audio.hosts()
device="USB Audio", # el nombre o el id de un dispositivo (None: el de por defecto)
sample_rate=48000, # None: la frecuencia propia del dispositivo
buffer_size=128, # muestras; None: el tamaño recomendado
input=True, # abre también la entrada por defecto (para el módulo audio_in)
input_device=None, # o nombra otra
)
engine.start()
print(engine.info)

engine.start(**ajustes) también recibe estos ajustes, así puedes parar y volver a empezar con un buffer más pequeño u otro dispositivo; el patch se queda como está.

engine.info dice qué se abrió y cómo funciona:

Clave Significado
backend "device", "null" (sin tarjeta: un reloj que lleva el tiempo) o "offline"
host, device, input_device la API y los dispositivos en uso
sample_rate, buffer_size, channels el formato del stream (buffer_size es None cuando eligió el sistema)
latency_ms desde que se calcula un buffer hasta que sale por los altavoces, según el sistema
load la parte del tiempo de cada buffer que se gasta en calcularlo: por encima de 1.0 el sonido se corta
underruns buffers que salieron en silencio
error el último problema (un dispositivo desconectado, o por qué no hay sonido)

Un load que se queda por debajo de 0.5 deja margen para un buffer más pequeño.

  • WASAPI es la opción por defecto. En modo compartido Windows mezcla todos los programas y decide el buffer (normalmente 10 ms); el motor pide 256 muestras y acepta lo que dé Windows.
  • ASIO da la latencia más baja con interfaces de audio que traen driver ASIO. Necesita el SDK de ASIO de Steinberg al compilar, así que no está en las wheels de PyPI: compila Pyzed con maturin develop --release --features asio (con CPAL_ASIO_DIR apuntando al SDK) y luego usa audio.Engine(host="ASIO").
  • Para puertos MIDI virtuales, instala loopMIDI.
Backend Para qué
audio.Engine("auto") Por defecto: la tarjeta de sonido, o el reloj null si no hay ninguna (info["error"] dice por qué)
audio.Engine("device") La tarjeta de sonido o un error
audio.Engine("null") Tiempo real sin sonido: servidores, CI, una interfaz que solo muestra las señales
audio.Engine("offline") Sin reloj: engine.render(segundos) calcula lo más rápido posible, para tests y archivos