Creación del efecto 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.

Primero debe quitar el código del ejemplo del asistente que escala el audio. En la sección de 8 bits, quite el código siguiente:

// Apply scale factor to sample.
i = int( ((double) i) * m_dwDelayTime );

(Recuerde que m_fScaleFactor se ha reemplazado por m_dwDelayTime).

En la sección de 16 bits, quite el código siguiente:

// Apply scale factor to sample.
i = int( ((double) i) * m_dwDelayTime );

La implementación de DoProcessOutput proporcionada por el código de ejemplo del asistente para complementos crea un bucle while que itera una vez para cada ejemplo del búfer de entrada proporcionado por Reproductor multimedia de Windows. Este bucle funciona de la misma manera para audio de 8 y 16 bits, aunque se requiere un bucle independiente para cada uno. En cada caso, el bucle se inicia con la prueba siguiente:

while (dwSamplesToProcess--)

Una vez dentro del bucle, las rutinas de procesamiento son muy similares para audio de 8 y 16 bits. La principal diferencia es que el código de la sección de 8 bits cambia el intervalo de valores de datos a -128 a 127 y, a continuación, vuelve a convertir el intervalo antes de escribir los datos en el búfer de salida. Esto es importante para conservar la simetría de la forma de onda de audio durante el procesamiento.

Ahora puede empezar a agregar y reemplazar código en el bucle de procesamiento.

Recuperar un ejemplo del búfer de entrada

Durante cada iteración del bucle, se recupera una única muestra del búfer de entrada. En el caso del audio de 8 bits, la muestra se desplaza al nuevo intervalo y, a continuación, el puntero al búfer de entrada está avanzado al ejemplo siguiente. El código siguiente procede del asistente para complementos:

// Get the input sample and normalize to -128 .. 127
int i = (*pbInputData++) - 128;

Para audio de 16 bits, el proceso es el mismo, excepto para la normalización:

// Get the input sample.
int i = *pwInputData++;

Recuerde que los punteros del código de 16 bits se han convertido al tipo short.

Recuperar un ejemplo del búfer de retraso

A continuación, recupere una única muestra del búfer de retraso. En el caso del código de 8 bits, las muestras de retraso se almacenan en su intervalo nativo de 0 a 255. El código siguiente, que debe agregar, recupera un ejemplo de retraso de 8 bits:

// Get the delay sample and normalize to -128 .. 127
int delay = m_pbDelayPointer[0] - 128;

Para audio de 16 bits, el proceso es similar:

// Get the delay sample.
int delay = *pwDelayPointer;

Escribir el ejemplo de entrada en el búfer de retraso

Ahora, debe almacenar el ejemplo de entrada en el búfer de retraso en la misma ubicación desde la que recuperó la muestra de retraso. A continuación se muestra el código que debe agregar para audio de 8 bits:

// Write the input sample into the delay buffer.
m_pbDelayPointer[0] = i + 128;

Este es el código que se va a agregar para la sección de 16 bits:

// Write the input sample to the delay buffer.
*pwDelayPointer = i;

Mover el puntero de búfer de retraso

Ahora que el trabajo del búfer de retraso ha finalizado para esta iteración, puede avanzar el puntero móvil al búfer de retraso. Si el puntero alcanza el final del búfer circular, debe cambiar su valor para que apunte al encabezado del búfer. Para ello, use el código siguiente para el audio de 8 bits:

// Increment the delay pointer.
// If it has passed the end of the buffer,
// then move it to the head of the buffer.
if (++m_pbDelayPointer > pbEOFDelayBuffer)
    m_pbDelayPointer = m_pbDelayBuffer;

Este es el código de la sección de 16 bits:

// Increment the local delay pointer.
// If it is past the end of the buffer,
// then move it to the head of the buffer.
if (++pwDelayPointer > pwEOFDelayBuffer)
    pwDelayPointer = pwDelayBuffer;

Puesto que el puntero de la sección de 16 bits es realmente una copia de la variable miembro, debe recordar actualizar el valor de la variable miembro con la nueva dirección. Si no lo hace, el puntero de búfer de retraso apuntará al encabezado del búfer repetidamente y el efecto de eco no funcionará según lo previsto. Agregue el código siguiente a la sección de 16 bits:

// Move the global delay pointer.
m_pbDelayPointer = (BYTE *) pwDelayPointer;

Mezclar el ejemplo de entrada con el ejemplo de retraso

Aquí es donde se usan los valores de mezcla húmeda y mezcla seca para crear la muestra de salida final. Simplemente multiplica cada muestra por el valor de punto flotante que representa el porcentaje de la señal final de la muestra. Multiplique la muestra de entrada por el valor almacenado en m_fDryMix; multiplique la muestra de retraso por el valor almacenado en m_fWetMix. A continuación, agregue los dos valores. El código que debe agregar es idéntico para las secciones de 8 y 16 bits:

// Mix the delay with the dry signal.
i = (int)((i * m_fDryMix ) + (delay * m_fWetMix));   

Escribir los datos en el búfer de salida

Por último, copie el ejemplo mixto en el búfer de salida y, a continuación, avance el puntero del búfer de salida. En el caso del audio de 8 bits, el asistente para complementos usa el código siguiente para devolver el ejemplo a su rango original:

// Convert back to 0..255 and write to output buffer.
*pbOutputData++ = (BYTE)(i + 128);

En el caso del audio de 16 bits, el asistente usa el código siguiente como último paso del bucle de procesamiento:

// Write to output buffer.
*pwOutputData++ = i;

Implementación de CEcho::D oProcessOutput