WAV实际上就是裸数据PCM外面包了一层文件头,其实质为一个“RIFF”文件,普通的线性PCM数据的WAV头为44个字节。
格式定义
位置 | 字节数 | 值/类型 | 描述 |
---|---|---|---|
1 - 4 | 4 | "RIFF" | 表示文件"RIFF"文件 |
5 - 8 | 4 | 32位整形(UInt32) | 文件长度-8 |
9 -12 | 4 | "WAVE" | 文件类型头,表示一个"WAVE"文件 |
13-16 | 4 | "fmt " | 格式表示符 |
17-20 | 2 | 16位整形(UInt16) | "10 00 00 00 "表示PCM数据 |
21-22 | 2 | char(UInt8) | 数据类型,"01 00"表示 PCM |
23-24 | 2 | char(UInt8) | 通道数 |
25-28 | 4 | 32位整形(UInt32) | 采样率,比如""表示44100采样率 |
29-32 | 4 | 32位整形(UInt32) | 码率: 采样率x位深度x通道数/8 比如双通道的44.1K 16位采样的码率为176400 |
33-34 | 2 | 16位整形(UInt16) | 采样一次,占内存大小 : 位深度x通道数/8 |
35-36 | 2 | 16位整形(UInt16) | 采样深度 |
37-40 | 4 | "data" | 表述payload数据开头 |
41-44 | 4 | 32位整形(UInt32) | 数据部分的长度 |
根据格式我们再来看一个示例文件:
这里用hexdump来查看二进制wav文件:
hexdump -n 44 car.wav
因为wav头44字节,所以直接dump出44个字节。-n选项表示dunp的长度。
文件类型头
首先来的是一个头:“RIFF”:
52 49 46 46
接在后面的文件总长度:
F4 FB 01 00
注意,现在主流的平台都是小端序。 所以上面的数字16进制为:
0x0001fbf4
对应的十进制为 : 130036 再加上8为: 130044 而我们看的文件:
[cz@air_11:sound]$ls -al
total 272
drwxr-xr-x 4 cz staff 136 Dec 1 22:57 .
drwxr-xr-x 4 cz staff 136 Dec 1 22:47 ..
-rw-r--r--@ 1 cz staff 130044 Dec 1 22:41 car.wav
恰好是130044个字节。
接着还是表示WAV文件的标签:
57 41 56 45 66 6D 74 20
为"WAVEfmt "的16进制表示。
接着6个字节,和装的PCM数据类型有关,前四个字节和后两个字节配对:比如
前四个字节| 后两个字节| 类型
---|---
10 00 00 00| 01 00| 线性化PCM
12 00 00 00| 06 00| A律量化的PCM
12 00 00 00| 07 00| U律量化的PCM
32 00 00 00| 02 00| AD PCM
14 00 00 00| 31 00| GSM
我们这的例子是线性PCM,所以是:
10 00 00 00 01 00
PCM音频文件属性
接着上面,再来是两个字节表示的通道数:
02 00
换算下为"0x02"表示双通道。
接着是4个字节表示的采样率:
11 2b 00 00
换算成十进制“11025” 一个比较少见的数,
用这个采样率x通道数x位深度/8 就可以得到一秒钟数据有多少了,也叫码率,其后面4个字节就是这个值。
44 ac 00 00
再往后两个字节表示采样一次占字节数,再在往后两个字节是上面公式里面的位深度:
10 00
表示16bit深度,套入公式:
0x2b11*0x10 * 2 / 8=0xac44
正好对上。
而采样字节数为:
04 00
正好为 16*2/8 = 4byte。
头部结尾
最后还剩8个字节,分成两部分:
固定的表示数据开始的额"data" 以及表示数据长度的uint32:
d0 fb 01 00
为13000 其等于文件长度 130044 减去WAV头44。