在Delphi下用Direct Sound 完成混音器組件
發(fā)表時間:2023-08-21 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]李國柱 Direct X是微軟公司提供給游戲編寫人員的一套應(yīng)用程序編程接口(APIs),它為編寫高效、實時的應(yīng)用程序提供了有力的支持。因此,有必要將這個接口封裝到Delphi的組件庫中。Dire...
李國柱
Direct X是微軟公司提供給游戲編寫人員的一套應(yīng)用程序編程接口(APIs),它為編寫高效、實時的應(yīng)用程序提供了有力的支持。因此,有必要將這個接口封裝到Delphi的組件庫中。Direct X SDK是面向Visual C/C++和Watcom C/C++的,因而使用Object Pascal直接存取Direct X SDK,將帶來諸多不便。但我們可先在VC下將Direct X接口封裝成動態(tài)鏈接庫,然后在Delphi下通過該動態(tài)鏈接庫去存取Direct X。
本文介紹用Delphi封裝Direct Sound的方法,這種方法同樣也可以應(yīng)用到Direct Draw(但建議不要使用獨占模式,否則會帶來不少問題)。
先簡單介紹一下Direct Sound的接口界面。Direct Sound的基本對象有兩個,即IDirectDraw和IDirectDrawBuffer。前者代表聲卡,后者代表聲音數(shù)據(jù)緩沖區(qū)。
IDirectDraw是整個Direct Sound的基礎(chǔ),其建立方法如下:
LPDIRECTSOUND lpDS;
HRESULT ErrorCode;
HWND hwnd=Mainhwnd;//窗口句柄
ErrorCode=DirectSoundCreate(NULL, &lpDS, NULL); //建立對象
if(ErrorCode!=DS_OK)return FALSE; //失敗則返回
ErrorCode=lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL);//設(shè)置存取模式
if(ErrorCode!=DS_OK) //失敗則返回
{
lpDS->Release();
lpDS=NULL;
return FALSE;
}
IDirectDrawBuffer通過IDirectDraw建立。IDirectDrawBuffer有兩種基本類型,一種被稱作“基本緩沖區(qū)”(Primary Buffer), 另一種被稱作“輔助緩沖區(qū)”(Secondary Buffer)。 基本緩沖區(qū)是Direct Sound 混音的基礎(chǔ),一般不直接存取這個緩沖區(qū)(雖然也可以),但可以通過該緩沖區(qū)去存取初始化聲卡,方法如下:
HRESULT ErrorCode;
LPDIRECTSOUND lpDS=lpMainDS;//Direct Sound對象
LPDIRECTSOUNDBUFFER lpDBP;
DSBUFFERDESC dsbds;
ZeroMemory(&dsbds,sizeof(dsbds));
dsbds.dwSize=sizeof(dsbds);
dsbds.dwFlags=DSBCAPS_PRIMARYBUFFER;
ErrorCode=lpDS->CreateSoundBuffer(&dsbds,&lpDBP,NULL);//建立基本緩沖區(qū)
if(ErrorCode!=DS_OK)return FALSE;//失敗則返回
ErrorCode=lpDBP->Play(0,0,DSBPLAY_LOOPING);//初始化
if(ErrorCode!=DS_OK)//失敗則返回
{
lpDBP->Release();
lpDBP=NULL;
lpDS->Release();
lpDS=NULL;
return FALSE;
}
lpDBP->Release();//釋放基本緩沖區(qū)
return TRUE; //初始化成功
輔助緩沖區(qū)可以建立任意多個,聲音數(shù)據(jù)就放在這種緩沖區(qū)內(nèi),每個緩沖區(qū)可被獨立播放(IDirectSoundBuffer::Play),Direct Sound會處理這些聲音并實現(xiàn)混音的效果。其建立方法與基本緩沖區(qū)的差不多,只是對DSBUFFERDESC的填寫有些不一樣:
ZeroMemory(&dsbufferdesc,sizeof(dsbufferdesc));
dsbufferdesc.dwSize=sizeof(dsbufferdesc);
dsbufferdesc.dwFlags=DSBCAPS_STATIC DSBCAPS_CTRLDEFAULT;
dsbufferdesc.dwBufferBytes=BufferSize;//緩沖區(qū)大小
dsbufferdesc.lpwfxFormat=(LPWAVEFORMATEX)&pcmformat;//wav文件的PCM格式
ErrorCode=lpDS->CreateSoundBuffer(&dsbd,&lpSB,NULL);
建立該緩沖區(qū)后,通過IDirectSoundBuffer::Lock鎖定內(nèi)存即可寫入數(shù)據(jù)。數(shù)據(jù)可以用普通MCI的多媒體函數(shù)讀取,由于篇幅所限,這里不再詳述,讀者可以參考Win32 SDK手冊和Direct X SDK的聯(lián)機幫助。值得注意的是,Direct Sound的緩沖區(qū)是循環(huán)的,Lock返回兩個指針,數(shù)據(jù)必須分成兩部分寫入。
數(shù)據(jù)進入DirectSoundBuffer后,就可以調(diào)用IDirectSoundBuffer的聲音控制方法來控制聲音的播放、停止、頻率、聲道等特性。但要注意的是:因為Win95是多任務(wù)的,設(shè)備有可能被別的程序占用,所以IDirectSoundBuffer的功能調(diào)用可能會引發(fā)DSERR_BUFFERLOST錯誤。此時,如果要確保你的請求一定會得到響應(yīng),則必須調(diào)用IDirectSoundBuffer::Restore以重新獲得設(shè)備。
掌握了這些基本概念后,就可以在C++中編寫Direct Sound的控制程序了,但Delphi無法直接存取上面提及的數(shù)據(jù)結(jié)構(gòu)。為了解決這個問題,我們可以定義一個數(shù)組,分別代表不同的輔助緩沖區(qū),Dephi通過該數(shù)組的索引來使用多個緩沖區(qū)。因此,我們的DLL中至少包括以下的接口函數(shù):
CreateDSoundInterface(HWND hwnd)//初始化
LoadWave(int index, char *filename)//裝入wav數(shù)據(jù)
Play(int Index) //播放
Stop(int Index)//停止
Clear(int Index)//釋放緩沖區(qū)
當然,還可以加入其它控制,例如對頻率、聲道等的控制。
有了動態(tài)鏈接庫后,在Delphi中編寫混音器組件的方法就比較簡單了,與其它組件基本上沒什么區(qū)別。
首先,新建一個組件(New Component),設(shè)定其祖先類型為TComponent。然后,編寫相應(yīng)的方法初始化設(shè)備,實現(xiàn)DLL中提供的功能。這里只作兩點說明:
1、不要在繼承的Create函數(shù)中加載DLL和初始化設(shè)備。不在構(gòu)造方法中初始化設(shè)備是明智的做法,因為這樣做較安全。
2、因為DLL是用C編寫的,所以接口函數(shù)說明必須是C的調(diào)用標準,例如可以像下面這個樣子:
Var
DllFunction :
function(Parametre : ParaType) : RusultType; cdecl;
......
LibraryHandle=LoadLibrary('DllFile.dll');
......
@DllFunction:=GetProcAddress(LibHandle,'DllFunction_Name');
組件單元編好以后,可通過選擇Component Install Component菜單來將組件裝入Delphi的組件庫即可使用它。
本文所介紹的程序在Visual C++ 4.2、Delphi 3.0、Direct X 5.0 SDK下通過,但程序功能只需VC 2.0、 Delphi 2.0、 Direct X 2.0(Visual C 4.0內(nèi)置Direct X 2.0 SDK)支持即可。若要確保程序能夠正常運行,則必須在Win95下安裝Direct X,并將DLL文件放到\Windows\System目錄下。