WAV文件格式说明
―― form杨少军
WAVE文件是以RIFF(Resource InterchangeFile Format,"资源交互文件格式")格式来组织内部结构的。RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的单元,最顶端是一个“RIFF”块,下面的每个块有“类型块标识(可选)”、“标志符”、“数据大小”及“数据”等项所组成,其中,format chunk和data chunk是必需要的,其它的chunk可选。在data chunk中存放的数据可能是压缩的也可能是非压缩的,这是根据format chunk中的wFormatTag来决定的,如果wFormatTag为WAVE_FORMAT_PCM时,表示数据为非压缩的,其它的为压缩的。在非压缩格式时,存放的数据就是PCM码;而在采用压缩格式时,由于各个公司都有自己的压缩算法,没有一个统一的标准,所以压缩制式非常杂。下面主要以INTEL 公司的IMA-ADPCM压缩算法来讲WAV文件的结构。
1. WAV文件内部结构
在讲WAV文件结构时,主要以非压缩格式和以INTEL 公司的IMA-ADPCM压缩算法来论述。下面来谈谈INTEL 公司的IMA-ADPCM压缩算法。
IMA-ADPCM 是Intel公司首先开发的是一种主要针对16bit采样波形数据的有损压缩算法, 压缩比为 4:1.它与通常的DVI-ADPCM是同一算法。它是将声音流中每次采样的 16bit 数据以 4bit 存储。具体的压缩算法可以参看其它文章。
WAV文件的内部结构如表所示:
| 字节数 | 数据类型 | 变量名 | 内容 |
| 4 | Char | RIFF[4] | “RIFF”标志 |
| 4 | DWORD | ChunkSize | 文件的大小,不包含前8个byte |
| 4 | Char | Fmt[4] | “WAVE”标志 |
Fact Chunk | 4 | Char | FactChunkID[4] | 在wFormatTag为非WAVE_FORMAT_PCM标志时,有Fact chunk |
4 | DWORD | FactChunkSize | Fact chunk的长度,不包括FactChunkID,FactChunkSize。故为4 | |
4 | DWORD | dwSamplesLength | 表示转化后总共的采样点数 | |
Format Chunk | 4 | Char | FormatChuckID | “fmt ”标志 |
4 | DWORD | FormatChuckSize | Format chunk的大小,共有20个byte | |
2 | WORD | wFormatTag | Format类型,在采用INTEL IMA-ADPCM压缩算法时,为0x00 11 | |
2 | WORD | nChannels | 通道数 | |
4 | DWORD | nSamplesPerSec | 采样率 | |
4 | DWORD | nAvgBytesPerSec | 每秒的数据流量,以byte计 | |
2 | WORD | nBlockAlign | 在data block中的block大小 | |
2 | WORD | wBitsPerSample | 每个采样点多少位,指压缩后的位数 | |
2 | WORD | cbSize | 额外的字节数,即下面的一个WORD(在wFormatTag为非WAVE_FORMAT_PCM标志时) | |
2 | WORD | wSamplesPerBlock | 每一个data block的采样点数 | |
Data Chunk | 4 | Char | DataChunkID | “data”标志 |
4 | DWORD | DataChunkSize | 所有的data block的大小,不包括ID和Size的8个byte | |
nBlockAlign | Data block 0 | Block header |
| |
Data |
| |||
nBlockAlign | 。。。。。。 | 。。。。。。 |
| |
。。。。。。 |
| |||
nBlockAlign | Data block n | Block header |
| |
Data |
|
在wFormatTag为WAVE_FORMAT_PCM时,没有Fact Chunk,也没有format chunk中的wSamplesPerBlock,data chunk中紧跟着DataChunkSize后的就是PCM数据了。而在wFormatTag为WAVE_FORMAT_DVI_ADPCM时,表示采用INTEL公司的IMA-ADPCM压缩算法,WAV文件格式即为上表所示。
在采用IMA-ADPCM压缩算法时,“data”chuck中的数据是以block形式来组织的,把它叫做“段”,也就是说在进行压缩时,并不是依次把所有的数据进行压缩保存,而是分段进行的。Data Block一般是由block header (block头) 和 data 两者组成的。其中block header是一个结构,它在单声道下的定义如下:
Typedef struct
{
short sample0; //block中第一个采样值(未压缩)
BYTE index; //上一个block最后一个index,第一个block的index=0;
BYTE reserved; //尚未使用
}MonoBlockHeader;
有了blockheader的信息后,就可以不需要知道这个block前面和后面的数据而轻松地解出本block中的压缩数据。对于双声道,它的blockheader应该包含两个MonoBlockHeader其定义如下:
typedaf struct
{
MonoBlockHeader leftbher;
MonoBlockHeader rightbher;
}StereoBlockHeader;
在解压缩时,左右声道是分开处理的,所以必须有两个MonoBlockHeader;
//波形文件的文件头,占用44Byte,文件头后为波形数据区
struct FORMAT_WAV
{
long ChunkID; //“RIFF”
long ChunkSize; //chunk(大块)的数量,wav文件的总大小,单位字节
long Format; //“WAVE”
long Subchunk1ID; //“fmt” 第一个chunk的ID
long Subchunk1Size; //第一个chunk的Size
short AudioFormat; //音频格式
short NumChannels; //声道的数量
long SampleRate; //采样率
long ByteRate; //比特率
short BlockAlign; //块对齐
short BitsPerSample; //每个采样点的位宽
long Subchunk2ID; //"data" 第二个chunk的ID
long Subchunk2Size; //第二个chunk的Size,波形数据的大小,单位为字节
}
};