Cómo funciona el ejemplo de eco

[La característica asociada a esta página, Reproductor multimedia de Windows SDK, es una característica heredada. Se ha reemplazado por MediaPlayer. MediaPlayer se ha optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer en lugar de Reproductor multimedia de Windows SDK, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

El código crea el efecto de eco asignando un búfer lo suficientemente grande como para contener exactamente la cantidad de datos de audio que se pueden representar en el período de tiempo especificado por el valor de tiempo de retraso. El tamaño del búfer se calcula, en bytes, mediante la fórmula siguiente:

tamaño del búfer = tiempo de retraso * frecuencia de muestreo / 1000 * alineación de bloques

El tiempo de retraso está en milisegundos. Los valores de frecuencia de muestreo y alineación de bloques se proporcionan en una estructura WAVEFORMATEX. La frecuencia de muestreo está en muestras por segundo; dividir por 1000 produce muestras por milisegundos. La alineación del bloque es igual al producto del número de canales (1 para mono, 2 para estéreo) y el número de bits por muestra (8 o 16) divididos por 8 (bits por byte).

Además de la variable de puntero que apunta al encabezado del búfer de retraso, el código crea un puntero móvil que recorre los datos del búfer en sincronización con el bucle de procesamiento en la función DoProcessOutput . Cuando el puntero móvil llega al final del búfer de retraso, vuelve al encabezado del búfer. Un búfer usado de esta manera se denomina búfer circular.

Una vez que existe el búfer de retraso y Reproductor multimedia de Windows ha asignado un búfer de entrada para proporcionar datos de audio y un búfer de salida para recibir datos de audio procesados, el procesamiento de eco continúa de esta manera:

  1. Escriba un bucle que permita el procesamiento de cada muestra de audio en el búfer de entrada.
  2. Recupere un ejemplo del búfer de entrada. A continuación, mueva el puntero del búfer de entrada al siguiente ejemplo para prepararse para la iteración del bucle siguiente.
  3. Recupere un ejemplo del búfer de retraso.
  4. Copie el ejemplo del búfer de entrada en la misma ubicación del búfer de retraso desde el que se recuperó la última muestra de retraso.
  5. Mueva el puntero de búfer de retraso hacia delante al ejemplo siguiente. Si el puntero se mueve más allá del final del búfer, muévalo al encabezado del búfer.
  6. Combine el ejemplo del búfer de entrada con el ejemplo del búfer de retraso.
  7. Copie el resultado en el búfer de salida. A continuación, mueva el puntero del búfer de salida hacia delante a la unidad siguiente para prepararse para la siguiente iteración del bucle.
  8. Repita hasta que se procesen todas las muestras.

Cuando una muestra de entrada recuperada en el paso 2 se copia en el búfer de retraso en el paso 4, permanece allí hasta que el puntero móvil recorre cada muestra en el búfer de retraso y, por último, vuelve a la misma posición. Dado que el tamaño del búfer de retraso está diseñado para corresponder al tiempo de retraso, el tiempo transcurrido entre la muestra que se copia en el búfer de retraso y la muestra que se recupera una vez más es igual al retraso especificado (además de cualquier latencia introducida por el procesamiento real).

Cuando se inicia una secuencia, no se generan datos de retraso hasta que haya transcurrido el tiempo de retraso. Por lo tanto, es importante que el búfer de retraso contenga inicialmente silencio. Si el búfer de retraso contiene datos aleatorios, el usuario escuchará ruido blanco hasta que el complemento genere suficientes datos de retraso para sobrescribir todo el búfer de retraso.

Información general sobre el ejemplo de eco