상세 컨텐츠

본문 제목

다이렉트사운드(DirectSound) 관련

프로그래밍 관련/사운드

by AlrepondTech 2020. 9. 17. 10:36

본문

반응형

 

 

=================================

=================================

=================================

 

 


출처 : http://blog.naver.com/dunyazad/150030270349

-13장#1-다이렉트사운드(DirectSound)  

사운드가 없는 게임은 단팥없는 붕어빵과도 같다.

사운드의 사용으로 타격감, 게임의 몰입도, 긴장감 등을 극대화 시킬 수 있는 것이다.

DirectX에서는 사운드를 사용하기 위해서 다이렉트 사운드(DirectSound)를 제공한다.

 

다이렉트 사운드를 사용하기 위해서는  Project >> Settings 의 Link 탭으로 이동하여

 Object/library modules  항목란에 dsound.lib 를 추가한다.

또는, #pragma comment(lib,"dsound.lib")  사용하여 추가해도 된다.

  

다이렉트 사운드의 구조는 DirectDraw와 비슷하고, 설정방법 또한 비슷하다.

 

1. 다이렉트 사운드의 객체를 생성한다.  DirectSoundCreate8() 함수사용.

2. 협력레벨을 설정한다. IDirectSound8::SetCooperativeLevel()함수 사용.

3. 보조 사운드 버퍼를 생성한다.  IDirectSound8::CreateSoundBuffer()함수 사용.

4. 생성된 보조 사운드 버퍼에 사운드정보를 복사한다.

마지막으로, 프로그램 종료시에는 반드시 사용중인 객체들을 해제시킨다.

 

여기서는 IDirectSound8 인터페이스를 사용한다.

DirectDraw7 인터페이스를 사용하면서  버전이 틀린 IDirectSound8 인터페이스를

사용할 수 있다는 것이 가능한가??

물론, 가능하다. DirectSound는 DirectDraw에 포함된 구성요소가 아니고,

DirectX에 포함된 구성요소이다. 또한, 우리는 1장에서 DirectX9.0b SDK를 설치했기 때문에

하위버전인 IDirectSound8를 사용할 수 있는 것이다.

 

위의 순서대로 함수의 원형들과 사용방법을 알아보도록 하자.

첫 번째, HRESULT  DirectSoundCreate8(LPGUID lpGuid, 

                             LPDIRECTSOUND8* lpDS8,  //LPDIRECTSOUND8의 포인터 변수

                             IUnknown FAR* pUnkOuter  //항상 NULL 이다.

 

lpGuid는 사운드 카드의 장치 포인터이고, NULL을 넘겨주면 디폴트 장치를 선택한다.

 

사용 예)----------------------------------------------------------------------

  LPDIRECTSOUND  g_lpDS = NULL;

  if( DirectSoundCreate8(NULL, &g_lpDS, NULL) != DS_OK )
        return FALSE;

------------------------------------------------------------------------------

 

두 번째, HRESULT SetCooperativeLevel(HWND hWnd,  //메인 윈도우 핸들

                                                           DWORD dwLevel )  //협력레벨 플래그 

협력레벨은 아래와 같이 4가지가 있다.

DSSCL_NORMAL - 일반적인 협력레벨. 응용프로그램이 활성화 중일때만 사운드를

    출력한다. 주버퍼를 제어하기 위한 코드를 작성할 필요가 없으며, 대 부분 이 설정을

    사용한다.

DSSCL_PRIORITY - 우선순위 협력레벨. 사운드카드에 접근할 수 있는 권한을

    가지게 되며, 주 사운드 버퍼의 일반적인 제어권이 프로그래머에게 있게 된다.

    이 설정은 사운드압축과 같은 주 사운드 버퍼의 데이터형식 변경작업을 필요로 할 경우

    사용된다.

DSSCL_EXCLUSIVE - 독점(배타적) 협력레벨. 우선순위 협력레벨과 비슷하지만

     응용프로그램이 활성화 되어 있을 때만 사운드를 출력할 수 있다.

DSSCL_WRITERPRIMARY - 가장 높은 협력레벨로서, 주 사운드 버퍼의 모든 제어권한이

     주어진다. 즉 플레이, 정지 등의 동작들을 프로그래머가 직접 제어해야 한다.

     자신만의 사운드 믹서, 사운드 엔진을 만들 때에만 이 모드를 사용하면 된다.

 

사용 예)------------------------------------------------------------------------

g_lpDS->SetCooperativeLevel( hWnd, DSSCL_NORMAL ) != DS_OK )
        return FALSE;

---------------------------------------------------------------------------------

 

세 번째, HRESULT  CreateSoundBuffer(LPCDSBUFFERDESC  lpcDSBuffDesc,

                               LPLPDIRECTSOUNDBUFFER  lplpDSBuff,

                               IUnknown FAR* pUnkOuter)  //항상 NULL 이다.

lpcDSBuffDesc에는 DSBUFFERDESC 포인터를 넘겨주면 되고, lplpDSBuff는 사운드 버퍼의

포인터를 넘겨주면 된다.

DSBUFFERDESC 구조체의 원형은 아래와 같다.

typedef struct{

   DWORD                   dwSize;             //구조체의 크기를 대입

   DWORD                   dwFlags;           //보조 사운드 버퍼의 플래그 정보를 대입

   DWORD                   dwBufferBytes; //사운드 버퍼의 크기를 대입.단위는B yte이다.

   DWORD                     dwReserved;  //사용하지 않는다.

   LPWAVEFORMATEX  lpwfxFormat;  //WAVEFORMATEX 구조체 정보를 받는다.

   GUID                         guid3DAlgorithm;

}DSBUFFERDESC, *LPDSBUFFERDESC;

 

위 구조체에서 상당히 주의해야 할 멤버들은 dwFlags와 lpwfxFormat 이다.

dwFlags 에 자주 사용되는 플래그는 아래와 같다.

DSBCAPS_CTRLALL - 버퍼는 모든 제어 기능을 가진다.

DSBCAPS_CTRLDEFAULT - 버퍼는 기본 제어 옵션을 가진다. 이 값은

   DSBCAPS_CTRLVOLUME, DSBCAPS_CTRLFREQUENCY 를 지정하는 것과 동일하지만, 

   이 플래그 값은 DirectX6.0 이후 부터 없어졌다.

DSBCAPS_CTRLFREQUENCY - 버퍼는 주파수 제어 기능을 가진다.

DSBCAPS_CTRLPAN - 버퍼는 팬(pan)기능을 가진다.

DSBCAPS_CTRLVOLUME - 버퍼는 볼륨제어 기능을 가진다.

DSBCAPS_STATIC - 버퍼가 정적 사운드 데이타에 사용될 것임을 알린다. 대부분 하드웨어

        (사운드카드) 메모리에 생성한다.

DSBCAPS_LOCHARDWARE - 메모리가 사용 가능하다면, 하드웨어(사운드카드) 메모리에

      사운드 버퍼를 생성하며, 하드웨어 믹싱을 사용한다.

DSBCAPS_LOCSOFTWARE - 시스템 메모리(RAM)에 사운드 버퍼를 생성하며, 소프트웨어

     믹싱을 사용한다.

DSBCAPS_PRIMARYBUFFER - 주 사운드 버퍼로 생성한다. 이 플래그를 주지 않으면

     기본값으로 보조 사운드 버퍼로 생성된다.

 

대 부분,  DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE 를 주어서 기본제어,

정적 사운드, 그리고 시스템 메모리를 사용하도록 설정한다.

DSBCAPS_CTRLDEFAULT 플래그는 Directx6.0 이후 부터 없어졌으며, 설정하지 않아도

기본값으로 기본제어 옵션이 설정된다.

하드웨어(사운드 카드) 메모리를 사용하기 위해서는 DSBCAPS_LOCSOFTWARE 대신에,

DSBCAPS_LOCHARDWARE 를 주면 된다.

 

WAVEFORMATEX 구조체의 원형은 아래와 같다.

