程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 在 Delphi 下使用 DirectSound (9): 效果器初步及 IDirectSoundFXGargle8 效果器

在 Delphi 下使用 DirectSound (9): 效果器初步及 IDirectSoundFXGargle8 效果器

編輯:Delphi

 只有使用 IDirectSoundBuffer8 的次緩沖區才能設置"特效", 主緩沖區主要負責的是混音和處理 3D 效果.

  IDirectSoundBuffer8(非 IDirectSoundBuffer) 支持以下效果器:

IDirectSoundFXChorus8      //合唱; 微調原生與回聲的延遲  
IDirectSoundFXCompressor8  //壓縮; 壓縮某些振幅  
IDirectSoundFXDistortion8  //失真; 將波形頂部修改為方形或鋸齒形 
IDirectSoundFXEcho8        //回聲; 重復並衰減回聲 
IDirectSoundFXFlanger8    //鑲邊; 延遲回聲 
IDirectSoundFXGargle8      //漱口; 有人叫它咕嘟效果 
IDirectSoundFXI3DL2Reverb8 //環境回響; 不同房間、大廳的回響效果 
IDirectSoundFXParamEq8    //均衡; 縮放不同頻率的信號 
IDirectSoundFXWavesReverb8 //聲波回響; DirectX Media Objects(DMOs), 是微軟從 Waves 購買的聲音處理技術 

  使用步驟:

  1、通過 IDirectSoundBuffer8 的 SetFX() 方法關聯特效, 這個過程主要是給 SetFX() 方法的參數准備 TDSEffectDesc 結構數組;

  2、通過 IDirectSoundBuffer8 的 GetObjectInPath() 方法獲取特效對象;

  3、通過特效對象的 SetAllParameters() 方法設置特效參數.

  9 個特效對象都只有兩個方法: GetAllParameters()、SetAllParameters(), 兩方法的參數都是結構體(各不相同).

{給 IDirectSoundBuffer8 關聯特效; 不能在緩沖區鎖定或播放時使用:} 
function SetFX( 
  dwEffectsCount: DWord;    //特效數目, 即第二個參數 pDSFXDesc 的大小 
  pDSFXDesc: PDSEffectDesc; //TDSEffectDesc 結構的數組 
  pdwResultCodes: PDWord    //接收設置結果, 不需要則給 nil 
): HResult; stdcall; 
 
//可以使用 SefFX(0, nil, nil) 刪除緩沖區的所有特效. 
 
{SetFX() 方法用到的結構體:} 
TDSEffectDesc = packed record 
  dwSize        : DWord;    //結構大小 
  dwFlags      : DWord;    //處理標志; 一般給 0 
  guidDSFXClass : TGUID;    //指定要使用的效果 
  dwReserved1  : DWord_PTR; //未使用 
  dwReserved2  : DWord_PTR; //未使用 
end; 
 
//DSEffectDesc.dwFlags 
DSFX_LOCHARDWARE = $00000001; //使用硬件處理效果; 這其實在 Direct9.0 還不支持 
DSFX_LOCSOFTWARE = $00000002; //使用軟件處理效果; 同默認 
0                            //默認 
 
//DSEffectDesc.guidDSFXClass, 這分別是上面九個接口對應的 GUID 標識: 
GUID_DSFX_STANDARD_CHORUS 
GUID_DSFX_STANDARD_COMPRESSOR 
GUID_DSFX_STANDARD_DISTORTION 
GUID_DSFX_STANDARD_ECHO 
GUID_DSFX_STANDARD_FLANGER 
GUID_DSFX_STANDARD_GARGLE 
GUID_DSFX_STANDARD_I3DL2REVERB 
GUID_DSFX_STANDARD_PARAMEQ 
GUID_DSFX_WAVES_REVERB 
 
 
{從 IDirectSoundBuffer8 獲取特效對象的方法} 
function GetObjectInPath( 
  const rguidObject: TGUID;    //對象查詢標識, GUID_DSFX_ ... 
  dwIndex: DWord;              //該特效在 SetFX() 安排特效數組時的索引 
  const rguidInterface: TGUID; //對象的唯一標識, IID_IDirectSoundFX ... 或 IDirectSoundFX ... 
  out ppObject                //返回要獲取的特效接口 
): HResult; stdcall; 
 
