只有使用 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 recorddwSize        : DWORD;     //结构大小dwFlags       : DWORD;     //处理标志; 一般给 0guidDSFXClass : 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 recorddwRateHz: DWORD;    //频率; 取值范围 1..1000, 默认 20dwWaveShape: 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;interfaceuses Windows, Classes, SysUtils, MMSystem, Dialogs;type
TReadWave = class
privateFFileHandle: HMMIO;FFormat: TWaveFormatEx;FSize: DWORD;function GetFormatAndSize(hFile: HMMIO): Boolean;
publicdestructor Destroy; override;function Open(FileName: string): Boolean;            //从文件打开function OpenResource(ResName: string): Boolean;     //从资源打开, 资源的指定格式必须是 WAVEfunction 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;
beginif FFileHandle > 0 then mmioClose(FFileHandle, 0);inherited;
end;function TReadWave.GetFormatAndSize(hFile: HMMIO): Boolean;
varckiRIFF,ckiFmt,ckiData: TMMCKInfo;
beginResult := 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;
beginResult := 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;
beginwith TOpenDialog.Create(nil) do beginFilter := 'Wave File(*.wav)|*.wav';if Execute then Result := Open(FileName);Free;end;
end;function TReadWave.OpenResource(ResName: string): Boolean;
varres: TResourceStream;mmioInfo: TMMIOInfo;
beginResult := 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;
beginResult := mmioRead(FFileHandle, pDest, Size) = Size;
end;end.


测试代码:


unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls, ComCtrls;typeTForm1 = class(TForm)Button1: TButton;         //打开并播放Button2: TButton;         //停止TrackBar1: TTrackBar;     //用于调整 TDSFXGargle.dwRateHzRadioGroup1: TRadioGroup; //用于调整 TDSFXGargle.dwWaveShapeprocedure FormCreate(Sender: TObject);procedure FormDestroy(Sender: TObject);procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);procedure TrackBar1Change(Sender: TObject); //RadioGroup1.OnClick 也关联它end;varForm1: TForm1;implementation{$R *.dfm}uses DirectSound, ReadWave2; //ReadWave2 是刚刚修改过的自定义单元varmyDSound: IDirectSound8;buf8: IDirectSoundBuffer8;fxGargle: IDirectSoundFXGargle8; //IDirectSoundFXGargle8 效果器{建立设备对象并初始化界面}
procedure TForm1.FormCreate(Sender: TObject);
beginDirectSoundCreate8(nil, myDSound, nil);myDSound.SetCooperativeLevel(Handle, DSSCL_NORMAL);TrackBar1.Min := DSFXGARGLE_RATEHZ_MIN; //1TrackBar1.Max := DSFXGARGLE_RATEHZ_MAX; //1000TrackBar1.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);
varbuf: 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);
beginif Assigned(buf8) then buf8.Stop;
end;{特效变换}
procedure TForm1.TrackBar1Change(Sender: TObject);
varrGargle: TDSFXGargle;
beginif buf8 = nil then Exit;rGargle.dwRateHz := TrackBar1.Position;rGargle.dwWaveShape := RadioGroup1.ItemIndex;fxGargle.SetAllParameters(rGargle);
end;procedure TForm1.FormDestroy(Sender: TObject);
beginbuf8 := nil;myDSound := nil;
end;end.


运行效果图:


