作者:多盟乄丶 | 来源:互联网 | 2023-09-12 22:21
文章目录
- 第一个子chunk
- 另一个子chunk
- 实例:用C语言解析wav文件
- 运行结果:
- 通过WinHex验证结果
根据网络上的各种资料可以得知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
#include
#include typedef struct wave_tag {char ChunkID[4]; unsigned int ChunkSize; char Format[4]; char SubChunk1ID[4]; unsigned long int SubChunk1Size; unsigned short int AudioFormat; unsigned short int NumChannels; unsigned short int SampleRate; unsigned int ByteRate; unsigned short int BlockAlign; unsigned short int BitsPerSample; char SubChunk2ID[4]; unsigned long int SubChunk2Size; } WAVE;int main(int argc, char *argv[]){FILE *fp; WAVE wav; fp=fopen("E:\\test_wave\\2.wav","rb"); fread(&wav, sizeof(WAVE), 1, fp);
printf("ChunkID=\t%c%c%c%c \n",wav.ChunkID[0],wav.ChunkID[1],wav.ChunkID[2],wav.ChunkID[3]); printf("ChunkSize=\t%d\n",wav.ChunkSize); printf("Format=\t\t%c%c%c%c\n",wav.Format[0],wav.Format[1],wav.Format[2],wav.Format[3]);printf("SubChunk1ID=\t%c%c%c%c\n",wav.SubChunk1ID[0],wav.SubChunk1ID[1],wav.SubChunk1ID[2],wav.SubChunk1ID[3]);printf("SubChunk1Size=\t%ld\n",wav.SubChunk1Size);printf("AudioFormat=\t%x\n",wav.AudioFormat); printf("NumChannels=\t%d\n",wav.NumChannels);printf("SampleRate=\t%d\n",wav.SampleRate);printf("ByteRate=\t%d\n",wav.ByteRate);printf("BlockAlign=\t%d\n",wav.BlockAlign);printf("BitsPerSample=\t%d\n",wav.BitsPerSample);printf("SubChunk2ID=\t%c%c%c%c \n",wav.SubChunk2ID[0],wav.SubChunk2ID[1],wav.SubChunk2ID[2],wav.SubChunk2ID[3]);printf("SubChunk2Size=\t%ld\n",wav.SubChunk2Size);return 0;}
运行结果:
通过WinHex验证结果
WinHex 是一款以通用的 16 进制编辑器为核心,专门用来对付计算机取证、数据恢复、低级数据处理、以及 IT 安全性、各种日常紧急情况的高级工具: 用来检查和修复各种文件、恢复删除文件、硬盘损坏、数码相机卡损坏造成的数据丢失等。可进行 2 进制、16 进制 ASCII, Intel 16 进制, 和 Motorola S 转换。