typedef struct {

    WORD   wFormatTag; //항상 WAVE_FORMAT_PCM 을 대입한다. 

    WORD   nChannels;    //사운드의 채널 수. 1일때는 MONO, 2일때는 STEREO

    DWORD  nSamplesPerSec; //주파수(Mhz)를 대입한다.

    DWORD  nAvgBytesPerSec; //평균 데이타 비율( nSamplesPerSec * nBlockAlign )

    WORD    nBlockAlign; //블럭당 전체 데이타를 설정. 모노일땐 1, 스테레오일땐 2

    WORD    wBitsPerSample; //샘플당 비트수를 대입한다.

    WORD    cbSize;               //항상 0이다.

}WAVEFORMATEX;

 

CreateSoundBuffer()함수 사용 예)-----------------------------------------------

DSBUFFERDESC dsbd;

//구조체에 값을 채운 후 ..........

g_lpDS->CreateSoundBuffer( &dsbd, &g_lpDSBuffer, NULL) != DS_OK )
        return FALSE;

--------------------------------------------------------------------------------

 

참고 : 다이렉트 사운드의 함수들은 수행에 성공하면 DS_OK 를 반환한다.

 

마지막 단계, 생성된 보조 사운드 버퍼에 IDirectSoundBuffer::Lock()함수를 사용하여

버퍼를 잠근 후, 사운드정보를 버퍼에 복사하면 된다.

 

함수 원형은 아래와 같다.

HRESULT Lock(DWORD dwWriteCursor, //어디서부터 잠글 것인가를 설정

                DWORD dwWriteBytes,         //얼만큼 잠글 것인가를 설정

                LPVOID lplpAudioPtr1,          //첫번째 영역의 주소

                LPDWORD lpdwAudioBytes1, //첫번째 영역의 길이(Byte)

                LPVOID lplpAudioPtr2,           //두번째 영역의 주소

                LPDWORD lpdwAudioBytes2, //두번째 영역의 길이(Byte)

                DWORD dwFlags);                 //잠금 설정 플래그

               

dwFlags를 DSBLOCK_FROMWRITECURSOR 로 설정하면, 버퍼의 현재 기록커서

(write cursor)로 부터 잠겨지게 된다. DSBLOCK_ENTIREBUFFER 로 설정하면,

전체 버퍼가 잠겨진다.

 

Lock()함수에서 알 수 있듯이, 다이렉트 사운드는 사운드 버퍼를 두개의 영역으로 나누어서

처리한다. 아래 그림은 1000Byte의 사운드 버퍼를 생성한다고 했을 때, 첫 번째 영역=900,

두 번째 영역=100 으로 나눈 것을 보여준다.

 

그런데, 첫 번째 영역과 두 번째 영역이 서로 바뀐 것을 볼 수 있는데, 이렇게 하는 이유는

(여러가지 이유가 있겠지만) 사운드의 처리속도를 빠르게 하고 사운드의 재생이

끊기지 않고 반복 될 수 있도록 하기위해서 이다.

 

첫 번째 버퍼에 있는 사운드를 재생하는 동안에 두 번째 버퍼에는 나머지 사운드 부분을

저장한다. 그리고 첫 번째 버퍼에 있는 사운드의 재생이 끝나면, 곧바로 두 번째 버퍼에

저장된 사운드를 재생하게 된다.

이렇게 처리함으로서, 사운드의 처리 속도를 빠르게 하고 사운드의 재생이 끊기지 않고

반복되는 것이다.

복사작업이 끝났다면 IDirectSoundBuffer::Unlock() 함수를 호출하여 잠금상태를

꼭 풀어야 한다.

 

이렇게 사운드 버퍼를 생성하고, 사운드 파일을 불러와서 복사를 했다면, DirectSound에서

제공하는 함수를 통하여, 손쉽게 플레이, 정지, 볼륨조절 등을 할 수 있다.

 

그런데, DirectSound 에서는 사운드 파일을 불러오는 기능이 없다.

따라서, 사운드 파일을 불러오는 함수를 직접 만들어야 한다. (DirectDraw에서 비트맵

파일을 불러오는 것처럼.)

 

다음 장에서 wav 파일을 불러와서, 게임내에서 출력할 수 있는 함수들을 만들어 보도록

하겠다. 

 

=================================

=================================

=================================

 

 

 

 

반응형

 

 

