220 likes | 455 Views
DirectSound 프로그래밍. DirectSound 를 사용하면 매우 짧은 지연 시간에 사운드를 재생해, 애플리케이션으로 하드웨어 리소스를 치밀하게 제어할 수 있다. DirectSound 인터페이스를 사용하여 다음과 같은 처리가 가능하게 된다. WAV 포맷의 파일 또는 리소스로부터 사운드를 재생한다. 복수의 사운드를 동시에 재생한다. 커스터마이즈 가능한 3 D 환경에 사운드를 배치한다. 메아리나 코러스 등의 이펙트를 추가해, 이펙트의 파라미터를 동적으로 변경한다.
E N D
DirectSound 프로그래밍 • DirectSound를 사용하면 매우 짧은 지연 시간에 사운드를 재생해, 애플리케이션으로 하드웨어 리소스를 치밀하게 제어할 수 있다. • DirectSound 인터페이스를 사용하여 다음과 같은 처리가 가능하게 된다. • WAV 포맷의 파일 또는 리소스로부터 사운드를 재생한다. • 복수의 사운드를 동시에 재생한다. • 커스터마이즈 가능한 3D환경에 사운드를 배치한다. • 메아리나 코러스 등의 이펙트를 추가해, 이펙트의 파라미터를 동적으로 변경한다. • 마이크 또는 그 외의 입력으로부터 WAV 사운드를 캡춰한다.
DirectSound 프로그래밍의 순서 • 장치 개체를 생성 한다. • 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 • 새로운 버퍼의 사이즈 (바이트 단위) • 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 클래스를 이용한 초기화, 협조레벨 설정 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()함수의 인자는 다음과 같다 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); HRESULT CreateFGSound(LPTSTR strWaveFileName); HRESULT PlayBGSound(); HRESULT PlayFGSound(DWORD dwFlag = 0); HRESULT StopBGSound(); HRESULT StopFGSound(); }; class MyDirectSound{ private: CSoundManager m_pCSM; CSound *m_pCSBGSound; CSound *m_pCSFGSound; HRESULT hr; PLAYINFO pi; public: MyDirectSound(); ~MyDirectSound(); HRESULT Initialize(HWND hWnd);
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) • DirectSound를 초기화하는 동시에 협조레벨을 우선 협조레벨로 설정하고있다. • 1차버퍼의 포맷을 2채널 22050샘플링 비율 16비트로 정의한다. • MyDirectSound ::CreateBGSound(LPTSTR strWaveFileName) • 인자로 되어있는 화일이름을 배경음악으로 읽어들인다. • MyDirectSound ::CreateFGSound(LPTSTR strWaveFileName) • 인자로 되어있는 화일이름을 효과음으로 읽어들인다. • MyDirectSound ::PlayBGSound() • 배경음악을 재생하는 함수이다. 기본적으로 반복재생을 한다. • MyDirectSound ::PlayBGSound() • 재생을 할 수 있는 함수 두번째 플래그에(DWORD)DSBPLAY_LOOPING 인자값을 넣으면 반복 재생을 할 수 있다.
DirectSound의 예제 • MyDirectSound ::StopBGSound() • 배경음악 재생을 멈추는 함수 • 생성된 Csound 객체멤버함수인 Reset()를 호출하면 처음부터 재생을 한다. • MyDirectSound ::StopFGSound() • 효과음 재생을 멈추는 함수 • 생성된 Csound 객체멤버함수인 Reset()를 호출하면 처음부터 재생을 한다.