明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

在Delphi下用Direct Sound 完成混音器組件

[摘要]李國柱   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目錄下。