728x90

 

 

 

 

2008/04/12 23:42

 http://blog.naver.com/dunyazad/150030270389 

-13장#2-다이렉트사운드(DirectSound) 

어떤 파일을 로드할려면 먼저 그 파일에 대한 구조(정보)를 알아야 할 수 있다.

wav 파일 역시 이 해부과정(?)을 피해 갈 수 없다.-_-;;;

wav파일의 구조를 알아보기 전에, RIFF(Resource Interchange File Format)란

무엇인가에 대해서 간단히 알아보자.

 

음성이나 비디오 같은 멀티미디어 데이터들은 용량이 매우 크기 때문에, 저장할 때 비트단위

보다는 블럭(block) 단위로 저장을 하게 된다.

이렇게, 멀티미디어 데이터들을 블럭 단위로 저장하기 위해 만든 포맷을 RIFF라고 하며,

RIFF 방식으로 저장된 파일을 RIFF 파일이라고 한다.

그리고, RIFF파일을 구성하는 각각의 블럭을 chunk(청크)라고 한다.

RIFF 파일의 처음은 부모청크(Parent chunk)가 되며, 그 다음에 위치하는 것들이 자식청크

(child chunk)가 된다.

 

wav 파일은 RIFF 형식으로 되어 있으며, 아래 그림과 같은 구조를 가진다.

RIFF Chunk는 WAVE Chuck 의 부모청크이며, 멀티미디어 파일이라는 것을 나타내는

정보가 들어있다.

WAVE Chunk는 fmf Chunk 와 data Chunk  두 개의 자식청크를 가지며,

fmf Chunk에는 wav파일의 정보,즉 WAVEFORMATEX 구조체가 담겨있고,

data Chunk에는 순수한 사운드데이터(순수한 wave data)가 담겨있다.

 

이런 구조를 가진 wav 파일을 MMIO(Multi Media Input Output) 함수들을 사용해서 

로드한 후에, data Chunk에 있는 사운드 데이터를 DirectSound의 보조 사운드버퍼에

복사하면 되는 것이다.

 

참고---------------------------------------------------------------------------

MMIO 는 마이크로소프트사가 만든 Win32 API의 일부로서, 멀티미디어 입출력을

다루는 함수들을 말한다.

-------------------------------------------------------------------------------

 

그럼, 소스를 보도록 하자.

-----------------------------------------------------------------------------------

//Sound.h 파일

 

#include <windows.h>
#include <mmsystem.h> //이 헤더파일은 windows.h에 정의한 매크로영향을 받기

                                     //때문에 반드시 windows.h를 포함된 다음에 인클루드

                                     //해 줘야 한다.
#include <dsound.h>

 

#ifndef DSBCAPS_CTRLDEFAULT  //6.0이후 부터 없어졌으므로 define해줌 
#define DSBCAPS_CTRLDEFAULT  (DSBCAPS_CTRLFREQUENCY |

                                                     DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME)
#endif

 

//입력값을 dB(decibel)로 바꿔주는 매크로 함수
#define DSVOLUME_TO_DB(volume)   ((DWORD)(-30*(100-volume))) 

 

BOOL CreateDirectSound(HWND hWnd);
BOOL LoadWave(LPSTR lpFileName, LPDIRECTSOUNDBUFFER* lpDSBuffer);
BOOL SetVolume(LPDIRECTSOUNDBUFFER lpDSBuffer, LONG lVolume);
BOOL SetPan(LPDIRECTSOUNDBUFFER lpDSBuffer, LONG lPan);

 

void DeleteDirectSound();
void Play(LPDIRECTSOUNDBUFFER lpDSBuffer, BOOL Loop);
void Stop(LPDIRECTSOUNDBUFFER lpDSBuffer);

.......................................................................................................................

 

//Sound.cpp 파일

 

#include "sound.h"


LPDIRECTSOUND8  g_lpDS = NULL;  //다이렉트 사운드개체
BOOL                    g_bPlay=FALSE;


