DirectSound只支持Wav格式的音频文件,在创建次缓冲区之前需要先确定播放的Wav音频数据的格式。如果是从本地Wav文件播放,则需要先读出它的数据格式。

1. Wav音频格式布局

Wav是WAVE音频格式文件的后缀名,WAVE音频格式全称是Waveform Audio File Format,又叫波形文件。这是一种微软和IBM合理推出的音频比特流文件格式,是RIFF(Resource Interchange File Format)文件格式的一种特殊应用。

RIFF使用一种叫做Chunk的数据块来存储各种信息,主要分为两部分:RIFF ChunkOther Chunk

RIFF Chunk:

  • Chunk id: chunk标识符,值为FOURCC('R', 'I', 'F', 'F')组成的一个32位的无符号整数。
  • file size: 4字节大小,file typedata部分的数据大小总和。
  • file type: 用FOURCC标识的文件类型,对于Wav文件来说值为FOURCC('W', 'A', 'V', 'E')。
  • data: 该部分包含剩余的chunk块。

Other Chunk按顺序包含3个部分:

  • Chunk id:这是每个chunk的标识符,是由4个字符组成一个FOURCC。
  • Chunk size:4字节值,表明该chunk块数据部分的大小。
  • Chunk data:数据部分,该数据可能为空,并且实际的数据会被填充到2字节边界

对于Wav音频文件来说,常见并被称为标准格式的Wav格式的只包含“RIFF”、“fmt”和“data” chunk 块(今天我们不讨论格式标准,因此不深入探讨这方面),只有“data”子块中的data部分包含实际的音频数据,可以被用来播放。实际上整个RIFF文件只由一个“RIFF”块组成,而该“RIFF”又包含其他子块(例如“fmt”、“data”块)。由于Wav文件可能包含其他子块,因此在解析的时候不能假定这些字块的顺序。

2.Wav音频数据格式

Wav音频的数据格式信息包含在“fmt”块中,“fmt”字块的data部分就包含数据的格式信息。Wav文件多包含的是PCM( Pulse -code modulation)原始音频数据,即未经压缩的数据,但其实它可以包含多种数据格式,包括原始的和经过压缩的:

  • PCM

  • ADPCM

  • GSM

  • MP3

  • CELP

  • SBC

  • Truespeech

我们这里只处理PCM原始数据,因为DirectSound只支持它。我们看下图:

在Windows平台上开发时,系统已经为我们定义好了数据格式用来存储Wav格式信息WAVEFORMATEX,可以看到这个结构体的字段除cbSize以外都是按顺序和“fmt”块中data部分的格式信息字段一一对应的,这极大地方便了我们对格式信息的处理。

3. 读取Wav音频格式信息

HMMIO mmioOpen(LPTSTR szFilename, LPMMIOINFO lpmmioinfo, DWORD dwOpenFlags);

MMRESULT mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT wFlags);

MMRESULT mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, LPMMCKINFO lpckParent, UINT wFlags);

LONG mmioRead(HMMIO hmmio, HPSTR pch, LONG cch);

...

微软提供了mmio系列的函数来帮助我们操作RIFF文件,首先我们调用mmioOpen打开一个Wav文件并防止被其他程序写入:

HMMIO mmioHandle = mmioOpenW(tempFilePath, NULL,
MMIO_READ |
MMIO_DENYWRITE |
MMIO_ALLOCBUF);
if (mmioHandle == NULL) {
throw std::exception("mmioOpon error!");
}

然后我们调用mmioDescend函数下降到RIFF块,通过在MMCKINFO结构体中设置file type为FOURCC('W', 'A', 'V', 'E'),我们表明我们想下降到的RIFF块里的文件类型是“WAVE”:

MMCKINFO riffChunkInfo;
riffChunkInfo.fccType = mmioFOURCC('W', 'A', 'V', 'E');
DWORD as;
if ((as = mmioDescend(mmioHandle, &riffChunkInfo, NULL, MMIO_FINDRIFF))
!=
MMSYSERR_NOERROR) { throw std::exception("mmioDescend error!");
}

因为“fmt”块是RIFF的子块,因此我们紧接着下降到“fmt”子块:

MMCKINFO fmtSubChunkInfo;
fmtSubChunkInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(mmioHandle, &fmtSubChunkInfo, &riffChunkInfo, MMIO_FINDCHUNK)
!=
MMSYSERR_NOERROR) { throw std::exception("mmioDescend error!");
}

