2015-01-20 1 views
1

Windows 7에서 실행되는 C로 작성한 DirectSound 응용 프로그램이 있습니다. 응용 프로그램은 일부 사운드 프레임을 캡처하고 다시 재생합니다. 캡처 결과를 온전하게 확인하기 위해 PCM 데이터를 파일로 쓰고 있는데, 나는 파일을 사용하여 리눅스에서 재생할 수있다.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가 통지 위치. 그때 알림 점과 관련된 이벤트에와 WaitForMultipleObjects를 호출하는 재생 스레드를 촉발

lpDsCaptureBuffer->Start(DSCBSTART_LOOPING); 

: 나는 함께 캡처를 시작. 통지되면, 나는 모든 이벤트를 재설정하고 로컬 버퍼에 캡처 버퍼의 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까지 읽어야한다는 뜻입니까? 왜 그 위치들은 내 통보 위치와 정확히 일치하지 않습니까? 올바른 알고리즘은 무엇입니까?

DirectSound API는 현재 다른 "실제"오디오 캡처 API 위에있는 호환성 레이어입니다. 즉, 내부 오디오 캡처는 일부 버퍼 (특히 그 배수가 500)를 채운 다음 채워진 버퍼를 DirectSound 캡처에 전달하여 DirectSound 캡처에 전달합니다.따라서 DirectSound 자체에서이 방법으로 데이터를 사용할 수 있기 때문에 읽기 위치가 500의 배수로 표시되는 이유를 알 수 있습니다.

캡쳐 된 데이터를 가져 오는 데 관심이 있으니 주로 읽기 위치에 관심이 있다고 가정하십시오. 알림을 받으면 읽을 수있는 오프셋이 무엇인지 알 수 있습니다. 캡처 API가 계층화되어 있기 때문에 레이어를 사용할 수있게 만들기 전에 레이어간에 데이터를 전달해야하기 때문에 약간의 대기 시간이 필요합니다.

+0

캡처 데이터를 파일에 저장할 때 Linux에서 재생할 때 소리가 완벽합니다. Windows에서 재생 버퍼로 데이터를 재생하지 않는 경우에도 그렇습니다. . 어떻게 든, 별도의 버퍼에서 데이터를 재생하는 동작은 캡처 한 내용에 영향을 미칩니다. –

+0

몇 가지 힌트 : 디버거로 무엇인가를 찾고 호출 및 동작의 순서를 추적 할 수 있어야합니다. 아마도 스레드 동기화가 어떻게 든 특정 루프를 잃을 수 있습니다. 디버깅을 위해 슈퍼 오버 캡쳐 버퍼로 시작하여 오버 플로우, 언더 플로 등이 없도록해야합니다. 이 간단한 시나리오에서 일이 조정되면 최종 결과에 가깝게 변경할 수 있습니다. –

+0

WAV 파일을 버퍼에로드하고 두 가지 방법으로 재생 해 보았습니다. 첫째, 구식 호출 sndPlaySound를 시도해 보았습니다. 다음으로 DirectSound 재생 버퍼를 사용해 보았습니다. 올바른 음조와 속도로 연주되었지만 고르지 않고 왜곡되었습니다. 에뮬레이션 레이어가 그렇게 잘 작동하지 않기 때문일 수 있습니까? –

관련 문제