Создание эхо-эффекта

[Функция, связанная с этой страницей, Медиаплеер Windows sdk, является устаревшей функцией. Он был заменен MediaPlayer. MediaPlayer оптимизирован для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует по возможности использовать MediaPlayer вместо пакета SDK для Медиаплеер Windows. Корпорация Майкрософт предлагает переписать существующий код, использующий устаревшие API, чтобы по возможности использовать новые API.]

Сначала необходимо удалить код из примера мастера, который масштабирует звук. Из 8-разрядного раздела удалите следующий код:

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

(Помните, что m_fScaleFactor был заменен m_dwDelayTime.)

Из 16-разрядного раздела удалите следующий код:

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

Реализация DoProcessOutput, предоставляемая примером кода мастера подключаемых модулей, создает цикл while, который выполняет итерацию по одному разу для каждого примера во входном буфере, предоставленном Медиаплеер Windows. Этот цикл работает одинаково для 8- и 16-разрядного звука, хотя для каждого из них требуется отдельный цикл. В каждом случае цикл инициируется с помощью следующего теста:

while (dwSamplesToProcess--)

После этого процедуры обработки очень похожи для 8- и 16-разрядного звука. Main разница заключается в том, что код в 8-разрядном разделе изменяет диапазон значений данных с -128 по 127, а затем преобразует диапазон обратно, прежде чем записывать данные в выходной буфер. Это важно для сохранения симметрии звуковой формы во время обработки.

Теперь можно приступить к добавлению и замене кода в цикле обработки.

Получение примера из буфера ввода

Во время каждой итерации цикла из входного буфера извлекается один образец. Для 8-разрядного звука образец перемещается в новый диапазон, а затем указатель на входной буфер перемещается к следующему образцу. Следующий код получен из мастера подключаемых модулей:

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

Для 16-разрядного звука процесс одинаков, за исключением нормализации:

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

Помните, что указатели в 16-разрядном коде были преобразованы в тип short.

Получение примера из буфера задержки

Затем извлеките один образец из буфера задержки. Для 8-разрядного кода примеры задержки хранятся в собственном диапазоне от 0 до 255. Следующий код, который необходимо добавить, извлекает пример 8-разрядной задержки:

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

Для 16-разрядного звука процесс аналогичен:

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

Запись входного примера в буфер задержки

Теперь необходимо сохранить входной образец в буфере задержки в том же расположении, из которого был получен пример задержки. Ниже приведен код, который необходимо добавить для 8-разрядного звука:

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

Это код, который нужно добавить для 16-разрядного раздела:

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

Перемещение указателя буфера задержки

Теперь, когда работа в буфере задержки завершена для этой итерации, можно переместить перемещаемый указатель на буфер задержки. Если указатель достигает конца кругового буфера, необходимо изменить его значение так, чтобы оно указывало на голову буфера. Чтобы сделать это для 8-разрядного звука, используйте следующий код:

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

Ниже приведен код для 16-разрядного раздела:

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

Так как указатель в 16-разрядном разделе действительно является копией переменной-члена, необходимо не забудьте обновить значение в переменной-члене новым адресом. Если это не удается сделать, указатель буфера задержки будет указывать на голову буфера несколько раз, и ваш эхо-эффект будет работать не так, как ожидалось. Добавьте следующий код в 16-разрядный раздел:

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

Сочетание входного примера с примером задержки

Здесь используются значения влажной и сухой смеси для создания окончательного выходного образца. Вы просто умножаете каждую выборку на значение с плавающей запятой, представляющее процент конечного сигнала для выборки. Умножьте входную выборку на значение, хранящееся в m_fDryMix; Умножьте выборку задержки на значение, хранящееся в m_fWetMix. Затем добавьте два значения. Код, который необходимо добавить, идентичен для 8-разрядных и 16-разрядных разделов:

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

Запись данных в выходной буфер

Наконец, скопируйте смешанный пример в выходной буфер, а затем переведите указатель выходного буфера. Для 8-разрядного звука подключаемый мастер использует следующий код, чтобы вернуть пример в исходный диапазон:

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

Для 16-разрядного звука мастер использует следующий код в качестве последнего шага в цикле обработки:

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

Реализация CEcho::D oProcessOutput