目录
WAV简介
WAV的文件组成成分
RIFF Chunk
FORMAT Chunk
DATA Chunk
8 bit 单声道:
8 bit 双声道:
16 bit 单声道:
16 bit 双声道
解析代码
实例分析
RIFF Chunk
FORMAT Chunk
DATA Chunk
总结
参考文献
WAVE,又或者是因为扩展名而被大众所知的WAV,是微软与IBM公司所开发在个人电脑存储音频流的编码格式,在Windows平台的应用软件受到广泛的支持。该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。由于此音频格式未经过压缩,所以在音质方面不会出现失真的情况,但文件的体积因而在众多音频格式中较为大。
WAVE文件是以RIFF(Resource Interchange File Format, "资源交互文件格式")格式来组织内部结构的,因此符合 PIFF Resource Interchange File Format规范。
WAV文件本身主要由三个“块”信息组成:
- 将文件标识为WAV文件的RIFF Chunk
- 识别采样率等参数的FORMAT Chunk
- 包含实际数据(样本)的DATA Chunk
除了上述三个主要Chunk以外,文件中还可能包含一些可选的区块,如:Fack Chunk、Cue Points Chunk、Playlist Chunk、Associated data list Chunk等。
一个使用WAV文件的应用程序必须能够读取三个主要的区块,可以选择忽略那些可区块。但是,所有对WAV文件进行复制操作的应用程序应该复制WAV文件中的所有区块。RIFF Chunk总是排在第一的Chunk。FORMAT Chunk应该出现在DATA Chunk之前。除此以外,WAV文件中各区块的顺序没有任何限制。
首先先解释一下大端数据和小端数据:
- 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
- 所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
RIFF Chunk是标识符,它意在告诉我们这是个WAV文件。
field name | file offset | field size(bytes) | endian | content |
ChunkID | 0x00 | 4 | big | "RIFF"(0x52494646) |
ChunkSize | 0x04 | 4 | little | 文件大小,=(fileSize - 8) |
Format | 0x08 | 4 | big | "WAVE"(0x57415645) |
Format Chunk包含描述波形的许多重要参数,比如它的采样率、每采样值的比特数、声道数等等。
field name | file offset | field size(bytes) | endian | content |
Subchunk1ID | 0x0C | 4 | big | "fmt" (0x666D7420) |
Subchunk1Size | 0x10 | 4 | little | 表示该区块数据的长度(不包含ID和Size的长度,为16时WAV文件头部不包含附加信息 |
AudioFormat | 0x14 | 2 | little | 表示音频格式。PCM=1(即线性量化),除1之外的值则表示某种形式的压缩 |
NumChannels | 0x16 | 2 | little | 表示通道数。单声道为1,双声道为2 |
SampleRate | 0x18 | 4 | little | 表示采样率 |
ByteRate | 0x1C | 4 | little | 表示WAV音频数据传送速率。其值=通道数×采样率×每样本的数据位数/8 |
BlockAlign | 0x20 | 2 | little | 一个样本的包含所有通道在内的字节数。其值=通道数×每样本的数据位数/8 |
BitsPerSample | 0x22 | 2 | little | 表示每样本的数据位数。例如8bits=8,16bits=16 |
在解释WAV文件时,使用的测量单位是 "样本"。一个样本代表在一个采样周期内捕获的数据。所以,如果采样频率是44KHz,则将有44K个样本。每个样本可以表示为8比特、16比特、24比特或32比特。(除了必须是8的倍数外,对采样的位数没有限制)。在某种程度上,样本中的比特数越多,音频的质量就越好。
当处理这种多通道的声音时,每个通道的单个样本点是交错的,而不是先存储所有的左通道的样本点,然后存储所有的右通道的样本点。两个通道的样本交错在一起:将存储左通道的第一个样本;然后,再将存储右通道的第一个样本,以此类推。
这个区域只需要关心 NumChannels、SampleRate和BitsPerSample 三个参数就可以了,因为其它的都是依据这三个参数计算得到的。
field name | file offset | field size(bytes) | endian | content |
Subchunk2ID | 0x24 | 4 | big | 数据标记符"data" |
Subchunk2Size | 0x28 | 4 | little | 表示语音数据的长度。其值=样本数×通道数×每样本的数据位数/8 |
data | 0x2C | 不定 | little | 实际的声音数据 |
对于DATA Chunk,根据声道数和采样率的不同情况,布局如下(每列代表8bits):
采样1 | 采样2 |
数据1 | 数据2 |
采样1 | 采样2 | ||
声道1数据1 | 声道2数据1 | 声道1数据2 | 声道2数据2 |
采样1 | 采样2 | ||
数据1低字节 | 数据1高字节 | 数据2低字节 | 数据2高字节 |
采样1 | |||
声道1数据1低字节 | 声道1数据1高字节 | 声道2数据1低字节 | 声道2数据1高字节 |
采样2 | |||
声道1数据2低字节 | 声道1数据2高字节 | 声道2数据2低字节 | 声道2数据2高字节 |
#include
#include
#include
#include "wave.h"
int main()
{
FILE *fp = NULL;
Wav wav;
RIFF_t riff;
FMT_t fmt;
Data_t data;
fp = fopen("/home/douzi/Douzi_qdreamer/resolve_wav/mbfio_mic3.wav", "rb");
if (!fp) {
printf("can't open audio file\n");
exit(1);
}
fread(&wav, 1, sizeof(wav), fp);
riff = wav.riff;
fmt = wav.fmt;
data = wav.data;
/**
* RIFF
*/
printf("ChunkID \t\t%c%c%c%c\n", riff.ChunkID[0], riff.ChunkID[1], riff.ChunkID[2], riff.ChunkID[3]);
printf("ChunkSize \t\t%d\n", riff.ChunkSize);
printf("Format \t\t\t%c%c%c%c\n", riff.Format[0], riff.Format[1], riff.Format[2], riff.Format[3]);
printf("\n");
/**
* fmt
*/
printf("Subchunk1ID \t%c%c%c%c\n", fmt.Subchunk1ID[0], fmt.Subchunk1ID[1], fmt.Subchunk1ID[2], fmt.Subchunk1ID[3]);
printf("Subchunk1Size \t%d\n", fmt.Subchunk1Size);
printf("AudioFormat \t%d\n", fmt.AudioFormat);
printf("NumChannels \t%d\n", fmt.NumChannels);
printf("SampleRate \t\t%d\n", fmt.SampleRate);
printf("ByteRate \t\t%d\n", fmt.ByteRate);
printf("BlockAlign \t\t%d\n", fmt.BlockAlign);
printf("BitsPerSample \t%d\n", fmt.BitsPerSample);
printf("\n");
/**
* data
*/
printf("blockID \t\t%c%c%c%c\n", data.Subchunk2ID[0], data.Subchunk2ID[1], data.Subchunk2ID[2], data.Subchunk2ID[3]);
printf("blockSize \t\t%d\n", data.Subchunk2Size);
printf("\n");
// duration = Subchunk2Size / ByteRate
printf("duration \t\t%d\n", data.Subchunk2Size / fmt.ByteRate);
}
属性 | 取值 | 说明 |
ChunkID | “RIFF” | |
ChunkSize | 文件大小为64036字节 | |
Format | “WAVE” |
属性 | 取值 | 说明 |
Subchunk2ID | “data” | |
Subchunk2Size | 语音数据的长度为64000字节 | |
data | 太太太多了,略 | 实际的声音数据 |
对WAV格式影响最大的参数是编码格式。采用不同的编码的WAV格式是不同的,PCM是最常见的编码格式,其它的为压缩编码格式,一般很少使用,有的已经废弃。随着人们认识的进步可能还会有新的编码格式出现。今后对WAV文件格式的更多的研究是压缩编码格式。
[1]维基百科:WAV
[2]WAV文件格式解析 - CodeAntenna
[3]CSDN:WAV文件格式详解
[4] CSDN:wav音频文件格式解析
[5]博客园:WAVE 文件格式分析