Wave文件格式主要是用來存儲音頻PCM數據的,其實也可以存儲非PCM音頻數據,這種情況我們就不考慮了。文件的擴展名爲“.wav”,採用RIFF文件結構。
一、RIFF文件格式簡介
1、RIFF文件是由一個一個的chunk組成的,並且chunk之間可以嵌套。使用小端存儲。
2、chunk的基本結構如下:
struct chunk
{
char chunkId[4]; // 4個字符組成的chunk標識,少於4字符右補空格
U32 chunkSize; // 數據塊的大小,字節
char data[chunkSize]
};
chunkId可以爲"RIFF"、"LIST"、"fmt"、"data"...
3、當chunkId爲"RIFF"或"LIST"(類型塊)時,chunk的結構變形爲下面這樣:
struct chunk
{
char chunkId[4]; // 4字符組成的chunk標識,少於4字符右補空格
U32 chunkSize; // chunkType + data的數據大小,字節
char chunkType[4]; // chunk的類型,e.g. WAVE/AVI...
char data[chunkSize - 4]
};
二、Wave文件格式
1、Wave文件採用RIFF文件格式,當然也就遵循RIFF文件結構。總體來看Wave文件是由多個chunk嵌套組成的。
字段 | 長度(B) | 字段描述 | ||||
chunk1 | chunkId | 4 | 第一個chunk的標識始終是"RIFF" | |||
chunkSize | 4 | 該chunk的數據大小,包括chunkType | ||||
chunkType | 4 | 對於Wave文件chunk的類型爲"WAVE" | ||||
data | chunk2 | chunkId | 4 | Wave文件的第二個chunk標識爲"fmt" | ||
chunkSize | 4 | 該chunk的數據大小 | ||||
data | wFormatTag | 2 | 音頻數據格式,0x0001表示PCM數據 | |||
nChannels | 2 | 聲道數 | ||||
nSamplesPerSec | 4 | 採樣率,每秒採樣次數 | ||||
nAvgBytesPerSec | 4 | 每秒的音頻數據大小(B),聲道數*採樣率*每個採樣點的比特數/8 | ||||
nBlockAlign | 2 | 每個時刻的音頻數據塊大小(B),聲道數*每個採樣點的比特數/8 | ||||
wBitsPerSample | 2 | 每個採樣點(的幅值)用多少比特編碼(8 or 16) | ||||
chunk3 | chunkId | 4 | Wave文件的第三個chunk的標識爲"data" | |||
chunkSize | 4 | 該chunk的數據大小 | ||||
data | PCM數據 | chunkSize | PCM數據 |
從上表可以看出:
(1) Wave文件最外層是一個標識爲"RIFF"的類型塊chunk1
(2) 在chunk1的data部分嵌套了2個chunk,即chunk2和chunk3
(3) chunk2的標識爲"fmt",在它的data部分存儲音頻的一些相關屬性
(4) chunk3的標識爲"data",在它的data部分存儲具體的音頻PCM數據
2、PCM數據存儲格式
3、用二進制方式打開.wav文件 驗證對Wave文件格式的理解
Wave測試文件我用的是C:\Windows\Media\Windows 關機.wav
二進制文本工具我用的是notepad++的Hex Editor插件,也可以用UltraEdit編輯器
爲了方便描述,我把Wave文件的各個字段進行了編號1-14,依次對應上面表格中的各個字段
1: 0x 52 49 46 46,4字節,"RIFF"的ASCII碼
對應chunk1的chunkId字段
2: 0x dc 95 02 00,4字節,由於RIFF文件格式採用小端存儲,所以轉換爲人們熟悉的字節序(大端)爲0x 00 02 95 dc,
再轉換爲十進制數爲169436,表示chunk1的數據大小爲169436字節。我們可以查看
Windows 關機.wav文件的大小爲169444字節,由於chunkId和chunkSize已經佔用8字節,
所以後面還有169436字節的數據。
對應chunk1的chunkSize字段
3: 0x 57 41 56 45,4字節,"WAVE"的ASCII碼
對應chunk1的chunkType字段
4: 0x 66 6d 74 20,4字節,"fmt "的ASCII碼,"fmt"不夠4個字符,所以右邊補空格。
對應chunk2的chunkId字段
5: 0x 10 00 00 00,4字節,同樣是小端存儲,轉換爲大端爲0x 00 00 00 10即十進制的16,
表示chunk2的數據大小爲16字節。從上面表格可知,wFormatTag、nChannels、
nSamplesPerSec、nAvgBytesPerSec、nBlockAlign、wBitsPerSample加起來剛好佔16字節。
對應chunk2的chunkSize字段
6: 0x 01 00,2字節,轉換爲大端爲0x 00 01,表示該Wave文件存儲的是音頻PCM數據。
對應chunk2的data部分的wFormatTag字段
7: 0x 02 00,2字節,轉換爲大端爲0x 00 02即十進制的2,表示音頻聲道數爲2即雙聲道。
對應chunk2的data部分的nChannels字段
8: 0x 44 ac 00 00,4字節,轉換爲大端爲0x 00 00 ac 44即十進制的44100,表示音頻採樣率爲44100Hz。
對應chunk2的data部分的nSamplesPerSec字段
9: 0x 10 b1 02 00,4字節,轉換爲大端爲0x 00 02 b1 10即十進制的176400,
表示每秒的音頻數據大小爲176400B。用公式”聲道數*採樣率*每個採樣點的比特數/8”
計算得到的剛好就是176400即2 * 44100 * 16 / 8 = 176400
對應chunk2的data部分的nAvgBytesPerSec
10: 0x 04 00,2字節,轉換爲大端爲0x 00 04即十進制的4,表示每個時鐘(有2個採樣點)的音頻數據有4B大小。
它的值等於”聲道數*每個採樣點的比特數/8”即2 * 16 / 8 = 4
對應chunk2的data部分的nBlockAlign字段
11: 0x 10 00,2字節,轉換爲大端爲0x 00 10即十進制的16,表示每個採樣值用16比特編碼。
對應chunk2的data部分的wBitsPerSample字段
12: 0x 64 61 74 64,4字節,"data"的ASCII碼
對應chunk3的chunkId字段
13: 0x b8 95 02 00,4字節,轉換爲大端爲0x 00 02 95 b8即十進制的169400,
表示chunk3的data部分的數據大小即PCM音頻數據的大小
對應chunk3的chunkSize字段
14: 音頻PCM數據即chunk3的data