WAV文件格式解析

2023-11-12

来源:

http://www.codeguru.com/cpp/g-m/multimedia/audio/article.php/c8935/PCM-Audio-and-Wave-Files.htm#page-1

源程序下载地址:

http://www.codeguru.com/dbfiles/get_file/WaveFun_Src.zip?id=8935&lbl=WAVEFUN_SRC_ZIP

http://www.codeguru.com/dbfiles/get_file/WaveFun_Bin.zip?id=8935&lbl=WAVEFUN_BIN_ZIP


WAVE文件支持很多不同的比特率、采样率、多声道音频。WAVE是PC机上存储PCM音频最流行的文件格式,基本上可以等同于原始数字音频。

WAVE文件为了与IFF保持一致,数据采用“chunk”来存储。因此,如果想要在WAVE文件中补充一些新的信息,只需要在在新chunk中添加信息,而不需要改变整个文件。这也是设计IFF最初的目的。

WAVE文件是很多不同的chunk集合,但是对于一个基本的WAVE文件而言,以下三种chunk是必不可少的。


使用WAVE文件的应用程序必须具有读取以上三种chunk信息的能力,如果程序想要复制WAVE文件,必须拷贝文件中所有的chunk。

文件中第一个chunkRIFFchunk,然后是fmtchunk,最后是datachunk。对于其他的chunk,顺序没有严格的限制。

以下是一个最基本的WAVE文件,包含三种必要chunk


文件组织形式:

1. 文件头

RIFF/WAV文件标识段

 声音数据格式说明段

2. 数据体:

由 PCM(脉冲编码调制)格式表示的样本组成。



描述WAVE文件的基本单元是“sample”,一个sample代表采样一次得到的数据。因此如果用44KHz采样,将在一秒中得到44000sample。每个sample可以用8位、24位,甚至32位表示(位数没有限制,只要是8的整数倍即可),位数越高,音频质量越好。

此处有一个值得注意的细节,8位代表无符号的数值,而16位或16位以上代表有符号的数值。

例如,如果有一个10bit的样本,由于sample位数要求是8的倍数,我们就需要把它填充到16位。16位中:0-5位补0,6-15位是原始的10bit数据。这就是左补零对齐原则。

上述只是单声道,如果要处理多声道,就需要在任意给定时刻给出多个sameple。例如,在多声道中,给出某一时刻,我们需要分辨出哪些sample是左声道的,哪些sample是右声道的。因此,我们需要一次读写两个sample.

假如以44KHz取样立体声音频,我们需要一秒读写44*2 KHz的sample. 给出公式:

每秒数据大小(字节)=采样率 * 声道数 * sample比特数 / 8

处理多声道音频时,每个声道的样本是交叉存储的。我们把左右声道数据交叉存储在一起:先存储第一个sample的左声道数据,然后存储第一个sample的右声道数据。

当一个设备需要重现声音时,它需要同时处理多个声道,一个sample中多个声道信息称为一个样本帧。

下面将介绍如何使用C++处理WAVE文件。

RIFF头chunk表示如下:

1.	struct RIFF_HEADER
2.	{
3.	   TCHAR szRiffID[4];        // 'R','I','F','F'
4.	      DWORD dwRiffSize;
5.	 
6.	   TCHAR szRiffFormat[4];    // 'W','A','V','E'
7.	};

第二个块是fmt chunk,它用来描述WAVE文件的特性,例如比特率、声道数。可以使用结构体来描述fmt chunk.

1.	struct WAVE_FORMAT
2.	{
3.	   WORD wFormatTag;
4.	   WORD wChannels;
5.	   DWORD dwSamplesPerSec;
6.	   DWORD dwAvgBytesPerSec;
7.	   WORD wBlockAlign;
8.	   WORD wBitsPerSample;
9.	};
10.	struct FMT_BLOCK
11.	{
12.	   TCHAR szFmtID[4];    // 'f','m','t',' ' please note the
13.	                        // space character at the fourth location.
14.	      DWORD dwFmtSize;
15.	      WAVE_FORMAT wavFormat;
16.	};

最后,描述包含实际声音数据的data chunk:

1.	struct DATA_BLOCK
2.	{
3.	   TCHAR szDataID[4];    // 'd','a','t','a'
4.	   DWORD dwDataSize;
5.	};

以上就是一个WAV文件的三个最基本的chunk,也可以有很多可选chunk位于fmt block和data block之间,下面是一个可选chunk的例子(note chunk)。

