書上的第十一章是聲音系統(tǒng)置侍,Dx9已經(jīng)不支持DirectMusic绩鸣,參考以下代碼可以修改為基于DirectSound的聲音系統(tǒng)
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
using namespace std;
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"dsound.lib")
#pragma comment(lib,"winmm.lib")
#define WINCLASSNAME "winclass1"
#ifndef DSBCAPS_CTRLDEFAULT
#define DSBCAPS_CTRLDEFAULT (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME)
#endif
////////////////////////////////
LPDIRECTSOUND lpds = NULL;
LPDIRECTSOUNDBUFFER lpdbsBuffer = NULL;
DSBUFFERDESC dsbd;
WAVEFORMATEX wfmx;
UCHAR* sndBuffer = NULL;
HWND main_window_handle = NULL;
//////////////////////////////////
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
int GameInit(void* params = NULL, int num = 0);
int GameMain(void* params = NULL, int num = 0);
int GameShutdown(void* params = NULL, int num = 0);
int DSound_Load_Wav(char* filename, int control_flags = DSBCAPS_CTRLDEFAULT);
int GameInit(void* params, int num)
{
if (DirectSoundCreate(NULL, &lpds, NULL) != DS_OK)
return 0;
if (lpds->SetCooperativeLevel(main_window_handle, DSSCL_NORMAL) != DS_OK)
return 0;
DSound_Load_Wav("Windows XP Startup.wav");
lpdbsBuffer->Play(0, 0, 1);
return 1;
}
//-----------------------------------------------------------
//名稱:DSound_Load_Wav
//功能:利用微軟提供的mmio庫厢洞,解析wav文件忍抽,將數(shù)據(jù)讀入內(nèi)存汉嗽,然后拷貝到
//DirectSound建立的 輔助緩沖區(qū) 從而實(shí)現(xiàn)文件的播放(GameInit())
//----------------------------------------------------------
int DSound_Load_Wav(char* filename, int control_flags)
{
HMMIO handle;
MMCKINFO mmckriff, mmckIn;
PCMWAVEFORMAT pwfm;
memset(&mmckriff, 0, sizeof(MMCKINFO));
if ((handle = mmioOpen(filename, NULL, MMIO_READ | MMIO_ALLOCBUF)) == NULL)
return 0;
//--------------------------------------------
//進(jìn)入塊(chunk),查找 riff和wave的標(biāo)記
//----------------------------------------------
if (0 != mmioDescend(handle, &mmckriff, NULL, 0))
{
mmioClose(handle, 0);
return -1;
}
//-----------------------------------------
//#define FOURCC_RIFF mmioFOURCC('R','I','F','F')
//----------------------------------------------
if (mmckriff.ckid != FOURCC_RIFF || mmckriff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))
{
mmioClose(handle, 0);
return -1;
}
/////////////////////////////////////////////
//查找 fmt 塊
////////////////////////////////////////////
mmckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (0 != mmioDescend(handle, &mmckIn, &mmckriff, MMIO_FINDCHUNK))
{
mmioClose(handle, 0);
return -1;
}
////////////////////////////////////////////////////
//fmt塊的格式與PCMWAVEFORMAT 的格式定義相同
//所以讀入臨時變量因妇,最后寫入 wmtf中
////////////////////////////////////////////////////
if (mmioRead(handle, (HPSTR)&pwfm, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
{
mmioClose(handle, 0);
return -1;
}
////////////////////////////////////
//檢測是不是 pc的wave標(biāo)準(zhǔn)格式
//
//////////////////////////////
if (pwfm.wf.wFormatTag != WAVE_FORMAT_PCM)
{
mmioClose(handle, 0);
return -1;
}
/////////////////////////////
//給wmfx賦值
/////////////////////////
memcpy(&wfmx, &pwfm, sizeof(pwfm));
wfmx.cbSize = 0;
if (0 != mmioAscend(handle, &mmckIn, 0))
{
mmioClose(handle, 0);
return -1;
}
/////////////////////////////
//查找 data chunk
/////////////////////////
mmckIn.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (0 != mmioDescend(handle, &mmckIn, &mmckriff, MMIO_FINDCHUNK))
{
mmioClose(handle, 0);
return -1;
}
sndBuffer = new UCHAR[mmckIn.cksize];
/////////////////////////////
//數(shù)據(jù)寫入sndBuffer
/////////////////////////
mmioRead(handle, (HPSTR)sndBuffer, mmckIn.cksize);
mmioClose(handle, 0);
/////////////////////////////
//建立directsound的輔助緩存
//
/////////////////////////
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwBufferBytes = mmckIn.cksize;
dsbd.dwFlags = (control_flags | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE);
dsbd.lpwfxFormat = &wfmx;
if (FAILED(lpds->CreateSoundBuffer(&dsbd, &lpdbsBuffer, NULL)))
{
delete[] sndBuffer;
return -1;
}
VOID* pDSLockedBuffer = NULL;
DWORD dwDSLockedBufferSize = 0;
////////////////////
//lock 住內(nèi)存问潭,現(xiàn)在他是可操作的,拷貝進(jìn)去即可
////////////////
if (lpdbsBuffer->Lock(0, mmckIn.cksize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0L))
return 0;
memcpy(pDSLockedBuffer, sndBuffer, mmckIn.cksize);
///////////////
//Unlock 緩沖區(qū)內(nèi)存
//
////////////////
if (FAILED(lpdbsBuffer->Unlock(pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0)))
{
delete[] sndBuffer;
return 0;
}
return 1;
}
int GameMain(void* params, int num)
{
return 1;
}
INT WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR lCmdline, int nCmdshow)
{
MSG msg;
HWND hwnd;
WNDCLASSEX wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 255, 255));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hinst;
wndclass.lpfnWndProc = WinProc;
wndclass.lpszClassName = WINCLASSNAME;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wndclass);
if (!(hwnd = CreateWindowEx(NULL, WINCLASSNAME, "DSOUND DEMO",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0,
640, 480,
NULL,
NULL,
hinst,
NULL)))
return 0;
main_window_handle = hwnd;
GameInit();
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
GameMain();
}
}
return (int)(msg.wParam);
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (msg)
{
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return (DefWindowProc(hwnd, msg, wparam, lparam));
}
- 創(chuàng)造DirectSound對象最簡單的方法是調(diào)用DirectSoundCreate函數(shù)
LPDIRECTSOUND lpds;
HRESULT hr = DirectSoundCreate(NULL, &lpds, NULL));
該函數(shù)的第一個參數(shù)是硬件設(shè)備婚被,NULL表示使用默認(rèn)的設(shè)備狡忙,第二個參數(shù)是遠(yuǎn)程指針LPDIRECTSOUND的地址,也就是創(chuàng)造的DirectSound對象放置的地址址芯,第三個參數(shù)必須為NULL灾茁,暫時沒有用
- 因?yàn)閃INDOWS是一多任務(wù)環(huán)境,可以允許多個應(yīng)用程序同時工作谷炸,當(dāng)然也會產(chǎn)生多個程序在同時里使用同一設(shè)備工作的情況北专,通過合作級別,DirectX可以保證所有的程序在使用同一設(shè)備時不會發(fā)生沖突
所以每個使用DirectSound的程序都應(yīng)該有一合作級別用來決定允許訪問的設(shè)備旬陡。DirectSound有四種合作級別:標(biāo)準(zhǔn)級拓颓、優(yōu)先級、獨(dú)占級和寫主緩沖級(write-primary描孟,寫是主要的動作)驶睦,其中游戲普遍使用優(yōu)先級這種級別可以使程序在同一采樣條件下作出最柔韌的輸出
lpds->SetCooperativeLevel(main_window_handle, DSSCL_NORMAL)
- 標(biāo)準(zhǔn)級(DSSCL_NORMAL):該級別只能使用22KHZ、立體聲画拾、8位的音樂啥繁,并且不能直接的寫主緩沖,也不能使用壓縮過的聲音
- 優(yōu)先級(DSSCL_PAIORITY):可以實(shí)現(xiàn)硬件混合青抛,可以設(shè)置主緩沖的聲音格式和壓縮過的音樂
- 獨(dú)占級(DSSCL_EXCLUSIVE):當(dāng)應(yīng)用程序在前臺工作時,其它程序是不可使用聲音的
- 寫主緩沖級(DSSCL_WRITEPRIMARY):最高的合作級酬核,程序可以直接的操縱主緩沖蜜另,而且程序必須直接的寫主緩沖區(qū)(最基層的操作).在這種級別,第二緩沖將不可用
- 播放聲音播放聲音要通過以下步驟:
- 鎖定輔助緩沖的一部分以獲得你所需要的那部分緩沖的基址
- 向緩沖寫數(shù)據(jù)
- 解鎖
- 使用IDirectSoundBuffer::Play方法來播放聲音