//함수명 : CreateDirectSound() 
//설명   : DirectSound 객체를 생성하고 협력레벨을 설정한다.
BOOL CreateDirectSound(HWND hWnd)
{
   //다이렉트 사운드 개체 생성 
    if( DirectSoundCreate8(NULL, &g_lpDS, NULL) != DS_OK )
        return FALSE;
 
    //협력수준 설정- DSSCL_NORMAL로 설정 
    if( g_lpDS->SetCooperativeLevel( hWnd, DSSCL_NORMAL ) != DS_OK )
        return FALSE;

     
    return TRUE;
}


//함수명 : DeleteDirectSound() 
//설명   : DirectSound 객체를 해제한다.
void DeleteDirectSound()
{

   g_lpDS->Release();

   g_lpDS = NULL;
}


//함수명 : LoadWave() 
//설명   : 파일로 부터 wav파일을 읽어 메모리에 로드한다.
BOOL LoadWave(LPSTR lpFileName, LPDIRECTSOUNDBUFFER* lpDSBuffer)
{

   HMMIO          hmmio;              //wave파일의 핸들

   MMCKINFO    ckInRIFF, ckIn;  //부모 청크 , 자식 청크 
   PCMWAVEFORMAT  pcmWaveFormat;
   WAVEFORMATEX*     pWaveFormat;      
 
 //웨이브 파일을 열어, MMIO 핸들을 얻는다.
 hmmio = mmioOpen(lpFileName, NULL, MMIO_ALLOCBUF|MMIO_READ);
    if(hmmio==NULL)  return FALSE;
    
 //내려갈 하위 청크이름을 등록하고, 현재 위치인 RIFF청크에서 WAVE청크를

 //찾아 내려간다.
 ckInRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
 if( (mmioDescend(hmmio, &ckInRIFF, NULL, MMIO_FINDRIFF)) != 0 )
 {

    mmioClose(hmmio, 0);  //실패하면 열려있는 웨이브파일을 닫고 리턴(꼭 해준다.)
    return FALSE;
 }
 //내려갈 하위 청크이름을 등록하고, 현재 위치인 WAVE청크에서 fmt 청크를 찾아 내려간다.
 //주의: 모든 청크는 4개의 문자코드를 갖기 때문에 t 다음에 공백문자가 있다.
  ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); 
 if( mmioDescend(hmmio, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0)
 {

     mmioClose(hmmio, 0);//실패하면 열려있는 웨이브파일을 닫고 리턴(꼭 해준다.)
     return FALSE; 
  }

  //fmt 청크에서 wav파일 포맷(Format)을 읽어 들인다.
  if( mmioRead(hmmio, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat))

      != sizeof(pcmWaveFormat) )
  {

      mmioClose(hmmio, 0);//실패하면 열려있는 웨이브파일을 닫고 리턴(꼭 해준다.)
      return FALSE;
  }

 //WAVEFORMATEX를 메모리에 할당 
   pWaveFormat = new WAVEFORMATEX;

 //PCMWAVEFORMAT로부터 복사한다.
    memcpy( pWaveFormat, &pcmWaveFormat, sizeof(pcmWaveFormat) );
    pWaveFormat->cbSize = 0;

  

  //fmt Chunk 에서 부모청크인 WAVE Chunk로 올라간다.
  if( mmioAscend(hmmio, &ckIn, 0) )
  {

     mmioClose(hmmio, 0);//실패하면 열려있는 웨이브파일을 닫고 리턴(꼭 해준다.)
     return FALSE;
   }
 
 //내려갈 하위 청크이름을 등록하고, 현재 위치인 WAVE청크에서 data 청크를

 //찾아 내려간다.
 ckIn.ckid = mmioFOURCC('d', 'a', 't', 'a');
 if( mmioDescend(hmmio, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0 )
 {

    mmioClose(hmmio, 0);//실패하면 열려있는 웨이브파일을 닫고 리턴(꼭 해준다.)
    return FALSE;
 }
   
  BYTE*   pData = NULL;
 //data chunk 사이즈 만큼 메모리 할당
  pData = new BYTE[ckIn.cksize] ;

 //data chunk에 있는 순수한 wave data를 읽어 들인다. 
  mmioRead(hmmio, (LPSTR)pData, ckIn.cksize);
 
 //여기까지 왔으면 wav파일읽기에 성공한 것이므로, 열려있는 wav파일을 닫는다. 
  mmioClose(hmmio, 0);

 

 // DSBUFFERDESC 구조체 정보를 채운다.
    DSBUFFERDESC dsbd;
    ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
    dsbd.dwSize        = sizeof(DSBUFFERDESC);
    dsbd.dwFlags       = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC |

                                   DSBCAPS_LOCSOFTWARE ;

    dsbd.dwBufferBytes = ckIn.cksize;

    dsbd.lpwfxFormat   = pWaveFormat;
    
   //사운드 버퍼의 생성
    if( g_lpDS->CreateSoundBuffer( &dsbd, lpDSBuffer, NULL ) != DS_OK )

       return FALSE;
    
    VOID* pBuff1 = NULL;  //사운드 버퍼의 첫번째 영역주소  
    VOID* pBuff2 = NULL;  //사운드 버퍼의 두번째 영역주소 
    DWORD dwLength;      //첫번째 영역크기        
    DWORD dwLength2;     //두번째 영역크기

   //사운드 버퍼에 순수한 wav데이터를 복사하기 위해 락을 건다.
    if( (*lpDSBuffer)->Lock( 0, dsbd.dwBufferBytes, &pBuff1, &dwLength, 
                              &pBuff2, &dwLength2, 0L ) != DS_OK )
    {

        (*lpDSBuffer)->Release();

        (*lpDSBuffer) = NULL;

        return FALSE;

     }

   

     memcpy( pBuff1, pData, dwLength );                     //버퍼의 첫번째 영역을 복사

     memcpy( pBuff2, (pData+dwLength), dwLength2); //버퍼의 두번째 영역을 복사

    //잠금 상태를 풀어준다.
    (*lpDSBuffer)->Unlock(pBuff1, dwLength, pBuff2, dwLength2 );
     pBuff1 = pBuff2= NULL;
  
 //할당된 메모리를 해제
   delete[] pData;
   delete pWaveFormat;

   

    return TRUE;   
}


