文档章节

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

涂孟超
 涂孟超
发布于 2014/09/26 15:37
字数 799
阅读 4
收藏 0

首先要修改前面自定义的 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

本文转载自:http://www.cnblogs.com/del/archive/2011/01/19/1939429.html

共有 人打赏支持
涂孟超
粉丝 12
博文 2011
码字总数 14107
作品 0
深圳
程序员
私信 提问
delphi资源文件制作及使用详解

delphi资源文件制作及使用详解 摘自:http://www.ej38.com/showinfo/delphi-131567.html 一、引子: 现在的Windows应用程序几乎都使用图标、图片、光标、声音等,我们称它们为资源(Resourc...

vga
2015/03/03
0
0
DirectSound入门

文档内容: (费话篇) 关于DirectSound DirectSound是DirectX API的音频(waveaudio)组件之一,它可以提供快速的混音、硬件加速功能,并且可以直接访问相关设备,当然,最主要的是它提供的...

长平狐
2012/08/13
901
0
Windows上的音频采集技术(转)

转自:http://shanewfx.github.io/blog/2013/08/14/caprure-audio-on-windows/前一段时间接到一个任务,需要采集到声卡的输出信号,以便与麦克风的输入信号进行混音。 之前一直没有研究过音频...

元谷
2013/12/05
0
0
DirectSound学习(二)--流式缓冲区

使用流式缓冲方式播放波形音频文件比较复杂,主要原因是在只有一个缓冲区提供给用户的前提下,这个缓冲区在提供给声卡播放数据的同是还需要用户不断的定时向其中写入数据。要注意从缓冲区这时...

imxiangzi
02/11
0
0
进阶音效控制与管理(转载)

摘要 以 XNA 为基础的游戏程序可以利用 SoundEffect 类别的功能执行简单的音效播放,或是利用 SoundEffectInstance 类别进行进阶的音效播放控制,包括播放、暂停、恢复、结束、是否要播放 3D...

junwong
2012/02/17
494
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud 分布式链路跟踪 Sleuth + Zipkin + Elasticsearch

随着业务越来越复杂,系统也随之进行各种拆分,特别是随着微服务架构的兴起,看似一个简单的应用,后台可能很多服务在支撑;一个请求可能需要多个服务的调用;当请求迟缓或不可用时,无法得知...

编程SHA
15分钟前
1
0
Swift-清除缓存

func removeCache (){ // 取出cache文件夹路径.如果清除其他位子的可以将cachesDirectory换成对应的文件夹 let cachePath = NSSearchPathForDirectoriesInDomains(FileMan...

west_zll
15分钟前
1
0
kl键盘事件

frameworks/base/data/keyboards路径下定义了很对kl文件。如Vendor_0416_Product_0300.kl,定义了某某遥控器的按键事件 # TVkey 103 DPAD_UPkey 108 DPAD_DOWNkey 105 DPAD_LEFTk...

安卓工程师王恒
19分钟前
1
0
CentOS 7 安装 Docker

工具: Oracle VM VirtualBox 虚拟机 ,本地电脑win10 系统: 虚拟机装 centos 7 前置条件: Docker 要求 CentOS 系统的内核版本高于 3.10 1. 通过 uname -r 命令查看当前的内核版本 2. 如果不够...

_大侠__
29分钟前
1
0
webrtc onAddStream回调流程

背景 webrtc代码基于M59 正文 1. 回调设置和处理 (1)java层先在监听器中实现回调处理函数,如下所示: private class PCObserver implements PeerConnection.Observer { @Override...

bill_shen
31分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部