1.	struct NOTE_CHUNK
2.	{
3.	   TCHAR ID[4];    // 'note'
4.	   long chunkSize;
5.	   long dwIdentifier;
6.	   TCHAR dwText[];
7.	};

原文:


The WAVE FileFormat

The WAVE File Format supports a variety of bitresolutions, sample rates, and channels of audio. I would say that this is themost popular format for storing PCM audio on the PC and has become synonymouswith the term "raw digital audio."

The WAVE file format is based on Microsoft's version of theElectronic Arts Interchange File Format method for storing data. In keepingwith the dictums of IFF,data in a Wave file is stored in many different "chunks."So, if a vendor wants to store additional information in a Wave file, he justadds info to new chunks instead of trying to tweak the base file format or comeup with his own proprietary file format. That is the primary goal of the IFF.

As mentioned earlier, a WAVE file is a collection of a numberof different types of chunks. But, there are threechunks that are required tobe present in a valid wave file:

1.   'RIFF', 'WAVE' chunk

2.   "fmt" chunk

3.   'data' chunk

All otherchunks are optional. The Riff wave chunk is the identifier chunkthat tells us that this is a wave file. The "fmt" chunk containsimportant parameters describing the waveform, such as its sample rate, bits per sample,and so forth. The Data chunk contains the actual waveform data.

An application that uses a WAVE file must be able to read the threerequired chunks,although it can ignore the optional chunks.But, all applications that perform a copy operation on wave files should copy all of the chunksin the WAVE.

The Riffchunk is always the first chunk. The fmt chunk should be present before thedata chunk. Apart from this, there are no restrictions upon the order of thechunks within a WAVE file.

Here is an example of the layout for a minimal WAVE file. Itconsists of a single WAVE containing the three required chunks.

While interpreting WAVE files, the unit of measurement usedis a "sample."Literally, it is what it says. A sample represents data captured during asingle sampling cycle. So, if you are sampling at 44 KHz, you will have 44 Ksamples. Each sample could be represented as 8 bits, 16 bits, 24 bits, or 32bits. (There is no restriction on how many bits you use for a sample exceptthat it has to be a multiple of 8.) To some extent, the more the number of bitsin a sample, the better the quality of the audio.

One annoying detail to note is that 8-bit samples arerepresented as "unsigned"values whereas 16-bit and higher are represented by "signed"values. I don't know why this discrepancy exists; that's just the way it is.

The data bits for each sample should be left-justified and padded with0s. For example, consider the case of a 10-bit sample (assamples must be multiples of 8, we need to represent it as 16 bits). The 10bits should be left-justified so that they become bits 6 to 15 inclusive, andbits 0 to 5 should be set to zero.

The analogy I have provided is for mono audio, meaning that you have just one"channel." When you deal with stereo audio, 3Daudio, and so forth, you are in effect dealing with multiplechannels, meaning you have multiple samples describing theaudio in any given moment in time. For example, for stereo audio, at any givenpoint in time you need to know what the audio signal was for the left channel as well as the right channel.So, you will have to read and write two samples at a time.

Say you sample at 44 KHz for stereoaudio; then effectively, you will have 44 K * 2 samples. If you are using 16bits per sample, then given the duration of audio, you can calculate the totalsize of the wave file as:

Size in bytes = sampling rate * numberof channels * (bits per sample / 8) * duration in seconds

When youare dealing with such multi-channelsounds, single sample points from each channel are interleaved. Instead of storing all of the samplepoints for the left channel first, and then storing all of the sample pointsfor the right channel next, you "interleave"the two channels' samples together. You would store the first sample of theleft channel. Then, you would store the first sample of the right channel, andso on.

When adevice needs to reproduce the stored stereo audio (or any multi-channel audio),it will process the left and right channels (or however many channels thereare) simultaneously. This collective piece of information is called a sample frame.

So far,you have covered the very basics of PCM audio and how it is represented in awave file. It is time to take a look at some code and see how you can use C++to manage wave files. Start by laying out the structures for the differentchunks of a wave file.

Thefirst chunk is the riff header chunk and can be represented as follows. You usea TCHAR that is defined as a normal ASCII char or as a wide character dependingupon whether the UNICODE directive has been set on your compiler.

  1. struct RIFF_HEADER
  2. {
  3.    TCHAR szRiffID[4];       // 'R','I','F','F'
  4.       DWORD dwRiffSize;
  5.  
  6.    TCHAR szRiffFormat[4];   // 'W','A','V','E'
  7. };

 

