본문 바로가기

Programming/DirectX

[DirectSound] 8. 버퍼의 통지와 스트리밍 재생

반응형

DirectSound의 버퍼는 논리적으로 원형(순환) 버퍼로 되어 있습니다.

한정된 버퍼의 크기를 계속 사용하기 위해서 이런 구조를 사용합니다.

IDirectSoundBuffer8 인터페이스의 Lock() 메소드는 2개의 주소와 크기를 리턴합니다.

HRESULT Lock(
         DWORD dwOffset,
         DWORD dwBytes,
         LPVOID * ppvAudioPtr1,
         LPDWORD  pdwAudioBytes1,
         LPVOID * ppvAudioPtr2,
         LPDWORD pdwAudioBytes2,
         DWORD dwFlags
)

보통 하나의 주소와 크기를 반환하지만 다음과 같은 경우에는 두 개를 리턴합니다.

주소가 0~39999까지인 40000바이트 크기의 버퍼를 생성했다고 가정합니다.

20000 바이트의 위치에서 30000의 크기를 요청하게 되면 전체 크기를 넘어가게 됩니다.

20000~39999까지 20000밖에 되지 않기 때문에 요청한 30000바이트를 제공할 수 없게 됩니다.

이럴 때 20000~39999까지 첫 번째 주소와 크기에 리턴하고 다시 맨 처음으로 돌아옵니다.

그리고 0~9999까지의 메모리 영역을 두 번째 주소와 크기에 리턴합니다.

이렇게 하면 뒷 부분의 2만과 앞 부분에서 다시 1만을 리턴하게 되서 요청한 크기를 정상적으로 제공합니다.

물론 메모리를 요청할 때는 전체 크기보다 커서는 안됩니다.

전체 크기가 40000바이트인데 50000바이트 이런 식으로 요청하는 것은 안됩니다.

이런 식으로 원형을 구성할 필요가 없다면 ppvAudioPtr2와 pdwAudioBytes2는 각각 NULL과 0이 됩니다.

그림으로 표현하면 다음과 같습니다.

20000~39999까지의 2만 바이트가 각각 ppvAudioPtr1, pdwAudioBytes1에 저장됩니다.

0~9999까지의 1만 바이트가 ppvAudioPtr2, pdwAudioBytes2에 저장됩니다.

다음으로 스트리밍 재생은 다음과 같은 절차로 진행됩니다.

1. 버퍼의 통지 지점을 설정

0.5초 분량의 버퍼를 생성하고 0.1초마다 통지를 설정해서 총 5개의 통지 구간을 설정한다.

2. 버퍼의 통지가 감지되면 재생이 완료된 부분에 Lock()

3. Lock()이 성공하면 새로운 소리 데이터를 채움

위와 같은 순서로 하면 간단하게 스트리밍 재생이 가능합니다.

먼저 0.5초 분량의 버퍼를 생성해서 0.5초의 소리 데이터를 채워놓습니다.

그리고 각각 0.1초가 재생되면 통지가 되도록 통지 구간을 설정합니다.

이제 재생이 진행되면 읽기 커서는 순서대로 읽으면서 소리를 재생합니다.

0.1초 분량의 재생이 끝나면 통지가 오게 되고 쓰기 커서의 위치를 0~0.1초 구간으로 이동시킵니다.

여기에 0.6초의 데이터를 입력합니다.

같은 방법으로 다시 0.1초(총 0.2초)가 재생되면 0.1~0.2초 구간에 0.7초의 데이터를 입력합니다.

버퍼의 재생이 무한히 순환하기 때문에 계속 새로운 값이 채워지면서 스트리밍의 재생이 가능하게 됩니다.

무한히 순환하게 하기 위해서 Play() 메소드를 호출할 때 플래그를 DSBPLAY_LOOPING을 전달하면 됩니다.

Stop()을 호출하기 전까지 데이터를 입력하면 계속 반복해서 재생하게 됩니다.

반응형