首先要修改前面自定义的 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.
本节演示录像: http://files.cnblogs.com/del/DirectSound_7.rar