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。