//함수명 : Play()
//설명   : 해당 사운드를 플레이 한다.
void Play(LPDIRECTSOUNDBUFFER lpDSBuffer, BOOL Loop)
{
 //버퍼가 비어있으면 종료 
  if( lpDSBuffer==NULL )  return;
  

  //재생중 실패하면 종료 
  if( !lpDSBuffer->Play( 0, 0, (Loop) ? 1 :0 ) )  return;
  
   g_bPlay = TRUE; 
}


//함수명 : Stop()
//설명   : 해당 사운드를 멈춘다.
void Stop(LPDIRECTSOUNDBUFFER lpDSBuffer)
{

   //버퍼가 비어있으면 종료

    if(lpDSBuffer == NULL)  return;
    

    lpDSBuffer->Stop();  //멈춤

   

     g_bPlay = FALSE;

     lpDSBuffer->SetCurrentPosition(0L); //처음위치로
}


//함수명 : SetVolume()
//설명   : 해당 사운드의 볼륨을 조절한다.(100이면 최대출력, 0이면 무음)
BOOL SetVolume(LPDIRECTSOUNDBUFFER lpDSBuffer, LONG lVolume)
{

    if( lpDSBuffer->SetVolume( DSVOLUME_TO_DB(lVolume)) != DS_OK )

       return FALSE;

   

     return TRUE;  
}

//함수명 : SetVolume()
//설명   : 스테레오 패닝조절(범위는 -10000~10000)
BOOL SetPan(LPDIRECTSOUNDBUFFER lpDSBuffer, LONG lPan)
{

   if( lpDSBuffer->SetPan(lPan) != DS_OK )

      return FALSE;

 

    return TRUE;
}

 

-----------------------------------------------------------------------------------

 

헤더파일( Sound.h )에 DSBCAPS_CTRLDEFAULT  를 재정의 해 주었다.

13장#1에서 설명했듯이 DSBCAPS_CTRLDEFAULT 는 사라져서, 아무런 지정을 하지않으면

기본적으로 DSBCAPS_CTRLDEFAULT 를 지정한 효과를 가진다. 

하지만, 유연성 측면에서 만들어 보았다.

 

DirectSound에서 볼륨단위인 dB(decibel)은 0값이 최대 볼륨이고, -10000이 무음이다.

우리가 일반적으로 생각하는 볼륨값이 아니므로, 0~100까지의 값을 넘겨주면 dB로

변환 시켜주는 매크로 함수 DSVOLUME_TO_DB(volume)를 만들었다.

 

함수 정의부인 Sound.cpp 의 CreateDirectSound() 함수는 다이렉트 사운드 객체를

생성하고, 협력 레벨을 설정한다.( 13장#1에서 설명한 것과 동일한 순서이다.)

 

LoadWave()함수는 MMIO 함수들을 사용해서 wav파일을 로드한 후, 보조사운드 버퍼를

생성하고 복사를 한다.

wav파일을 로드해서 필요한 정보를 뽑아내는 순서는

파일을 연다 -> fmt Chunk를 찾아서 그 안에 있는 wav파일 포맷을 읽어 들인다.

-> data Chunk 를 찾아서 그 안에 있는 순수한 사운드 데이터를 읽어 들인다.

함수 내에서 쓰인 MMIO 함수들에 대한 자세한 사항들은 MSDN을 참고하기 바란다.

(소스내의 주석을 참조해도, 어느 정도 함수의 기능에 대해서 알 것이다.)

 

이러한 순서를 거쳐서 알아낸 데이터들을 가지고 보조 사운드 버퍼를 생성하고,

보조 사운드 버퍼에 사운드 데이터를 복사하면 되는 것이다.

 

그리고 나머지 함수들은 Play, 멈춤, 볼륨조절, 패닝설정 을 하는 함수들이다.

단순히, DirectSound에서 제공하는 함수를 호출하는 루틴만 들어있는 랩퍼함수들이므로

설명은 하지 않겠다.

 

참고로 패닝(Panning)이란 스피커의 양쪽에서 나오는 소리의 밸런스를 변경하는 것이다.

예를 들어, 왼쪽 패닝을 증가 시키면, 오른쪽 볼륨이 줄고 왼쪽 볼륨은 커지게 된다.

반대로 한다면, 왼쪽 볼륨이 줄고 오른쪽 볼륨이 커질 것이다.

이런 패닝을 통하여서 게임내에서 3D 사운드를 얻을 수 있게 도와준다.

 

위 함수들을 적용하는 간단한 예제(정말 간단하다..전부 생략..-_-;; )

--------------------------------------------------------------------------------

//그 동안 사용했던 소스에서 Demp.cpp 파일

#include "Demo.h"
#include "Sound.h"

 

//..

//중략

LPDIRECTSOUNDBUFFER   g_lpDSBG[2] = {NULL,};  //두개의 배경음악을 담을 버퍼

//..

//중략

//..

/함수명 : InitDemo()
//설명   : 프로그램 실행에 필요한 객체들을 초기화 한다.
BOOL InitDemo()
{

   //초기화 하는 곳에서 다이렉트 사운드 객체를 생성한다.

    CreateDirectSound(g_hWnd);

   //그리고, wav파일을 로드하여, 보조버퍼를 생성한다.

    LoadWave("BGM1.wav",&g_lpDSBG[0]);

    LoadWave("BGM2.wav",&g_lpDSBG[1]);
 

//중략...   
//..

}

//..

//게임이 실질적으로 돌아가는 함수내에서 Play()함수를 호출하면 된다.

//함수명 : DemoRun()
//설명   : 전체적인 프로그램을 실행한다.
void DemoRun()
{

    //..중략

    //...

     Play(g_lpDSBG[0],FALSE);  //첫번째 배경음악은 조건없이 나온다.

     //업키가 눌리면 두번째 배경음악이 나온다.

     if( KEYDOWN(VK_UP) )      Play(g_lpDSBG[1],FALSE);

   

     //.. 이하 생략..

}

----------------------------------------------------------------------------------

프로그램 종료전에 생성된 버퍼와 DirectSound 객체를 해제하는 것을 잊지 말자!!!

 

 

=================================

=================================

=================================

 

 

반응형


관련글 더보기

댓글 영역