只有使用 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.
運行效果圖:
只有使用 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.
運行效果圖: