У меня есть приложение DirectSound, которое я пишу на C, работающее в Windows 7. Приложение просто захватывает некоторые звуковые фреймы и воспроизводит их. Для проверки работоспособности результатов захвата я пишу данные PCM в файл, который я могу играть в Linux с помощью aplay.Как избежать искажения и заикания в DirectSound?
К сожалению, звук нестабилен, иногда он содержит заикание (и играет с неправильной скоростью в Linux). Как ни странно, количество искажений, наблюдаемое при воспроизведении файла захвата, меньше, если данные PCM не воспроизводятся в буфере воспроизведения во время захвата.
Вот инициализации моего WAVEFORMATEX:
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.cbSize = 0;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1;
wfx.nSamplesPerSec = sampleRate;
wfx.wBitsPerSample = sampleBitWidth;
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample)/8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign code here
SAMPLERATE составляет 8000, а sampleBitWidth 16.
создать захват и воспроизведение буфера, используя ту же самую структуру, и буфер захвата имеет 3 уведомлений. Я начала съемки с:
lpDsCaptureBuffer->Start(DSCBSTART_LOOPING);
потом зажигать поток воспроизведения, который вызывает WaitForMultipleObjects о событиях, связанных с точками уведомления. После получения уведомления, сбросить все события, и скопировать 1 или 2 части буфера захвата в локальный буфер, и передавать их на рутину игры:
void playFromBuff(LPVOID captureBuff,DWORD captureLen) {
LPVOID playBuff;
DWORD playLen;
HRESULT hr;
hr = lpDsPlaybackBuffer->Lock(0L,captureLen,&playBuff,&playLen,NULL,0L,0L);
memcpy(playBuff,captureBuff,playLen);
hr = lpDsPlaybackBuffer->Unlock(playBuff,playLen,NULL,0L);
hr = lpDsPlaybackBuffer->SetCurrentPosition(0L);
hr = lpDsPlaybackBuffer->Play(0L,0L,0L);
}
(некоторые проверки ошибок опущено).
Обратите внимание, что буфер воспроизведения не имеет позиций для оповещения. Каждый раз, когда я получаю кусок из буфера захвата, я заблокировать буфер воспроизведения, начиная с позиции 0.
Кодекса захвата, охраняются WaitForMultipleObjects, выглядит следующим образом:
lpDsCaptureBuffer->GetCurrentPosition(NULL,&readPos);
hr = lpDsCaptureBuffer->Lock(...,...,&captureBuff1,&captureLen1,&captureBuff2,&captureLen2,0L);
где эллипсы содержат расчеты с текущие и ранее просматриваемые позиции чтения. Я опускаю эти ошибочные расчеты - я подозреваю, что в этом проблема.
Мои позиции для уведомлений кратны 1024. Однако сообщения о позиции чтения - 1500, 2500 и 3500. Так что, если я вижу позицию чтения 1500, значит ли это, что я могу читать от байтов от 0 до 1500. И когда следующий Я вижу 2500, значит ли это, что я должен читать от 1501 до 2500? Почему эти позиции чтения не соответствуют моим позициям? Какой здесь правильный алгоритм?
Я пробовал более простую альтернативу остановке захвата, когда буфер захвата заполнен, без других позиций оповещения. Но это означает, я думаю, что позволяет некоторым звукам избежать захвата.
Я перерисовал вычисления буфера захвата, так что теперь, когда я сохраняю данные захвата в файл, звук идеально подходит при игре с Linux aplay - ЕСЛИ я не воспроизвожу данные с буфером воспроизведения в Windows , Так или иначе, действие воспроизведения данных в отдельном буфере влияет на то, что было захвачено. –
Некоторые подсказки: вы можете найти что-то с отладчиком и отслеживать порядок вызовов и действий. Возможно, ваша синхронизация потоков заставляет вас как-то терять определенные циклы. Для целей отладки вы хотели бы начать с супер длинного буфера захвата, чтобы убедиться, что у вас нет переполнений, потоков и т. Д. Когда все настроено в этом простом сценарии, вы можете изменить его близко к тому, что вам в конечном итоге нужно. –
Я загрузил WAV-файл в буфер и попытался воспроизвести его двумя способами. Во-первых, я попробовал старомодный вызов sndPlaySound, и это звучало нормально. Затем я попытался использовать свой буфер воспроизведения DirectSound. Это звучало неряшливо и искажено, хотя оно было на правильном шаге и скорости. Может быть, потому, что слой эмуляции работает не так хорошо? –