Copyright2008ByNeusoftGroup.Allrightsreserved专题10游戏音乐与音效抛砖引玉•如果您在玩一种以跳舞为主的游戏时,您只能看到屏幕上那些上下左右箭头一直在往上跑,但是却不能听到任何的声音,这时,你只能看着那些箭头猛踩踏板,而不能跟着音乐的节拍起舞,那么游戏玩起来还会觉得有趣吗?•一个好的游戏,除了有真实而具有震撼力的游戏画面之外,游戏的音乐与音效也是相当重要的部分。像仙剑奇侠传的中国古典音乐,暗黑破坏神的欧美风格的音乐,都给玩家留下了深刻的印象。另外,在很多3D射击游戏中,音效的处理也是相当重要的一个工作,程序员往往需要设计一个真实的3D音效,让玩家根据音效来判断所处的环境。Copyright2008ByNeusoftGroup.Allrightsreserved麻雀虽小,五脏俱全•DirectSound简介•声音的播放过程•DirectSound的编程步骤•3D音效的实现Copyright2008ByNeusoftGroup.AllrightsreservedDirectSound简介•DirectSound是DirectXAudio的一个较底层的部件,提供了丰富的接口函数,实现.wav格式的波形声音数据的播放控制。•与一般的WindowsAPI提供的声音播放函数不同,DirectSound可实现多个声音的混合播放,便于在游戏的背景声音下实现各种角色发出声音。DirectSound可充分使用声卡的内存资源,同时也提供了3D声效算法,模拟出真实的3D立体声。Copyright2008ByNeusoftGroup.Allrightsreserved次缓冲区1次缓冲区2次缓冲区3混声器(混频器)主缓冲区主缓冲区和次缓冲区声卡或系统内存声卡内存声音的播放过程:若干声音文件数据,装入相应的次缓冲区中。次缓冲区位于声卡或系统内存中,需要事先进行申请。所申请的次缓冲区大小,一般为对应的声音文件大小。将次缓冲区的声音数据输出到混声器进行混频处理,输出数字化的声音数据到主缓冲区。主缓冲区中的声音数据,转换为模拟信号,送入扬声器中进行播放。Copyright2008ByNeusoftGroup.Allrightsreserved声音的播放过程声音的播放过程•主缓冲区:可以看做是一个DirectSound,是用来播放声音、产生混音效果的区域,它有一个预设的播放格式(8bit、22kHz),而声音文件在播放时便按照这种格式输出。主缓冲区在建立DirectSound对象时自动生成,不过如果需要比默认值更好的播放品质,就必须建立主缓冲区并设定其播放的格式,并且在设定协调级别时,标志位必须设定为DSSCL_PRIORITY或DSSCL_EXCLUSIVE。•次缓冲区:存储播放声音的文件,可以建立多个次缓冲区来存放多个要播放的声音文件。Copyright2008ByNeusoftGroup.AllrightsreservedDirectSound的编程步骤•创建DirectSound对象•设置设备的协调级别•建立主缓冲区•建立次缓冲区•装入声音数据到次缓冲区•声音的播放与控制创建DirectSound对象•创建一个代表声卡的IDirectSound8对象:Copyright2008ByNeusoftGroup.AllrightsreservedHRESULTDirectSoundCreate8(//声卡设备全局标志,一般为NULL,表示默认的声卡LPCGUIDlpcGuidDevice,//返回的IDirectSound8接口对象指针LPDIRECTSOUND8*ppDS8,LPUNKNOWNpUnkOuter//必须为NULL);if(FAILED(DirectSoundCreate8(NULL,&m_pDirectSound,NULL)))returnfalse;设置设备的协调级别•在建立了IDirectSound8对象之后,需要设置声卡设备的协调级别,告诉Windows使用硬件的权限,其他应用软件与游戏如何共享声卡设备。Copyright2008ByNeusoftGroup.AllrightsreservedHRESULTSetCooperativeLevel(HWNDhwnd,//窗口句柄DWORDdwLevel//协调级别);if(FAILED(m_pDirectSound-SetCooperativeLevel(hwnd,dwCoopLevel)))returnfalse;dwLevel有如下几个取值:•DSSCL_EXCLUSIVE:对于DirectX8.0以上版本,此标志与DSSCL_PRIORITY具有相同的作用。对于以前的版本,此标志设置声卡设备为当前程序独占。•DSSCL_NORMAL:正常模式,其他程序可共享设备。此标志下,主缓冲区的播放格式不允许修改。•DSSCL_PRIORITY:具有优先设置DirectSound设备的权限。如:可调用SetFormat函数设置主次缓冲区的播放格式。•DSSCL_WRITEPRIMARY:可写主缓冲区,此时次缓冲区就不可进行播放处理,即不能将次缓冲区的数据送进混声器,再输出到主缓冲区上。Copyright2008ByNeusoftGroup.Allrightsreserved建立主缓冲区Copyright2008ByNeusoftGroup.AllrightsreservedDSBUFFERDESCbufferDesc;ZeroMemory(&bufferDesc,sizeof(DSBUFFERDESC));bufferDesc.dwSize=sizeof(DSBUFFERDESC);//表示主缓冲区bufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER;bufferDesc.dwBufferBytes=0;//主缓冲区必须设置为0bufferDesc.lpwfxFormat=NULL;//主缓冲区必须设置为NULL//取得主缓冲区IDirectSoundBuffer*pDirectSoundBuf=NULL;if(FAILED(m_pDirectSound-CreateSoundBuffer(&bufferDesc,&pDirectSoundBuf,NULL)))returnfalse;•如果需要设置主缓冲区的新播放格式,则可调用CreateSoundBuffer函数,从声卡内存中分配出主缓冲区:CreateSoundBuffer函数原型:Copyright2008ByNeusoftGroup.AllrightsreservedHRESULTCreateSoundBuffer(LPCDSBUFFERDESCpcDSBufferDesc,//缓冲区的描述结构LPDIRECTSOUNDBUFFER*ppDSBuffer,//返回的缓冲区指针LPUNKNOWNpUnkOuter//必须为NULL);typedefstructDSBUFFERDESC{DWORDdwSize;//结构体的大小DWORDdwFlags;//缓冲区的用途标志DWORDdwBufferBytes;//缓冲区的大小DWORDdwReserved;//保留未用,必须为0LPWAVEFORMATEXlpwfxFormat;//声音的格式属性GUIDguid3DAlgorithm;//3D声效算法,一般不必理会}DSBUFFERDESC;DSBUFFERDESC结构体的定义:Copyright2008ByNeusoftGroup.AllrightsreservedWAVEFORMATEXwaveFormat;ZeroMemory(&waveFormat,sizeof(WAVEFORMATEX));waveFormat.wFormatTag=WAVE_FORMAT_PCM;waveFormat.nChannels=1;//单声道waveFormat.nSamplesPerSec=22050;//22.05kHzwaveFormat.wBitsPerSample=16;//16bitwaveFormat.nBlockAlign=(waveFormat.wBitsPerSample/8)*waveFormat.nChannels;waveFormat.nAvgBytesPerSec=waveFormat.nSamplesPerSec*waveFormat.nBlockAlign;if(FAILED(pDirectSoundBuf-SetFormat(&waveFormat)))returnfalse;•创建了主缓冲区后,可以通过调用SetFormat函数来设定主缓冲区的播放格式,以改变声音播放的品质与效果。建立次缓冲区•次缓冲区用来装入实际的声音数据,因此,必须根据实际的声音文件大小,创建一个相应大小的次缓冲区。•.wav文件依据称为RIFF的资源互换文件格式来存放声音数据。文件头包括3个块,分别是RIFF块、fmt块和data块。•每个块由块名称、块的大小以及块的数据构成。RIFF块的名称RIFF块的大小RIFF块的数据fmt块的名称fmt块的大小fmt块的数据data块的名称data块的大小data块的数据fmt块RIFF块data块Copyright2008ByNeusoftGroup.Allrightsreserved•为了读取.wav文件的声音格式数据,并将实际声音数据装入次缓冲区,定义如下的一个对应于.wav文件头的结构体sWaveHeader。Copyright2008ByNeusoftGroup.AllrightsreservedtypedefstructsWaveHeader_tag{charRiffID[4];//'RIFF'块longWaveformChunkSize;//4个字节charWaveID[4];//.wav文件应为'WAVE'类型charFormatID[4];//'fmt'块(末尾有一个空格)longFormatChunkSize;//16个字节shortFormatTag;//.wav文件应为WAVE_FORMAT_PCMshortChannels;//声道数longSampleRate;//采样频率longBytesPerSec;//每秒采样的字节数shortBlockAlign;//块对齐大小shortBitsPerSample;//bit位数(8bit或16bit)charDataID[4];//'data'块longDataSize;//data块的大小(实际的声音数据)}sWaveHeader;读取.wav文件的声音格式数据:Copyright2008ByNeusoftGroup.Allrightsreserved//打开bird.wav文件FILE*fp;if((fp=fopen(bird.wav,rb))==NULL)returnfalse;//定义文件头结构体变量,存储声音属性信息sWaveHeader*pWaveHeader=newsWaveHeader();//读入文件头信息到结构体变量fread(pWaveHeader,sizeof(sWaveHeader),1,fp);//检查是否为.wav文件if(memcmp(pWaveHeader-RiffID,RIFF,4)||memcmp(pWaveHeader-WaveID,WAVE,4)||memcmp(pWaveHeader-FormatID,fmt,4)||memcmp(pWaveHeader-DataID,data,4))returnfalse;•取得文件的声音属性信息后,就可以进行次缓冲区的创建。方法大体上与主缓冲区的创建差不多,只是一些参数的设置需要做出修改。•首先,次缓冲区需要根据.wav文件头的数据,填写一个WAVEFORMATEX结构体的信息,以反映声音数据的基本属性,如下所示:Copyright2008ByNeus