WAVE 文件作為Windows多媒體中使用的聲音波形文件格式之一,它是以RIFF(Resource Interchange File Format)格式為標准的。這里不針對RIFF文件格式做介紹,不太了解的可以參考“RIFF格式簡介”一文。
WAVE文件構成
每個WAVE文件的頭四個字節便是“RIFF”。WAVE 文件由文件頭和數據體兩大部分組成。其中文件頭又分為 RIFF/WAV 文件標識段和聲音數據格式說明段兩部分。相對於RIFF文件,只是將“RIFF”chunk的form id替換為“WAVE”。下表是一個典型的WAVE文件各部分構成及其長度字段。注意所有數據采用windows默認的小端存儲。(FOURCC是一個特殊的四字節碼,判斷時按照字符順序判斷即可。)
域 | 長度 | 內容說明 | |
---|---|---|---|
chunkID | 4 | Chunk ID: "RIFF",FOURCC四字節碼 | |
chunksize | 4 | Chunk size: 4+n | |
WAVEID | 4 | WAVE ID: "WAVE",FOURCC四字節碼 | |
WAVE chunks | n | Wave chunks包含格式信息和音頻采樣數據,分為“format” chunk和“data”chunk兩部分。 |
Format chunk
Format chunk用於說明data chunk中PCM數據的格式。主要三種不同的format chunk格式(不同的格式碼)。如下表:
域 | 長度 | 內容說明 | |
---|---|---|---|
ckID | 4 | Chunk ID: "fmt ",FOURCC四字節碼,注意最后一個填充是空格。 | |
cksize | 4 | Chunk size: 16 or 18 or 40 | |
wFormatTag | 2 | Format code,格式碼 | |
nChannels | 2 | Number of interleaved channels,采樣聲道數(交織存儲) | |
nSamplesPerSec | 4 | Sampling rate (blocks per second),音頻采樣率 | |
nAvgBytesPerSec | 4 | Data rate,音頻碼率 | |
nBlockAlign | 2 | Data block size (bytes),音頻數據塊大小(單位字節) | |
wBitsPerSample | 2 | Bits per sample,量化位數(比如8bits、16bits、32bits) | |
|
|||
cbSize | 2 | Size of the extension (0 or 22),擴展字段長度 | |
|
|||
wValidBitsPerSample | 2 | Number of valid bits,有效的位長度 | |
dwChannelMask | 4 | Speaker position mask,聲道描述掩碼,比如左聲道、右聲道等 | |
SubFormat | 16 | GUID, including the data format code,數據格式碼 |
標准中定義的wFormatTag(Format code)可取值范圍如下表:
Format Code | PreProcessor Symbol | Data |
---|---|---|
0x0001 | WAVE_FORMAT_PCM | PCM |
0x0003 | WAVE_FORMAT_IEEE_FLOAT | IEEE float,[-1.0f,1.0f] |
0x0006 | WAVE_FORMAT_ALAW | 8-bit ITU-T G.711 A-law |
0x0007 | WAVE_FORMAT_MULAW | 8-bit ITU-T G.711 µ-law |
0xFFFE | WAVE_FORMAT_EXTENSIBLE | Determined by SubFormat |
PCM格式
當wFormatTag為0x0001時,表示WAVE文件中存儲的是PCM格式的音頻數據。
在數據域中除了單聲道-量化位數為8音頻數據之外PCM存儲格式按照補碼的形式存放。對於單聲道、量化位數為8的情況,使用offset binary(偏移二進制碼),有興趣的可以查看下對應的標准。
非PCM格式
對於非PCM格式的數據,使用擴展字段,擴展字段長度由cbSize指定。需要說明以下幾點:
- 對於非PCM格式,必須有擴展字段,字段長度cbSize可以為0,但是擴展字段不可省略。
- 對於浮點數據,最大峰值為1,量化位數(bits/sample)取值可以是32或64。
- 對於 log-PCM formats (µ-law and A-law)的格式,量化位數(bits/sample)取值為8。
- 對於非PCM格式,必須包含“FACT”chunk。
擴展格式
當FormatTag為WAVE_FORMAT_EXTENSIBLE(0xFFFE)時,表示format chunk有擴展字段,其中包括有效量化位數(wValidBitsPerSample)、聲道位置掩碼、以及額外的GUID(SubFormat)。
- 在正常PCM數據中量化位數(wBitsPerSample)必須是8的倍數,在WAVE_FORMAT_EXTENSIBLE下量化位數可以使用wValidBitsPerSample來描述,也就是會所wValidBitsPerSample有可能小於wBitsPerSample。
- 對於聲道位置掩碼的信息,可參考如下文章:Multi-channel / high bit resolution formats, 2001-12-04: Multiple Channel Audio Data and WAVE Files。
- SubFormat代表的GUID前兩個字節是由PCM數據格式填充的,例如WAVE_FORMAT_EXTENSIBLE。后續的14個字節是固定的,"\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71"。
在以下幾種情況下必須使用WAVE_FORMAT_EXTENSIBLE格式:
- PCM數據的量化位數(wBitsPerSample)大於16。
- 音頻采樣聲道數大於2。
- 實際量化位數不是8的倍數。
- 存儲順序和播放順序不一致,需要指定從聲道順序到聲卡播放順序映射的情況。
FACT chunk
通常PCM數據是不壓縮的,對於所有壓縮的非PCM格式都需要有FACT chunk。具體可參考:WAVE update (Revision: 3.0), 1994-04-15: Multimedia Registration Kit Revision 3.0 (Q120253))。FACT chunk至少定義一個字段,實際采樣數dwSampleLength。
關於FACT chunk可以了解,但是很少用到,如果有這種格式的wav文件,建議參考上述標准解析。
DATA chunk
data chunk中包含采樣數據。格式如下:
域 | 長度 | 內容說明 | |
---|---|---|---|
ckID | 4 | Chunk ID: "data" | |
cksize | 4 | Chunk size: n | |
sampled data | n | Samples,音頻采樣數據,交織存儲 | |
pad byte | 0 or 1 | Padding byte if n is odd,填充字節 |
實例
由於微軟將多媒體輸入輸出函數廢棄了(Using Multimedia File I/O),這里不給出專門讀寫的代碼,而是直接使用二進制形式分析。
先做如下假定:
- Nc 表示channels,聲道數
- Ns表示文件中包含的實際采樣塊數目,每個采樣塊包括Nc 個獨立采樣
- 采樣率為 F (blocks per second,單位Hz)
- 每個采樣的長度為M字節。
PCM文件格式如下表:
Field | Length | Contents | ||
---|---|---|---|---|
ckID | 4 | Chunk ID: "RIFF" | ||
cksize | 4 | Chunk size: 4 + 24 + (8 + M * Nc * Ns + (0 or 1)) |
||
WAVEID | 4 | WAVE ID: "WAVE" | ||
|
||||
ckID | 4 | Chunk ID: "fmt " | ||
cksize | 4 | Chunk size: 16 | ||
wFormatTag | 2 | WAVE_FORMAT_PCM | ||
nChannels | 2 | Nc | ||
nSamplesPerSec | 4 | F | ||
nAvgBytesPerSec | 4 | F * M * Nc | ||
nBlockAlign | 2 | M * Nc | ||
wBitsPerSample | 2 | rounds up to 8 * M | ||
|
||||
ckID | 4 | Chunk ID: "data" | ||
cksize | 4 | Chunk size: M * Nc* Ns | ||
sampled data | M * Nc * Ns | Nc * Ns channel-interleaved M-byte samples | ||
pad | 0 or 1 | Padding byte if M * Nc * Ns is odd |
注意WAVE文件可能附加information chunk。所以程序解析是最好按照上述標准定義,不要認為去掉wav fmt chunk之后全是data chunk。
Extensible Format如下表:
Field | Length | Contents | ||
---|---|---|---|---|
ckID | 4 | Chunk ID: "RIFF" | ||
cksize | 4 | Chunk size: 4 + 48 + 12 + (8 + M * Nc * Ns + (0 or 1)) |
||
WAVEID | 4 | WAVE ID, "WAVE" | ||
|
||||
ckID | 4 | Chunk ID: "fmt " | ||
cksize | 4 | Chunk size: 40 | ||
wFormatTag | 2 | WAVE_FORMAT_EXTENSIBLE | ||
nChannels | 2 | Nc | ||
nSamplesPerSec | 4 | F | ||
nAvgBytesPerSec | 4 | F * M * Nc | ||
nBlockAlign | 2 | M * Nc | ||
wBitsPerSample | 2 | 8 * M | ||
cbSize | 2 | Size of the extension: 22 | ||
wValidBitsPerSample | 2 | at most 8 * M | ||
dwChannelMask | 4 | Speaker position mask: 0 | ||
SubFormat | 16 | GUID (first two bytes are the data format code) | ||
|
||||
ckID | 4 | Chunk ID: "fact" | ||
cksize | 4 | Chunk size: 4 | ||
dwSampleLength | 4 | Nc * Ns | ||
|
||||
ckID | 4 | Chunk ID: "data" | ||
cksize | 4 | Chunk size: M * Nc * Ns | ||
sampled data | M * Nc *Ns | Nc * Ns channel-interleaved M-byte samples | ||
pad | 0 or 1 | Padding byte if M * Nc * Ns is odd |
本文主要參考:Audio File Format Specifications,相關測試wav文件及標准也從其鏈接下載。
寫作本文的目的主要是學習下wave文件格式,並能夠將音頻數據解析出來。
以上介紹的內容中針對WAVE文件我們可以只關心,fmt chunk、data chunk數據,其他數據chunk可以忽略,如果你對其他chunk感興趣,建議查看rfc2361及Microsoft提供的標准文檔。