在 Delphi 下使用 DirectSound (7): 播放资源文件中的 Wave 数据


首先要修改前面自定义的 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 文件到资源:

在 Delphi 下使用 DirectSound (7): 播放资源文件中的 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

你可能感兴趣的:(Delphi)