Compartir a través de


eventos de Time-Stamped

La imagen general del tiempo del sintetizador es que, en lugar de enviar una nota exactamente cuando necesita reproducirse, cada nota se marca y se coloca en un búfer. A continuación, este búfer se procesa y se reproduce en dos milisegundos del tiempo especificado por la marca de tiempo. (Aunque la resolución de tiempo está en cientos de nanosegundos, hablaremos en términos de milisegundos, que son unidades de tiempo más convenientes para esta discusión).

Dado que la latencia se conoce para el sistema a través del reloj de latencia, los eventos con marca de tiempo pueden estar esperando en un búfer para reproducirse en su momento adecuado, en lugar de simplemente colocar eventos en una cola y esperar que la latencia sea baja.

Un reloj maestro implementa una interfaz IReferenceClock COM (descrita en la documentación de Microsoft Windows SDK). Todos los dispositivos del sistema usan esta hora de referencia.

La implementación del receptor de ondas de Microsoft crea un subproceso que se activa cada 20 milisegundos. El trabajo del subproceso es crear otro búfer y entregarlo a DirectSound. Para crear ese búfer, llama al sintetizador y le pide que represente una cantidad especificada de datos de música. La cantidad que solicita viene determinada por el tiempo real en que se reactiva el subproceso, que es poco probable que sea exactamente de 20 milisegundos.

Lo que realmente se pasa al sintetizador es simplemente un puntero a la ubicación en memoria en la que empezar a escribir datos en el búfer PCM y un parámetro de longitud que especifica la cantidad de datos que se van a escribir. Después, el sintetizador puede escribir datos de PCM en este búfer y rellenarlos hasta la cantidad especificada. Es decir, se representa desde la dirección inicial hasta que alcanza la longitud especificada. Ese bloque de memoria puede ser directSoundBuffer (que es el caso predeterminado), pero también podría ser un gráfico directShow o algún otro destino definido por el receptor de onda.

El búfer de PCM es conceptualmente cíclico (es decir, se repite constantemente). El sintetizador representa los números de 16 bits que describen el sonido en segmentos sucesivos del búfer. El tamaño del segmento es ligeramente diferente cada vez que se despierta el subproceso, porque el receptor no puede despertarse exactamente cada 20 milisegundos. Por lo tanto, cada vez que el subproceso se activa, se reproduce al día para determinar cuánto debe avanzar a través del búfer antes de volver a dormir.

Desde la perspectiva de la aplicación, el propio controlador de puerto de synth tiene una función IDirectMusicSynth::GetLatencyClock que obtiene el reloj del receptor de onda. Así que hay dos relojes:

  • El reloj maestro al que todo el mundo, incluido el receptor de onda, escucha.

  • El reloj de latencia implementado por el receptor de onda, que la aplicación ve como un puerto de DirectMusic que proporciona el reloj de latencia.

En otras palabras, la aplicación solicita el reloj de latencia, pero ve el reloj como procedente de la abstracción del puerto de DirectMusic en lugar del receptor de onda.

La hora devuelta por este reloj de latencia es la más temprana en la que se puede representar el búfer, ya que el sintetizador ya se ha representado hasta ese momento en el búfer. Si el sintetizador había representado un búfer más pequeño en su última escritura, la latencia también sería más pequeña.

Por lo tanto, el receptor de ondas llama a IDirectMusicSynth::Render en el sintetizador, presentando el búfer y solicitando que se rellene con datos representados. Como se muestra en la ilustración siguiente, el sintetizador toma todos los eventos con marca de tiempo que entran como resultado de las llamadas de función IDirectMusicSynth::P layBuffer .

Diagrama que ilustra el proceso de puesta en cola de mensajes con marca de tiempo en un sintetizador.

Cada búfer de entrada contiene mensajes con marca de tiempo. Cada uno de estos mensajes se coloca en una cola que se va a representar en un búfer en el momento especificado por su marca de tiempo.

Una de las cosas importantes de este modelo es que no hay ningún orden concreto que no sea la marca de tiempo. Estos eventos se transmiten en, por lo que se pueden agregar a la cola en cualquier momento antes de la representación. Todo se basa en eventos con respecto al tiempo. Por ejemplo, si el tiempo de referencia está actualmente en 400 unidades de tiempo, todo lo que se marca el tiempo para que suceda en el momento 400 está ocurriendo ahora. Los eventos con marca de tiempo para que se produzcan 10 unidades a partir de ahora se producirán en el momento 410.