转载于:https://www.cnblogs.com/del/archive/2011/01/21/1941193.html

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

  1. 在 Delphi 下使用 DirectSound (12): 测试失真效果器 IDirectSoundFXDistortion8

    为什么80%的码农都做不了架构师?>>>    {相关结构:} TDSFXDistortion = packed recordfGain: Sinle; //-60 .. 0 : - ...

  2. 在 Delphi 下使用 DirectSound (14): 测试镶边效果器 IDirectSoundFXFlanger8

    {相关结构:} TDSFXFlanger = packed recordfWetDryMix: Single; // 0 .. 100 : 50 (%)fDepth: Single; // 0 .. ...

  3. 在 Delphi 下使用 DirectSound (5): 获取或设置缓冲区的格式:

    次缓冲区(或叫辅助缓冲区)尽管使用了波形文件自己的 TWaveFormatEx, 但最终播放的却只是 22050HZ 的 8 位立体声. 因为次缓冲区最终要混入主缓冲区才播放, 可主缓冲区的缺省格式是 ...

  4. 在 Delphi 下使用 DirectSound (4): 设置音量、相位、播放频率和播放位置

    通过 IDirectSoundBuffer 的 SetVolume.SetPan.SetFrequency.SetCurrentPosition 方法可以简单进行这些设置. 同时 IDirectSou ...

  5. 在 Delphi 下使用 DirectSound (6): 按文件自己的格式(TWaveFormatEx)播放

    这必须手动建立主缓冲区. unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Contr ...

  6. 在 Delphi 下使用 DirectSound (2): 查看设备性能

    使用 DirectSound 前应先建立 IDirectSound8 对象(之前的版本是 IDirectSound): function DirectSoundCreate8(pcGuidDevice ...

  7. Delphi下的COM编程

    Delphi通过向导可以非常迅速和方便的直接建立实现COM对象的代码,但是整个COM实现的过程被完全的封装,甚至没有VCL那么结构清晰可见. 一个没有C++下COM开发经验甚至没有接触过COM开发的D ...

  8. Delphi下利用WinIo模拟鼠标键盘详解

    本文最早在编程论坛上发表,文章地址:http://programbbs.com/bbs/view12-17207-1.htm,相关文件可以在上述地址的页面中下载.转载时请注明出处. 前言 一日发现Se ...

  9. 李伯虎院士:新一代人工智能引领下的智造制造初步实践

    来源:电能革命 由中国智能制造百人会主办的"2018智造百强榜高峰会暨2019中国智能制造百人会年会上"于2019年1月11日在北京科技会堂举行.中国工程院院士/国家制造强国战略咨 ...

最新文章

  1. JavaScript--正则
  2. 如何用纯 CSS 创作一只愤怒小鸟中的黑炮
  3. 使用sed和awk取除最后两个字段之外的字段
  4. HTTP1.0,HTTP1.1,HTTPS和HTTP2.0的区别
  5. 【视频】vue组件的局部注册
  6. 只有想不到,「99」种扩展Jupyter功能的好方法
  7. 数据湖,大数据的下一个变革!
  8. 对jvm 同步锁的理解
  9. pixel和毫米怎么换算_压力传感器相关压力单位换算
  10. 扫目录过狗过waf方法
  11. IT运维管理为重,从业务需求看网管系统的选择
  12. data-index在react里怎样表达_对牛弹琴,在英语里该怎样地道表达?
  13. mysql宠物销售系统论文,宠物店管理系统的设计与实现.doc
  14. 单语种语料库 平行语料库 多语种语料库 可比语料库
  15. 变速精灵试用 目前唯一支持Vista加速
  16. 【资源分享】Dll Injector(DLL注入器)
  17. 世界上最简单的会计书(先进先出法VS后进先出法)
  18. 【物理应用】大气辐射和透射率模型及太阳和月亮模型(Matlab代码实现)
  19. 塑料周转箱提高贮存效率
  20. win11怎么关闭自动更新系统

热门文章

  1. linux环境下获取真实的ip地址
  2. Maven 的 settings.xml 配置中的mirror节点
  3. 使用links方式安装eclipse插件
  4. MxGraph从入门到精通之4:布局
  5. linux内核网络协议栈--发送流程及函数(十)
  6. javascript写各种排序算法
  7. Windows配置Oracle Instant Client
  8. 【智驾深谈】自动驾驶潜在突破点:传感器与车载集成系统(万字干货)
  9. Web 探索之旅 | 第二部分第一课:客户端语言
  10. Hdu 1312 Red and Black