{IDirectSoundFXGargle8.SetAllParameters() 需要結構體} 
TDSFXGargle = packed record 
  dwRateHz: DWord;    //頻率; 取值范圍 1..1000, 默認 20 
  dwWaveShape: DWord; //波形; 三角波(0)、方波(1) 
end; 
 
//TDSFXGargle.dwRateHz 取值范圍, 默認是 20 
DSFXGARGLE_RATEHZ_MIN    = 1;    // 
DSFXGARGLE_RATEHZ_MAX    = 1000; // 
 
DSFXGARGLE_WAVE_TRIANGLE = 0; //三角波 
DSFXGARGLE_WAVE_SQUARE  = 1; //方波 

 為讓代碼更簡潔, 又把前面自定義的 ReadWave 該為了 ReadWave2 (增加了一個 OpenDialog 方法):

unit ReadWave2; 
 
interface 
 
uses Windows, Classes, SysUtils, MMSystem, Dialogs; 
 
type 
TReadWave = class 
private 
  FFileHandle: HMMIO; 
  FFormat: TWaveFormatEx; 
  FSize: DWord; 
  function GetFormatAndSize(hFile: HMMIO): Boolean; 
public 
  destructor Destroy; override; 
  function Open(FileName: string): Boolean;            //從文件打開 
  function OpenResource(ResName: string): Boolean;    //從資源打開, 資源的指定格式必須是 WAVE 
  function OpenDialog: Boolean;                        //從對話框打開 
  function Read(pDest: Pointer; Size: DWord): Boolean; //讀出波形數據 
  property Format: TWaveFormatEx read FFormat;        //讀出格式數據 
  property Size: DWord read FSize;                    //讀出波形數據的大小 
end; 
 
implementation 
 
{ TReadWave } 
 
destructor TReadWave.Destroy; 
begin 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  inherited; 
end; 
 
function TReadWave.GetFormatAndSize(hFile: HMMIO): Boolean; 
var 
  ckiRIFF,ckiFmt,ckiData: TMMCKInfo; 
