文档章节

在 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
Windows上的音频采集技术(转)

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

元谷
2013/12/05
0
0
DirectSound入门

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

长平狐
2012/08/13
824
0
OPenAL 3D音效开发

介绍: 这几年,随着声卡能力的提升与处理声音API的丰富,3D音效在游戏中扮演着愈演愈烈角色。在游戏中制造一个模拟真实的音响效果与精美的游戏画面同等重要。环境音与音乐可以让玩家感受游戏...

长平狐
2012/08/13
1K
0
一个vc++ direct sound播放wav文件的类

头文件 #if !defined(AFXDIRECTSOUNDHA20FE86F118F11D29AB30060B0CDC13EINCLUDED) #define AFXDIRECTSOUNDHA20FE86F118F11D29AB30060B0CDC13EINCLUDED #if MSCVER >= 1000 #pragma once #end......

junwong
2012/03/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java并发备忘

不安全的“先检查后执行”,代码形式如下: if(条件满足){ //这里容易出现线程安全问题//doSomething}else{//doOther} 读取-修改-写入 原子操作:使用CAS技术,即首先从V中读取...

Funcy1122
今天
0
0
SpringBoot2.0 停机

最近新建了个SpringBoot2.0的项目,因为原来一直使用的是传统的Tomcat部署war包的形式,所以这次SpringBoot内置Tomcat部署jar包的时候遇到了很多问题。其中一个就是因为没有外置的Tomcat容器...

Canaan_
昨天
0
1
Confluence 6 外部参考

一个外部参考的意思是任何站点链接到你 Confluence 的实例。任何时候当 Confluence 的用户单击这个外部链接的时候,Confluence 可以记录这次单击为参考。 在默认的情况下,外部链接的参考链接...

honeymose
昨天
0
0
Android中的设计模式之抽象工厂模式

参考 《设计模式解析》 第十一章 Abstract Factory模式 《设计模式:可复用面向对象软件的基础 》3.1 Abstract Factory 抽象工厂 对象创建型模式 《Android源码设计模式解析与实战》第6章 创...

newtrek
昨天
0
0
Redis | 地理空间(GEO)的一个坑

Redis的地理空间(Geo)是个好东西,轻轻松松的就可以把地图描点的问题处理了, 最近却遇到一个坑...Redis采用的Msater-Slave模式, 运用GEORADIUS在salve读取对应的数据,新增了从节点但是从不返...

云迹
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部