Creazione dell'effetto Eco

[La funzionalità associata a questa pagina, Lettore multimediale Windows SDK, è una funzionalità legacy. È stato sostituito da MediaPlayer. MediaPlayer è stato ottimizzato per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer invece di Lettore multimediale Windows SDK, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

È innanzitutto necessario rimuovere il codice dall'esempio della procedura guidata che ridimensiona l'audio. Nella sezione a 8 bit rimuovere il codice seguente:

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

Tenere presente che m_fScaleFactor è stato sostituito da m_dwDelayTime.

Nella sezione a 16 bit rimuovere il codice seguente:

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

L'implementazione di DoProcessOutput fornita dal codice di esempio della procedura guidata plug-in crea un ciclo while che esegue un'iterazione una volta per ogni esempio nel buffer di input fornito da Lettore multimediale Windows. Questo ciclo funziona allo stesso modo sia per l'audio a 8 bit che per quello a 16 bit, anche se per ognuno è necessario un ciclo separato. In ogni caso, il ciclo inizia con il test seguente:

while (dwSamplesToProcess--)

Una volta all'interno del ciclo, le routine di elaborazione sono molto simili per l'audio a 8 bit e a 16 bit. La differenza principale è che il codice nella sezione a 8 bit modifica l'intervallo di valori di dati in -128 e 127 e quindi converte nuovamente l'intervallo prima di scrivere i dati nel buffer di output. Ciò è importante per mantenere la simmetria della forma d'onda audio durante l'elaborazione.

A questo punto è possibile iniziare ad aggiungere e sostituire il codice nel ciclo di elaborazione.

Recuperare un esempio dal buffer di input

Durante ogni iterazione del ciclo, un singolo esempio viene recuperato dal buffer di input. Per l'audio a 8 bit, l'esempio viene spostato nel nuovo intervallo e quindi il puntatore al buffer di input viene avanzato al campione successivo. Il codice seguente è tratto dalla procedura guidata del plug-in:

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

Per l'audio a 16 bit, il processo è lo stesso, ad eccezione della normalizzazione:

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

Tenere presente che i puntatori nel codice a 16 bit sono stati convertiti in short di tipo.

Recuperare un esempio dal buffer di ritardo

Recuperare quindi un singolo campione dal buffer di ritardo. Per il codice a 8 bit, i campioni di ritardo vengono archiviati nell'intervallo nativo compreso tra 0 e 255. Il codice seguente, che è necessario aggiungere, recupera un esempio di ritardo a 8 bit:

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

Per l'audio a 16 bit, il processo è simile:

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

Scrivere l'esempio di input nel buffer di ritardo

A questo punto, è necessario archiviare l'esempio di input nel buffer di ritardo nella stessa posizione da cui è stato recuperato l'esempio di ritardo. Di seguito è riportato il codice da aggiungere per l'audio a 8 bit:

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

Questo è il codice da aggiungere per la sezione a 16 bit:

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

Spostare il puntatore del buffer di ritardo

Ora che il lavoro nel buffer di ritardo è terminato per questa iterazione, è possibile spostare il puntatore mobile nel buffer di ritardo. Se il puntatore raggiunge la fine del buffer circolare, è necessario modificarne il valore in modo che punti all'intestazione del buffer. A tale scopo, usare il codice seguente per l'audio a 8 bit:

// 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;

Ecco il codice per la sezione a 16 bit:

// 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;

Poiché il puntatore nella sezione a 16 bit è in realtà una copia della variabile membro, è necessario ricordare di aggiornare il valore nella variabile membro con il nuovo indirizzo. Se non si riesce a eseguire questa operazione, il puntatore del buffer ritardato punterà ripetutamente all'intestazione del buffer e l'effetto eco non funzionerà come previsto. Aggiungere il codice seguente alla sezione a 16 bit:

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

Combinare l'esempio di input con l'esempio di ritardo

In questo caso si usano i valori di combinazione bagnata e combinazione secca per creare l'esempio di output finale. È sufficiente moltiplicare ogni campione per il valore a virgola mobile che rappresenta la percentuale del segnale finale per il campione. Moltiplicare l'esempio di input per il valore archiviato in m_fDryMix; moltiplicare il campione di ritardo per il valore archiviato in m_fWetMix. Aggiungere quindi i due valori. Il codice da aggiungere è identico per le sezioni a 8 bit e a 16 bit:

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

Scrivere i dati nel buffer di output

Copiare infine l'esempio misto nel buffer di output e quindi avanzare il puntatore del buffer di output. Per l'audio a 8 bit, la procedura guidata del plug-in usa il codice seguente per restituire l'esempio all'intervallo originale:

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

Per l'audio a 16 bit, la procedura guidata usa il codice seguente come passaggio finale del ciclo di elaborazione:

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

Implementazione di CEcho::D oProcessOutput