DirectSound 프로그래밍 DirectSound를 사용하면 매우 짧은 지연 시간에 사운드를 재생해, 애플리케이션으로 하드웨어 리소스를 치밀하게 제어할 수 있다. DirectSound 인터페이스를 사용하여 다음과 같은 처리가 가능하게 된다. WAV 포맷의 파일 또는 리소스로부터 사운드를 재생한다. 복수의 사운드를 동시에 재생한다. 커스터마이즈 가능한 3D환경에 사운드를 배치한다. 메아리나 코러스 등의 이펙트를 추가해, 이펙트의 파라미터를 동적으로 변경한다. 마이크 또는 그 외의 입력으로부터 WAV 사운드를 캡춰한다.
DirectSound 프로그래밍의 순서 장치 개체를 생성 한다. 2차 버퍼를 생성 한다. PCM 데이터를 얻어온다. DirectSoundCreate8 를 호출해, IDirectSound8 인터페이스를 지원 하는 개체를 생성 한다. 이 개체는 보통 디폴트 재생 장치를 나타낸다. 2차 버퍼를 생성 한다. IDirectSound8::CreateSoundBuffer를 사용해 사운드 데이터를 보관 유지하는 버퍼 개체를 생성 한다. 이러한 버퍼는, 모든 사운드를 믹싱 하는 개체인 1차 버퍼와 구별하기 위해, 2차 버퍼라고 부른다. PCM 데이터를 얻어온다. WAV파일 또는 리소스로부터 1차 버퍼에 데이터를 읽어낸다. 데이터를 버퍼에 저장 한다. DirectSoundBuffer::Lock를 호출해, 쓰기 조작용으로 2차 버퍼를 준비한다. 1차 버퍼로부터 그 주소에 데이터를 복사 한 후, IDirectSoundBuffer8::Unlock를 호출한다. 버퍼를 재생한다. IDirectSoundBuffer8::Play를 호출해 사운드를 재생한다. 버퍼에 대해서는, 마지막에 달한 시점에서 정지하는지, 또는 IDirectSoundBuffer8::Stop를 호출할 때까지 반복 재생을 계속하는지를 지시할 수 있다. 같은 데이터를 보관 유지하는 버퍼를 별도 생성하지 않는 한, 한번에 연주할 수 있는 사운드의 인스턴스는 1개 뿐이다. 임의의 수의 버퍼를 한 번에 재생할 수 있는 믹싱은 자동적으로 행해진다.
DirectSound 장치 개체의 생성 DirectSound를 사용하기 위해 장치 개체를 초기화를 한다. DirectSoundCreate 함수 원형 HRESULT WINAPI DirectSoundCreate8( LPCGUID lpcGuidDevice, LPDIRECTSOUND8 * ppDS8, LPUNKNOWN pUnkOuter ); DirectSoundCreate 함수 샘플 코드 LPDIRECTSOUND8 lpds; HRESULT hr = DirectSoundCreate8(NULL, &lpds, NULL));
협조 레벨 설정 DirectSound 에서는 3 종류의 협조 레벨이, 사운드 장치에 대해서 정의되고 있다. DSSCL_NORMAL 표준 협조 레벨 애플리케이션간 장치의 변환이 가장 원활히 행해진다. DSSCL_PRIORITY 우선 협조 레벨 거의 모든 게임 애플리케이션에서 사용하며 샘플링 레이트와 비트 깊이에 대한 애플리케이션 제어를 가능하게 하면서, 가장 강력하게 동작한다. DSSCL_WRITEPRIMARY 쓰기 우선 협조 레벨 1차 버퍼내의 오디오 샘플에 직접 쓰기 액세스를 실시하려면 , 애플리케이션을 쓰기 우선 레벨로 설정해야 한다. 애플리케이션이 이 레벨로 설정되지 않은 경우, 1차 버퍼에 대한 IDirectSoundBuffer::Lock 메서드의 호출은 모두 실패한다.
협조 레벨 설정 장치개체를 생성한 후 IDirectSound8::SetCooperativeLevel 메 서드를 사용해 장치 협조 레벨을 설정해야 한다. 협조레벨을 설정하지 않을 경우 소리가 나지 않는다. 다음의 예는 lpds에 의 DirectSound인터페이스에 의해 나타내지는 DirectSound의 장치 협조 레벨을 설정하고 있다. hwnd 파라미터는, 애플리케이션 윈도우의 핸들이다. HRESULT hr = lpDirectSound->SetCooperativeLevel( hwnd, DSSCL_PRIORITY); if (FAILED(hr)) { ErrorHandler(hr); // 에러 처리를 여기에 추가한다. }
버퍼의 설정 DSBUFFERDESC 구조체는, 새로운 버퍼 개체의 특성을 기술한다. IDirectSound8::CreateSoundBuffer 메서드 및 DirectSoundFullDuplexCreate8 함수로 사용된다. typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; GUID guid3DAlgorithm; } DSBUFFERDESC, *LPDSBUFFERDESC; typedef const DSBUFFERDESC *LPCDSBUFFERDESC;
버퍼의 설정 DSBUFFERDESC 구조체 멤버 dwSize dwFlags dwBufferBytes dwReserved 구조체의 사이즈. 사용하기 전에, 이 멤버를 초기화해야 한다. dwFlags 버퍼의 능력을 나타내는 플래그 dwBufferBytes 새로운 버퍼의 사이즈 (바이트 단위) 1차 버퍼를 생성할 때는 0을 설정. dwReserved 예약이 끝난 상태. 0 이 아니면 안된다. lpwfxFormat 버퍼의 웨이브 폼 포맷을 지정하는 WAVEFORMATEX구조체 또는 WAVEFORMATEXTENSIBLE 구조체의 주소 1차 버퍼에서는, 이 값은 NULL 이어야 한다. 애플리케이션은 IDirectSoundBuffer::SetFormat 를 사용해, 1차 버퍼의 포맷을 설정할 수 있다. guid3DAlgorithm DirectSound3D 의 하드웨어 에뮬레이션이 사용하는 2 스피커 가상화 알고리즘의 일의인 식별자
버퍼의 설정 버퍼 설정 및 생성 예제 코드 LPDIRECTSOUNDBUFFER pDSBPrimary = NULL; DSBUFFERDESC dsbd; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); // 구조체 멤버 설정 dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = NULL; HRESULT hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL );
버퍼의 설정 웨이브 폼 오디오 데이터의 포맷을 정의하는 코드. WAVEFORMATEX wfx; ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); wfx.wFormatTag = (WORD)WAVE_FORMAT_PCM; wfx.nChannels = (WORD)2; wfx.nSamplesPerSec = (DWORD)22050; wfx.wBitsPerSample = (WORD)16; wfx.nBlockAlign = (WORD)(wfx.wBitsPerSample / 8 * wfx.nChannels); wfx.nAvgBytesPerSec = (DWORD)(wfx.nSamplesPerSec * wfx.nBlockAlign); HRESULT hr = pDSBPrimary->SetFormat(&wfx)
DirectSound의 예제 DirectSound 샘플의 중심적인 기능을 하는 Dsutil.h에 선언되고 Dsutil.cpp에서 구현된 클래스들을 가지고 간단한 예제를 구현한다. DirectSound샘플에서 사용되는 클래스는 다음과 같다. Csound 클래스 : 스태틱 버퍼 를 나타낸다. CSoundManager 클래스 : DirectSound 의 생성과 초기화, 1차 버퍼에의 액세스, 2차 버퍼의 생성을 위한 기능을 포함한다. CStreamingSound 클래스 : 스트리밍 버퍼 내의 사운드를 나타낸다. CWaveFile 클래스 : WAV 파일의 read와 쓰기, 메모리에 저장 되고 있는 WAV 리소스 또는 웨이브 폼으로부터의 read에 사용된다.
DirectSound의 예제 CSoundManager 클래스를 이용한 초기화, 협조레벨 설정 1차 버퍼의 포맷 형태를 설정 CSoundManager m_pCSM; m_pCSM.Initialize(hWnd, (DWORD)DSSCL_PRIORITY); hWnd는 윈도우 핸들이며 우선협조레벨로 설정하고 있다. 1차 버퍼의 포맷 형태를 설정 m_pCSM.SetPrimaryBufferFormat((DWORD)2, (DWORD)22050, (DWORD)16); 위의 코드에서 1차 버퍼를 2채널(스테레오), 22050kHz의 샘플링, 한 샘플을 16bit으로 표현하는 형태로 정의하고있다
DirectSound의 예제 CSoundManager 클래스를 이용한 생성 CSound *m_pCSBGSound; m_pCSM.Create(&m_pCSBGSound, strWaveFileName, 0, GUID_NULL, 5); CSoundManager::Create() 함수를 호출하여 생성을 한다. 인자로는 Csound의 객체포인터가 필요하며, WAVE 화일명,그리고 0과 GUID_NULL은 DSBUFFERDESC의 구조체를 채우는데 사용되며, 마지막 인자인 5는 만들어지는 버퍼 배열의 갯수이다.
DirectSound의 예제 CSound::Play()를 이용하여 재생을 한다. CSound::Play(DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan) 첫번째는 사운드의 우선도를 나타내고, 두번째 플래그에서는 사운드를 반복 할 수 있는 DSBPLAY_LOOPING플래그를 사용 할 수 있다. 나머지 3개의 플래그는 볼륨 설정, 샘플링 오디오의 재생 주파수 설정, 좌우축의 음원 위치를 설정할 수 있는 플래그이다.
DirectSound의 예제 CSound::Stop()를 이용한 재생 중지 m_pCSBGSound->Stop(); 재생을 할 때 DSBPLAY_LOOPING 플래그를 설정하고 재생하면 멈추지 않고 계속 재생을 하게 된다. 이 때 CSound::Stop()함수를 호출 하면 재생을 중지 시킬수 있다.
DirectSound의 예제 예제에서는 사용을 편리 하게 하기 위해 MyDirectSound라는 클래스를 만들었다. #ifndef MYDIRECTSOUND_H #define MYDIRECTSOUND_H #define LOOP (DWORD)DSBPLAY_LOOPING //반복 재생을 위한 정의 typedef struct { //재생 정보를 구조체로 정의 DWORD dwPriority; DWORD dwFlags; LONG lVolume; LONG lFrequency; LONG lPan; }PLAYINFO;
DirectSound의 예제 HRESULT CreateBGSound(LPTSTR strWaveFileName); class MyDirectSound{ private: CSoundManager m_pCSM; CSound *m_pCSBGSound; CSound *m_pCSFGSound; HRESULT hr; PLAYINFO pi; public: MyDirectSound(); ~MyDirectSound(); HRESULT Initialize(HWND hWnd); HRESULT CreateBGSound(LPTSTR strWaveFileName); HRESULT CreateFGSound(LPTSTR strWaveFileName); HRESULT PlayBGSound(); HRESULT PlayFGSound(DWORD dwFlag = 0); HRESULT StopBGSound(); HRESULT StopFGSound(); };
DirectSound의 예제 코딩순서 기존에 생성 되어 있는 프로젝트에 Source Files에 DSUtil.cpp와 MyDirectSound.cpp를 Header Files에 DSUtil.h 와 MyDirectSound.h 파일을 추가한다. WinMain 함수가 있는 cpp 파일에서 DSUtil.h와 MyDirectSound.h 파일을 인클루드 시킨다.
DirectSound의 예제 코딩순서 인클루드 시킨다음 전역변수로 MyDirectSound객체를 선언하고 ex) MyDirectSound mydsapp; 메시지프로시저함수 안에 case WM_CREATE: mydsapp.Initialize(hWnd); mydsapp.CreateBGSound("11.wav"); mydsapp.CreateFGSound("bounce.wav"); mydsapp.PlayBGSound(); return(0); 와 같이 코딩을 하면 실행시에 11.wav를 배경음악으로 bounce.wav를 효과음악으로 로드하며 프로그램실행과 동시에 배경음악을 플레이 하도록 되어있다.
DirectSound의 예제 코딩순서 위의 코드에서 mydsapp.CreateBGSound("11.wav"); mydsapp.CreateFGSound("bounce.wav"); 따옴표안의 화일명을 고치면 다른 파일로 변경할 수 있다. 배경음악과 효과음악을 구분해놓은 이유는 배경음악은 LOOP옵션을 기본적으로 주었고 효과음악은 재생시에 PlayFGSound();를 호출하면 한번 재생, PlayFGSound(LOOP);로 호출하면 반복재생할 수 있다.
DirectSound의 예제 코딩순서 키보드의 입력을 받을 때마다 효과음악을 재생하고자 하면 WndProc(메시지프로시저함수)에서 switch문안에 case WM_KEYDOWN: mydsapp.PlayFGSound(); return(0); 와같이 코딩하여 호출하면 키보드 입력이 있을 때마다 효과음악을 재생하게 된다.
DirectSound의 예제 MyDirectSound::Initialize(HWND hWnd) 1차버퍼의 포맷을 2채널 22050샘플링 비율 16비트로 정의한다. MyDirectSound ::CreateBGSound(LPTSTR strWaveFileName) 인자로 되어있는 화일이름을 배경음악으로 읽어들인다. MyDirectSound ::CreateFGSound(LPTSTR strWaveFileName) 인자로 되어있는 화일이름을 효과음으로 읽어들인다. MyDirectSound ::PlayBGSound() 배경음악을 재생하는 함수이다. 기본적으로 반복재생을 한다. 재생을 할 수 있는 함수 두번째 플래그에(DWORD)DSBPLAY_LOOPING 인자값을 넣으면 반복 재생을 할 수 있다.
DirectSound의 예제 MyDirectSound ::StopBGSound() 배경음악 재생을 멈추는 함수 생성된 Csound 객체멤버함수인 Reset()를 호출하면 처음부터 재생을 한다. MyDirectSound ::StopFGSound() 효과음 재생을 멈추는 함수