I guessit is self explanatory. The second chunk is the fmt chunk. It describes theproperties of the wave file, such as bits per sample, number of channels, andthe like. You can use a helper structure to neatly represent the chunk as:

  1. struct WAVE_FORMAT
  2. {
  3.    WORD wFormatTag;
  4.    WORD wChannels;
  5.    DWORD dwSamplesPerSec;
  6.    DWORD dwAvgBytesPerSec;
  7.    WORD wBlockAlign;
  8.    WORD wBitsPerSample;
  9. };
  10. struct FMT_BLOCK
  11. {
  12.    TCHAR szFmtID[4];   // 'f','m','t',' ' please note the
  13.                        // space character at the fourth location.
  14.       DWORD dwFmtSize;
  15.       WAVE_FORMAT wavFormat;
  16. };

 

 

  1.  
  2. struct DATA_BLOCK
  3. {
  4.    TCHAR szDataID[4];   // 'd','a','t','a'
  5.    DWORD dwDataSize;
  6. };

 

That's it. That's all you need todescribe a wave form. Of course, there a lot of optional chunks that you canhave (they should be before the data block and after the fmt block). Just as anexample, here is an optional chunk that you could use:

Note Chunk, used to store"comments" about the wave data:

  1. struct NOTE_CHUNK
  2. {
  3.    TCHAR ID[4];   // 'note'
  4.   long chunkSize;
  5.   long dwIdentifier;
  6.    TCHAR dwText[];
  7. };

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WAV文件格式解析 的相关文章

  • 二十三.Python学习笔记.5

    组合数据类型 一 集合类型及操作 1 集合是多个 元素的无序组合 集合类型与数学中的集合概念一致 集合元素之间无序 每个元素唯一 不存在相同元素 集合元素不可更改 不能是可变数据类型 2 集合是多个元素的无序组合 集合用大括号 表示 元素间
  • UEditor百度富文本编辑器实现自定义按钮和自定义右键菜单

    以1 5 0版本为例子 注意 所有字符串的字母只能小写 不能大写 自定义工具栏按钮 在根目录的ueditor config js找到toolbars参数 大于34行 在后面加上自定义字符串 然后在根目录 lang zh cn zh cn j
  • Word2016怎么制作目录

    Word2016如何制作目录 点击 引用 点击 目录 选择目录的生成方式
  • 实体类与实体DTO类之间的转换

    实体类与实体DTO类之间的转换 实体类与实体DTO类之间的转换 1 通过使用第三方序列化反序列化工具Newtonsoft Json 2 通过反射实现 3 通过表达式目录树加字典缓存实现 4 通过表达式目录树加泛型缓存实现 静态构造函数 1
  • 解决redis缓存雪崩

    目录 一 什么是缓存雪崩 二 解决缓存雪崩 一 什么是缓存雪崩 1 同一时间大量的key同时失效或者redis宕机 大量请求直接访问数据库 二 解决缓存雪崩 1 如果是同一时间大量key失效 可以给不同的key的ttl添加随机值 2 如果是
  • Python 处理GBK编码转UTF-8读写乱码问题

    今日写了个爬虫 爬取前程无忧的招聘信息 老套路 首先获取网页源代码 coding utf 8 import requests url http search 51job com jobsearch search result php pag

随机推荐

  • cmake+QT+VTK常见错误及解决方法

    1 安装环境 cmake3 0 QT4 8 6 VTK5 10 PS VTK6 10以上只能配合使用QT5 0以上版本 2 编译安装 参考 http blog csdn net www doling net article details
  • 从那里进入EI检索号查询入口?

    一 EI检索号是什么 EI检索号是就是文章被EI收录后 在检索页面生成的一串数字 EI检索号样式 Accession number 20200308040970 这串数字是唯一的 EI检索收录与否 也就是看有无这串数字 后期如果去申请EI检
  • 5G QoS控制原理专题详解-基础概念

    相关文章会在公众号同步更新 公众号 5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理 保证更新内容的准确性 避免通过二手 甚至多手的资料 以讹传讹误导网友 在介绍完流程详解后 会整理专题内容 比如切片 服务发现 QoS流端到端
  • Spring Cloud Sleuth使用简介

    Spring Cloud Spring Cloud为开发者提供了在分布式系统 如配置管理 服务发现 断路器 智能路由 微代理 控制总线 一次性Token 全局锁 决策竞选 分布式会话和集群状态 操作的开发工具 使用SpringCloud开发
  • VS2008如何打开memory窗口

    VS2008如何打开memory窗口 1 在想要观察的变量处设置断点 2 运行工程至断点处 3 debug gt windows gt memory 4 将变量名称复制至memory的address处 按enter键即可 5 右击内存显示去
  • klee内存模型

    klee内存模型 一 LLVM基础 二 Klee中相关的类 2 1 基础类 2 2 内存管理相关类 三 示例 3 1 示例1 3 2 示例2 3 3 示例3 3 4 示例4 这篇blog主要通过一些简单的示例来了解以下klee对内存的建模方
  • JAVA生成带图标的二维码(产品溯源码)

    一 效果图 二 代码示例 1 引入依赖
  • element-ui组件库

    PC端组件库参考 https www jianshu com p 669d3e41dca6 element 官网 https element eleme cn zh CN 1 下载安装组件库 cnpm i element ui 2 两种引入
  • wx.getUserProfile调用后没有反应?获取不到真正的用户头像和昵称

    考虑到近期开发者对小程序登录 用户信息相关接口调整的相关反馈 为优化开发者调整接口的体验 小程序登录 用户信息相关接口调整说明 公告中关于小程序回收 wx getUserInfo 接口可获取用户授权的个人信息能力的截止时间调整至2021年4
  • 基于Java的停车场管理系统的设计与实现

    技术 Java JSP等 摘要 随着科技的迅速发展 各种管理系统已应用到社会的各个领域 各个大小企业 单位 都充分意识到传统的手工管理模式已经逐渐不能适应时代的发展 为了更好的发展 纷纷开发适合自己的管理系统 通过停车场管理系统这个平台 可
  • ppp协议帧格式

    ppp协议帧格式解析 现在全世界使用得最多的数据链路层协议是 点对点协议 PPP Point to Point Protocol 用户使用拨号电话线接入因特网时 一般都是使用 PPP 协议 PPP 的帧格式和 HDLC 的相似 标志字段F
  • Idea中JRebel热部署安装及激活

    一 JRebel安装 到idea的插件下载中下载JRebel插件 二 JRebel激活 下载反向代理软件地址 Release v1 4 ilanyu ReverseProxy GitHub UUID生成地址 Online UUID Gene
  • 通过服务器接口上传文件,云服务器上传文件的接口

    云服务器上传文件的接口 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 安装传输工具在本地主机和Windows云服务器上分
  • MQTT.fx客户端MQTT接入阿里云物联网平台,登录、订阅、发布消息

    目录 1 准备 2 MQTT fx 设置登录名 密码 3 MQTT fx 接入阿里云 订阅Topic 4 阿里云下发数据给 MQTT fx 5 MQTT fx 发布消息给服务器 相关链接 MQTT协议 1 准备 阿里云物联网 创建产品 设备
  • 01:STM32点灯大师和蜂鸣器

    目录 一 点亮1个LED 1 连接图 2 函数介绍 3 点灯代码 二 LED闪烁 1 函数介绍 2 闪烁代码 三 LED流水灯 1 连接图 2 函数介绍 3 流水灯代码 四 按键控制LED 1 电路图 2 连接图 3 函数介绍 4 按键控制
  • spring3在jboss4中部署异常java.lang.RuntimeException: XPathFactory#newInstance() failed

    java lang RuntimeException XPathFactory newInstance failed to create an XPathFactory for the default object model http j
  • vscode 配置C++编译环境(完美版)

    文章目录 vscode c 环境配置 完整教程请查看该教程 vscode c 环境配置 完整教程请查看该教程 https blog csdn net qq 43041976 article details 100542557 使用MinGW
  • 通过less或者scss 定义变量 实现 vue主题切换

    更新 不需要全局引入less或者scss的可以直接在body上面挂载css变量 body baseColor 4F94FA activeColor 4F94FA fontColor 4F94FA 然后在需要使用的地方 title color
  • python 深拷贝和浅拷贝浅析

    简单点说 1 copy copy 浅拷贝 只拷贝父对象 不会拷贝对象的内部的子对象 id会变化2 copy deepcopy 深拷贝 拷贝对象及其子对象 id会变化 gt gt gt import copy gt gt gt a 1 2 3
  • WAV文件格式解析

    来源 http www codeguru com cpp g m multimedia audio article php c8935 PCM Audio and Wave Files htm page 1 源程序下载地址 http www