然后我们调用mmioRead函数来读取格式信息到一个WAVEFORMATEX结构体中。调用mmioRead时,我们需要自己提供存放读取信息的地址,像这里我们提供的是一个栈上的变量地址:

//  `fmt` chunk contains wave audio format described by WAVEFORMAT or WAVEFORMATEX
if (mmioRead(mmioHandle, (HPSTR)&m_waveFormat, fmtSubChunkInfo.cksize)
<= 0) { throw std::exception("mmioRead read fmt chunk error!");
}

4. 运行结果

完整代码见链接

MMIO----Wav格式文件解析的更多相关文章

  1. WAV格式文件无损合并&帧头数据体解析(python)(原创)

    一,百度百科 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频 ...

  2. 将PCM格式存储成WAV格式文件

    将PCM格式存储成WAV格式文件 WAV比PCM多44个字节(在文件头位置多) 摘自:https://blog.csdn.net/u012173922/article/details/78849076 ...

  3. Android音频: 怎样使用AudioTrack播放一个WAV格式文件?

    翻译 By Long Luo 原文链接:Android Audio: Play a WAV file on an AudioTrack 译者注: 1. 因为这是技术文章,所以有些词句使用原文,表达更准 ...

  4. wav格式文件、pcm数据

    wav格式文件是常见的录音文件,是声音波形文件格式之一,wav 文件由文件头和数据体两部分组成. 文件头是我们在做录音保存到文件的时候,要存储的文件的说明信息,播放器要通过文件头的相关信息去读取数据播 ...

  5. Dicom格式文件解析器[转]

    Dicom格式文件解析器   Dicom全称是医学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题 只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的 无非就是字节码数据流处理.只不 ...

  6. Dicom格式文件解析器

    转自:http://www.cnblogs.com/assassinx/archive/2013/01/09/dicomViewer.html Dicom全称是医学数字图像与通讯,这里讲的暂不涉及通讯 ...

  7. 音频文件解析(一):WAV格式文件头部解析

    WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 文 ...

  8. [VB.NET][C#]WAV格式文件头部解析

    简介 WAV 为微软开发的一种声音文件格式,它符合 RIFF(Resource Interchange File Format)文件规范,用于保存 Windows 平台的音频信息资源. 第一节 文件头 ...

  9. 音频文件解析(二):WAV格式文件波形绘制

    解析WAV头部信息后,接下来就可以根据相关参数和DATA块数据绘制波形. 1.重新编码(转换为8bits,单声道数据) Public Function GetFormatData(ByVal pDat ...

随机推荐

  1. 小程序获取view元素的高度

    页面wxml <!--page/index/index.wxml--> <view id='demo'> <text>哈哈哈哈哈</text> < ...

  2. [转]SQL Server 2008 如何配置报表管理器

    本文转自:https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/cc281384%28v%3dsql.100%2 ...

  3. AngularJS学习笔记(三)数据双向绑定

    双向绑定 双向绑定是AngularJS最实用的功能,它节省了大量的代码,使我们专注于数据和视图,不用浪费大量的代码在Dom监听.数据同步上,关于双向更新,可看下图: 下面,我们通过代码来实现.先不要纠 ...

  4. JavaScript学习总结(二)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

    一.AJAX示例 AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术.改善用户体验,实现无刷新效 ...

  5. thinkphp 百度编辑器和layer简单用法

    百度编辑器1.4.3.3和layer插件简单案例 :后台单页面管理 增删改查操作 此处为默认图片保存路径,如果要修改保存路径,需要修改config文件. 添加页. <extend name=&q ...

  6. Number Sequence(hdu4390)

    Number Sequence Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot ...

  7. ActiveMQ demo

    Maven 配置文件 <dependency> <groupId>org.apache.activemq</groupId> <artifactId>a ...

  8. Navicat11全系列激活工具和使用方法

    Navicat特别好使,但是就是得注册,在网上看到了一个激活工具,成功激活了Navicat...工具链接地址是.. https://files.cnblogs.com/files/miantiaoan ...

  9. 【读书笔记】iOS-网络-HTTP-URL百分号编码

    代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, ty ...

  10. Hystrix 框架

    雪崩效应的产生原因:当一个服务突然受到高并发的请求,tomcat服务器承受不了的情况下会产生服务堆积,可能导致其他的服务也不可用. 服务保护:当服务产生堆积的时候,对服务实现保护功能. 服务隔离:每个 ...