根据网络上的各种资料可以得知WAVE文件本质上就是一种RIFF格式,它可以抽象成一颗树(数据结构的一种)来看。
我们看到这张图上面,从上到下分别对应着二进制数据在文件中相对于起始位置的偏移量。每一个格子对应一个字段,field size表示每个字段所占据的大小,根据这个大小以及当前的偏移量,我们也可以计算出下一个字段的起始地址(偏移量)。
一个chunk结构其实就是三个部分,第一部分标识符用于说明这个chunk是存什么内容,第二部分是说明这个chunk的内容有多大,用于让程序知道如果要找到下一个chunk该把地址偏移多少去读取,第三部分则是实际内容。
顶级chunk: 说明这个chunk是存什么内容
子chunk
第一个子chunk
Subchunk1ID 在WAV文件中恒定为fmt,表示该subchunk的内容为该WAV音频文件的一些元数据,即WAV音频的一些格式信息
AudioFormat这个字段一般为1,表示这个WAV音频为PCM编码
NumChannels则是该WAV音频文件的声道数量。1为单声道,2为双声道。
SampleRate 则为采样率
ByteRate 为数据传输速率。其值为:通道数*每秒数据位数*每样本的数据位数/8
BlockAlign 则是每个block的平均大小,它等于NumChannels * BitsPerSample/8,至于block是什么,以及它的计算公式是怎么得来的需要来看看另一个Subchunk。BitsPerSample则为每秒采样比特,有的地方称它为量化精度或者PCM位宽。
另一个子chunk
Subchunk2ID 是在WAV文件中恒定为data,即WAV音频文件的实际音频数据,里面存储的是音频的采样数据。但是我们的音频如果是双声道,那么实际上某一个采样时刻采样的数据是由左声道和右声道共同组成的。而这个共同组成的采样我们把他成为block。前面有讲到BlockAlign = NumChannels * BitsPerSample / 8,这个现在就很好理解了,至于为什么末尾要除以8,这是因为计算机中是以8个二进制数表示一个字节,所以要除以8来求出字节数。
音频的持续长度,我们可以通过Subchunk2Size除以ByteRate,也就是实际音频data的chunk总长度除以每秒字节数得到持续多少秒。
实例:用C语言解析wav文件
#include <stdio.h>
#include <stdint.h> /*struct类型里面我用的是uint32_t等类型,而不是传统的int,short等等
这些类型是由stdint.h头文件提供*/
#include <stdlib.h>
typedef struct wave_tag //声明结构体的相关参数
{
char ChunkID[4]; // "RIFF"标志
unsigned int ChunkSize; // 文件长度(WAVE文件的大小, 不含前8个字节)
char Format[4];</