begin 
  Result := False; 
  if hFile = 0 then Exit; 
  ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo)); 
  mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF); 
  if (ckiRIFF.ckid <> FOURCC_RIFF) or (ckiRIFF.fccType <> mmiOStringToFOURCC('WAVE',0)) then Exit; 
 
  ZeroMemory(@FFormat, SizeOf(TWaveFormatEx)); 
  ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo)); 
  ckiFmt.ckid := mmiOStringToFOURCC('fmt', 0); 
 
  ZeroMemory(@ckiData, SizeOf(TMMCKInfo)); 
  ckiData.ckid := mmiOStringToFOURCC('data', 0); 
 
  if (mmioDescend(hFile, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then mmioRead(hFile, @FFormat, SizeOf(TWaveFormatEx)); 
  mmioAscend(hFile, @ckiFmt, 0); 
  if (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then FSize := ckiData.cksize; 
 
  Result := FFormat.wFormatTag = WAVE_FORMAT_PCM; 
end; 
 
function TReadWave.Open(FileName: string): Boolean; 
begin 
  Result := False; 
  if not FileExists(FileName) then Exit; 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  FFileHandle := mmioOpen(PChar(FileName), nil, MMIO_READ); 
  Result := GetFormatAndSize(FFileHandle); 
end; 
 
function TReadWave.OpenDialog: Boolean; 
begin 
  with TOpenDialog.Create(nil) do begin 
    Filter := 'Wave File(*.wav)|*.wav'; 
    if Execute then Result := Open(FileName); 
    Free; 
  end; 
end; 
 
function TReadWave.OpenResource(ResName: string): Boolean; 
var 
  res: TResourceStream; 
  mmioInfo: TMMIOInfo; 
begin 
  Result := False; 
  res := TResourceStream.Create(HInstance, ResName, 'WAVE'); 
  ZeroMemory(@mmioInfo, SizeOf(TMMIOInfo)); 
  mmioInfo.fccIOProc := FOURCC_MEM; 
  mmioInfo.cchBuffer := res.Size; 
  mmioInfo.pchBuffer := res.Memory; 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  FFileHandle := mmioOpen(nil, @mmioInfo, MMIO_ALLOCBUF or MMIO_READ); 
  Result := GetFormatAndSize(FFileHandle); 
  res.Free; 
end; 
 
function TReadWave.Read(pDest: Pointer; Size: DWord): Boolean; 
begin 
  Result := mmioRead(FFileHandle, pDest, Size) = Size; 
end; 
 
end. 

 測試代碼:

unit Unit1; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, ExtCtrls, ComCtrls; 
 
type 
  TForm1 = class(TForm) 
    Button1: TButton;        //打開並播放 
    Button2: TButton;        //停止 
    TrackBar1: TTrackBar;    //用於調整 TDSFXGargle.dwRateHz 
    RadioGroup1: TRadioGroup; //用於調整 TDSFXGargle.dwWaveShape 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure TrackBar1Change(Sender: TObject); //RadioGroup1.OnClick 也關聯它 
  end; 
 
var 
  Form1: TForm1; 
 
implementation 
 
{$R *.dfm} 
 
uses DirectSound, ReadWave2; //ReadWave2 是剛剛修改過的自定義單元 
 
var 
  myDSound: IDirectSound8; 
  buf8: IDirectSoundBuffer8; 
  fxGargle: IDirectSoundFXGargle8; //IDirectSoundFXGargle8 效果器 
 
{建立設備對象並初始化界面} 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  DirectSoundCreate8(nil, myDSound, nil); 
  myDSound.SetCoOperativeLevel(Handle, DSSCL_NORMAL); 
 
  TrackBar1.Min := DSFXGARGLE_RATEHZ_MIN; //1 
  TrackBar1.Max := DSFXGARGLE_RATEHZ_MAX; //1000 
  TrackBar1.Position := 20;              //默認值 
  TrackBar1.ShowSelRange := False; 
  TrackBar1.TickStyle := tsNone; 
 
  RadioGroup1.Items.CommaText := 'TRIANGLE, SQUARE'; 
  RadioGroup1.Columns := 2; 
  RadioGroup1.ItemIndex := 0; 
  RadioGroup1.OnClick := TrackBar1.OnChange; //兩個事件的代碼相同 
 
  System.ReportMemoryLeaksOnShutdown := true; 
end; 
 
{建立緩沖區、關聯特效、獲取特效對象並播放} 
procedure TForm1.Button1Click(Sender: TObject); 
var 
  buf: IDirectSoundBuffer; //最終需要的是 IDirectSoundBuffer8, 這裡的 IDirectSoundBuffer 只是做個橋 
  bufDesc: TDSBufferDesc; 
  rEffect: TDSEffectDesc;  //SetFX() 方法需要的結構 
  wav: TReadWave; 
  p1: Pointer; 
  n1: DWord; 
begin 
  {經過對自定義單元的修改, 現在調入一個 Wave 很方便} 
  wav := TReadWave.Create; 
  if not wav.OpenDialog then begin wav.Free; Exit; end; 
 
  {獲取 IDirectSoundBuffer8 接口對象} 
  ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc)); 
  bufDesc.dwSize := SizeOf(TDSBufferDesc); 
  bufDesc.dwFlags := DSBCAPS_CTRLFX; //! 
  bufDesc.dwBufferBytes := wav.Size; 
  bufDesc.lpwfxFormat := @wav.Format; 
  myDSound.CreateSoundBuffer(bufDesc, buf, nil); 
  buf.QueryInterface(IID_IDirectSoundBuffer8, buf8); 
 
  {載入波形} 
  buf8.Lock(0, 0, @p1, @n1, nil, nil, DSBLOCK_ENTIREBUFFER); 
  wav.Read(p1, n1); 
  wav.Free; 
  buf8.Unlock(p1, n1, nil, 0); 
 
  {准備 SetFX() 需要的結構} 
  ZeroMemory(@rEffect, SizeOf(TDSEffectDesc)); 
  rEffect.dwSize := SizeOf(TDSEffectDesc); 
  rEffect.dwFlags := 0; 
  rEffect.guidDSFXClass := GUID_DSFX_STANDARD_GARGLE; //指定是 IDirectSoundFXGargle8 效果器 
 
  {關聯效果器} 
  buf8.SetFX(1, @rEffect, nil); //參數應該是個數組, 既然只有一個元素, 就先省了 
 
  {獲取效果器對象} 
  buf8.GetObjectInPath(GUID_DSFX_STANDARD_GARGLE, 0, IID_IDirectSoundFXGargle8, fxGargle); 
 
  {播放} 
  buf8.Play(0, 0, DSBPLAY_LOOPING); 
 
  //  buf := nil; //局部接口會被自動釋放 
end; 
 
{停止播放} 
procedure TForm1.Button2Click(Sender: TObject); 
begin 
  if Assigned(buf8) then buf8.Stop; 
end; 
 
{特效變換} 
procedure TForm1.TrackBar1Change(Sender: TObject); 
var 
  rGargle: TDSFXGargle; 
begin 
  if buf8 = nil then Exit; 
  rGargle.dwRateHz := TrackBar1.Position; 
  rGargle.dwWaveShape := RadioGroup1.ItemIndex; 
  fxGargle.SetAllParameters(rGargle); 
end; 
 
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  buf8 := nil; 
  myDSound := nil; 
end; 
 
end. 

運行效果圖:

在 Delphi 下使用 DirectSound (9): 效果器初步及 IDirectSoundFXGargle8 效果器

  只有使用 IDirectSoundBuffer8 的次緩沖區才能設置"特效", 主緩沖區主要負責的是混音和處理 3D 效果.

  IDirectSoundBuffer8(非 IDirectSoundBuffer) 支持以下效果器:

IDirectSoundFXChorus8      //合唱; 微調原生與回聲的延遲 
IDirectSoundFXCompressor8  //壓縮; 壓縮某些振幅 
IDirectSoundFXDistortion8  //失真; 將波形頂部修改為方形或鋸齒形 
IDirectSoundFXEcho8        //回聲; 重復並衰減回聲 
IDirectSoundFXFlanger8    //鑲邊; 延遲回聲 
IDirectSoundFXGargle8      //漱口; 有人叫它咕嘟效果 
IDirectSoundFXI3DL2Reverb8 //環境回響; 不同房間、大廳的回響效果 
IDirectSoundFXParamEq8    //均衡; 縮放不同頻率的信號 
IDirectSoundFXWavesReverb8 //聲波回響; DirectX Media Objects(DMOs), 是微軟從 Waves 購買的聲音處理技術 

  使用步驟:

  1、通過 IDirectSoundBuffer8 的 SetFX() 方法關聯特效, 這個過程主要是給 SetFX() 方法的參數准備 TDSEffectDesc 結構數組;

  2、通過 IDirectSoundBuffer8 的 GetObjectInPath() 方法獲取特效對象;

  3、通過特效對象的 SetAllParameters() 方法設置特效參數.

  9 個特效對象都只有兩個方法: GetAllParameters()、SetAllParameters(), 兩方法的參數都是結構體(各不相同).

{給 IDirectSoundBuffer8 關聯特效; 不能在緩沖區鎖定或播放時使用:} 
function SetFX( 
  dwEffectsCount: DWord;    //特效數目, 即第二個參數 pDSFXDesc 的大小 
  pDSFXDesc: PDSEffectDesc; //TDSEffectDesc 結構的數組 
  pdwResultCodes: PDWord    //接收設置結果, 不需要則給 nil 
): HResult; stdcall; 
 
//可以使用 SefFX(0, nil, nil) 刪除緩沖區的所有特效. 
 
{SetFX() 方法用到的結構體:} 
TDSEffectDesc = packed record 
  dwSize        : DWord;    //結構大小 
  dwFlags      : DWord;    //處理標志; 一般給 0 
  guidDSFXClass : TGUID;    //指定要使用的效果 
  dwReserved1  : DWord_PTR; //未使用 
  dwReserved2  : DWord_PTR; //未使用 
end; 
 
//DSEffectDesc.dwFlags 
DSFX_LOCHARDWARE = $00000001; //使用硬件處理效果; 這其實在 Direct9.0 還不支持 
DSFX_LOCSOFTWARE = $00000002; //使用軟件處理效果; 同默認 
0                            //默認 
 
//DSEffectDesc.guidDSFXClass, 這分別是上面九個接口對應的 GUID 標識: 
GUID_DSFX_STANDARD_CHORUS 
GUID_DSFX_STANDARD_COMPRESSOR 
GUID_DSFX_STANDARD_DISTORTION 
GUID_DSFX_STANDARD_ECHO 
GUID_DSFX_STANDARD_FLANGER 
GUID_DSFX_STANDARD_GARGLE 
GUID_DSFX_STANDARD_I3DL2REVERB 
GUID_DSFX_STANDARD_PARAMEQ 
GUID_DSFX_WAVES_REVERB 
 
 
{從 IDirectSoundBuffer8 獲取特效對象的方法} 
function GetObjectInPath( 
  const rguidObject: TGUID;    //對象查詢標識, GUID_DSFX_ ... 
  dwIndex: DWord;              //該特效在 SetFX() 安排特效數組時的索引 
  const rguidInterface: TGUID; //對象的唯一標識, IID_IDirectSoundFX ... 或 IDirectSoundFX ... 
  out ppObject                //返回要獲取的特效接口 
): HResult; stdcall; 
 
{IDirectSoundFXGargle8.SetAllParameters() 需要結構體} 
TDSFXGargle = packed record 
  dwRateHz: DWord;    //頻率; 取值范圍 1..1000, 默認 20 
  dwWaveShape: DWord; //波形; 三角波(0)、方波(1) 
end; 
 
//TDSFXGargle.dwRateHz 取值范圍, 默認是 20 
DSFXGARGLE_RATEHZ_MIN    = 1;    // 
DSFXGARGLE_RATEHZ_MAX    = 1000; // 
 
DSFXGARGLE_WAVE_TRIANGLE = 0; //三角波 
DSFXGARGLE_WAVE_SQUARE  = 1; //方波 

為讓代碼更簡潔, 又把前面自定義的 ReadWave 該為了 ReadWave2 (增加了一個 OpenDialog 方法):

unit ReadWave2; 
 
interface 
 
uses Windows, Classes, SysUtils, MMSystem, Dialogs; 
 
type 
TReadWave = class 
private 
  FFileHandle: HMMIO; 
  FFormat: TWaveFormatEx; 
  FSize: DWord; 
  function GetFormatAndSize(hFile: HMMIO): Boolean; 
public 
  destructor Destroy; override; 
  function Open(FileName: string): Boolean;            //從文件打開 
  function OpenResource(ResName: string): Boolean;    //從資源打開, 資源的指定格式必須是 WAVE 
  function OpenDialog: Boolean;                        //從對話框打開 
  function Read(pDest: Pointer; Size: DWord): Boolean; //讀出波形數據 
  property Format: TWaveFormatEx read FFormat;        //讀出格式數據 
  property Size: DWord read FSize;                    //讀出波形數據的大小 
end; 
 
implementation 
 
{ TReadWave } 
 
destructor TReadWave.Destroy; 
begin 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  inherited; 
end; 
 
function TReadWave.GetFormatAndSize(hFile: HMMIO): Boolean; 
var 
  ckiRIFF,ckiFmt,ckiData: TMMCKInfo; 
begin 
  Result := False; 
  if hFile = 0 then Exit; 
  ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo)); 
  mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF); 
  if (ckiRIFF.ckid <> FOURCC_RIFF) or (ckiRIFF.fccType <> mmiOStringToFOURCC('WAVE',0)) then Exit; 
 
  ZeroMemory(@FFormat, SizeOf(TWaveFormatEx)); 
  ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo)); 
  ckiFmt.ckid := mmiOStringToFOURCC('fmt', 0); 
 
  ZeroMemory(@ckiData, SizeOf(TMMCKInfo)); 
  ckiData.ckid := mmiOStringToFOURCC('data', 0); 
 
  if (mmioDescend(hFile, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then mmioRead(hFile, @FFormat, SizeOf(TWaveFormatEx)); 
  mmioAscend(hFile, @ckiFmt, 0); 
  if (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then FSize := ckiData.cksize; 
 
  Result := FFormat.wFormatTag = WAVE_FORMAT_PCM; 
end; 
 
function TReadWave.Open(FileName: string): Boolean; 
begin 
  Result := False; 
  if not FileExists(FileName) then Exit; 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  FFileHandle := mmioOpen(PChar(FileName), nil, MMIO_READ); 
  Result := GetFormatAndSize(FFileHandle); 
end; 
 
function TReadWave.OpenDialog: Boolean; 
begin 
  with TOpenDialog.Create(nil) do begin 
    Filter := 'Wave File(*.wav)|*.wav'; 
    if Execute then Result := Open(FileName); 
    Free; 
  end; 
end; 
 
function TReadWave.OpenResource(ResName: string): Boolean; 
var 
  res: TResourceStream; 
  mmioInfo: TMMIOInfo; 
begin 
  Result := False; 
  res := TResourceStream.Create(HInstance, ResName, 'WAVE'); 
  ZeroMemory(@mmioInfo, SizeOf(TMMIOInfo)); 
  mmioInfo.fccIOProc := FOURCC_MEM; 
  mmioInfo.cchBuffer := res.Size; 
  mmioInfo.pchBuffer := res.Memory; 
  if FFileHandle > 0 then mmioClose(FFileHandle, 0); 
  FFileHandle := mmioOpen(nil, @mmioInfo, MMIO_ALLOCBUF or MMIO_READ); 
  Result := GetFormatAndSize(FFileHandle); 
  res.Free; 
end; 
 
function TReadWave.Read(pDest: Pointer; Size: DWord): Boolean; 
begin 
  Result := mmioRead(FFileHandle, pDest, Size) = Size; 
end; 
 
end. 

測試代碼:

unit Unit1; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, ExtCtrls, ComCtrls; 
 
type 
  TForm1 = class(TForm) 
    Button1: TButton;        //打開並播放 
    Button2: TButton;        //停止 
    TrackBar1: TTrackBar;    //用於調整 TDSFXGargle.dwRateHz 
    RadioGroup1: TRadioGroup; //用於調整 TDSFXGargle.dwWaveShape 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure TrackBar1Change(Sender: TObject); //RadioGroup1.OnClick 也關聯它 
  end; 
 
var 
  Form1: TForm1; 
 
implementation 
 
{$R *.dfm} 
 
uses DirectSound, ReadWave2; //ReadWave2 是剛剛修改過的自定義單元 
 
var 
  myDSound: IDirectSound8; 
  buf8: IDirectSoundBuffer8; 
  fxGargle: IDirectSoundFXGargle8; //IDirectSoundFXGargle8 效果器 
 
{建立設備對象並初始化界面} 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  DirectSoundCreate8(nil, myDSound, nil); 
  myDSound.SetCoOperativeLevel(Handle, DSSCL_NORMAL); 
 
  TrackBar1.Min := DSFXGARGLE_RATEHZ_MIN; //1 
  TrackBar1.Max := DSFXGARGLE_RATEHZ_MAX; //1000 
  TrackBar1.Position := 20;              //默認值 
  TrackBar1.ShowSelRange := False; 
  TrackBar1.TickStyle := tsNone; 
 
  RadioGroup1.Items.CommaText := 'TRIANGLE, SQUARE'; 
  RadioGroup1.Columns := 2; 
  RadioGroup1.ItemIndex := 0; 
  RadioGroup1.OnClick := TrackBar1.OnChange; //兩個事件的代碼相同 
 
  System.ReportMemoryLeaksOnShutdown := true; 
end; 
 
{建立緩沖區、關聯特效、獲取特效對象並播放} 
procedure TForm1.Button1Click(Sender: TObject); 
var 
  buf: IDirectSoundBuffer; //最終需要的是 IDirectSoundBuffer8, 這裡的 IDirectSoundBuffer 只是做個橋 
  bufDesc: TDSBufferDesc; 
  rEffect: TDSEffectDesc;  //SetFX() 方法需要的結構 
  wav: TReadWave; 
  p1: Pointer; 
  n1: DWord; 
begin 
  {經過對自定義單元的修改, 現在調入一個 Wave 很方便} 
  wav := TReadWave.Create; 
  if not wav.OpenDialog then begin wav.Free; Exit; end; 
 
  {獲取 IDirectSoundBuffer8 接口對象} 
  ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc)); 
  bufDesc.dwSize := SizeOf(TDSBufferDesc); 
  bufDesc.dwFlags := DSBCAPS_CTRLFX; //! 
  bufDesc.dwBufferBytes := wav.Size; 
  bufDesc.lpwfxFormat := @wav.Format; 
  myDSound.CreateSoundBuffer(bufDesc, buf, nil); 
  buf.QueryInterface(IID_IDirectSoundBuffer8, buf8); 
 
  {載入波形} 
  buf8.Lock(0, 0, @p1, @n1, nil, nil, DSBLOCK_ENTIREBUFFER); 
  wav.Read(p1, n1); 
  wav.Free; 
  buf8.Unlock(p1, n1, nil, 0); 
 
  {准備 SetFX() 需要的結構} 
  ZeroMemory(@rEffect, SizeOf(TDSEffectDesc)); 
  rEffect.dwSize := SizeOf(TDSEffectDesc); 
  rEffect.dwFlags := 0; 
  rEffect.guidDSFXClass := GUID_DSFX_STANDARD_GARGLE; //指定是 IDirectSoundFXGargle8 效果器 
 
  {關聯效果器} 
  buf8.SetFX(1, @rEffect, nil); //參數應該是個數組, 既然只有一個元素, 就先省了 
 
  {獲取效果器對象} 
  buf8.GetObjectInPath(GUID_DSFX_STANDARD_GARGLE, 0, IID_IDirectSoundFXGargle8, fxGargle); 
 
  {播放} 
  buf8.Play(0, 0, DSBPLAY_LOOPING); 
 
  //  buf := nil; //局部接口會被自動釋放 
end; 
 
{停止播放} 
procedure TForm1.Button2Click(Sender: TObject); 
begin 
  if Assigned(buf8) then buf8.Stop; 
end; 
 
{特效變換} 
procedure TForm1.TrackBar1Change(Sender: TObject); 
var 
  rGargle: TDSFXGargle; 
begin 
  if buf8 = nil then Exit; 
  rGargle.dwRateHz := TrackBar1.Position; 
  rGargle.dwWaveShape := RadioGroup1.ItemIndex; 
  fxGargle.SetAllParameters(rGargle); 
end; 
 
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  buf8 := nil; 
  myDSound := nil; 
end; 
 
end. 

  運行效果圖:

在 Delphi 下使用 DirectSound (9): 效果器初步及 IDirectSoundFXGargle8 效果器







  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved