2015-01-20 3 views
1

У меня есть приложение 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? Почему эти позиции чтения не соответствуют моим позициям? Какой здесь правильный алгоритм?

Я пробовал более простую альтернативу остановке захвата, когда буфер захвата заполнен, без других позиций оповещения. Но это означает, я думаю, что позволяет некоторым звукам избежать захвата.

ответ

0

Мои позиции для обозначения кратны 1024. Но сообщения о позиции чтения - 1500, 2500 и 3500. Так что, если я вижу позицию чтения 1500, значит ли это, что я могу читать от байтов от 0 до 1500. И когда следующий я вижу 2500, значит ли это, что я должен читать от 1501 до 2500? Почему эти позиции чтения не соответствуют моим позициям? Какой здесь правильный алгоритм?

API DirectSound теперь является слоем совместимости поверх других «реальных» API захвата аудио. Это означает, что внутри аудиозахвата заполняются некоторые буферы (например, кратные 500), а затем передаются заполненные буферы на захват DirectSound, что, в свою очередь, сообщает их вам.Это объясняет, почему вы видите позиции чтения как кратные 500, потому что у DirectSound есть данные, доступные таким образом.

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

+0

Я перерисовал вычисления буфера захвата, так что теперь, когда я сохраняю данные захвата в файл, звук идеально подходит при игре с Linux aplay - ЕСЛИ я не воспроизвожу данные с буфером воспроизведения в Windows , Так или иначе, действие воспроизведения данных в отдельном буфере влияет на то, что было захвачено. –

+0

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

+0

Я загрузил WAV-файл в буфер и попытался воспроизвести его двумя способами. Во-первых, я попробовал старомодный вызов sndPlaySound, и это звучало нормально. Затем я попытался использовать свой буфер воспроизведения DirectSound. Это звучало неряшливо и искажено, хотя оно было на правильном шаге и скорости. Может быть, потому, что слой эмуляции работает не так хорошо? –

Смежные вопросы