• 在 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 文件到资源:



    本例可充分体现 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
  • 相关阅读:
    IE 创建条件样式
    Weinre
    three.js 之 透明物体不能正常显示
    用shader实现流动的水面(webgl)
    用js的方式运行c程序之webassemly
    three.js效果之热力图和轨迹线
    three.js后期之自定义shader通道实现扫光效果
    《计算机网络》物理层
    《计算机网络》概述
    pixi小游戏开发(vue+typescript)
  • 原文地址:https://www.cnblogs.com/del/p/1939429.html
Copyright © 2020-2023  润新知