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