首先要修改前面自定义的 ReadWaveFile 单元, 给它增加一个 OpenResource() 方法以直接读取资源文件中的 "WAVE" 数据;
为避免混淆, 把单元名 ReadWaveFile 同时改为 ReadWave; 类名 TReadWaveFile 改为 TReadWave.
{修改后的 ReadWave 单元: 从文件或资源读取 Wave 的格式、数据与数据尺寸} unit ReadWave; interface uses Windows, Classes, SysUtils, MMSystem; 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; 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.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.
下面的例子如图载入了三个 Wave 文件到资源:
本例可充分体现 DirectSound 可同时播放多个声音的特点; 实现代码:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; //播放第一个资源 Button2: TButton; //播放第二个资源 Button3: TButton; //播放第三个资源 Button4: TButton; //全部停止 CheckBox1: TCheckBox; //控制是否循环播放 procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses DirectSound, MMSystem, ReadWave; //ReadWave 是上面重新定义的单元 var myDSound: IDirectSound8; bufs: array[0..2] of IDirectSoundBuffer; //缓冲区数组, 用于装载资源文件中的三个 WAVE 文件 {使用资源文件建立缓冲区并播放} procedure PlayResourceWave(ResName: string; var buf: IDirectSoundBuffer; loop: Boolean=false); var bufDesc: TDSBufferDesc; wav: TReadWave; p1: Pointer; n1: DWORD; begin buf := nil; wav := TReadWave.Create; if not wav.OpenResource(ResName) then begin ShowMessage('打开失败'); wav.Free; Exit; end; ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc)); bufDesc.dwSize := SizeOf(TDSBufferDesc); bufDesc.dwFlags := DSBCAPS_STATIC; bufDesc.dwBufferBytes := wav.Size; bufDesc.lpwfxFormat := @wav.Format; myDSound.CreateSoundBuffer(bufDesc, buf, nil); buf.Lock(0, 0, @p1, @n1, nil, nil, DSBLOCK_ENTIREBUFFER); wav.Read(p1, n1); buf.Unlock(p1, n1, nil, 0); if loop then buf.Play(0, 0, DSBPLAY_LOOPING) else buf.Play(0, 0, 0); wav.Free; end; {初始化设备} procedure TForm1.FormCreate(Sender: TObject); begin DirectSoundCreate8(nil, myDSound, nil); myDSound.SetCooperativeLevel(Handle, DSSCL_NORMAL); end; {播放第一个资源} procedure TForm1.Button1Click(Sender: TObject); begin PlayResourceWave('wav_1', bufs[0], CheckBox1.Checked); end; {播放第二个资源} procedure TForm1.Button2Click(Sender: TObject); begin PlayResourceWave('wav_2', bufs[1], CheckBox1.Checked); end; {播放第三个资源} procedure TForm1.Button3Click(Sender: TObject); begin PlayResourceWave('wav_3', bufs[2], CheckBox1.Checked); end; {全部停止} procedure TForm1.Button4Click(Sender: TObject); var i: Integer; begin for i := Low(bufs) to High(bufs) do if bufs[i] <> nil then bufs[i].Stop; end; procedure TForm1.FormDestroy(Sender: TObject); var i: Integer; begin for i := Low(bufs) to High(bufs) do bufs[i] := nil; myDSound := nil; end; end.
本节演示录像: https://files.cnblogs.com/del/DirectSound_7.rar