WAV文件是微軟公司開發的一種聲音文件格式,大部分的WAV文件中的音頻數據是直接通過PCM(Pulse Code Modulation)脈衝編碼調製得到的樣本數據,由於未被壓縮或壓縮比很小所以其質量較高,但同時數據量也很大。在數字領域,存儲音頻文件的最直接方式就是在滿足奈奎斯特抽樣定理的條件下,將模擬的音頻文件進行抽樣量化,將得到的一系列樣本值以二進制形式存儲在文件中,這就是PCM脈衝編碼調製的大致步驟。儘管大部分的WAV文件存儲的都是未經壓縮的,但它也支持一些音頻壓縮方法。
那麼如何將模擬的音頻變成存儲在電腦中的二進制數據呢?首先是選定抽樣頻率,對模擬音頻進行抽樣使得其在時間域是離散的,再將抽樣值進行量化。WAV文件對每個抽樣值的量化比特數沒有具體規定,但固定在存儲時每個樣本值由整數個字節來表示,因此每個樣本值的比特數均應該爲8bit的整數倍如8bit、16bit、24bit、32bit等。當某個樣本值的比特數不是8bit的整數倍時,則需要將其左移並再低位填充0使其變成8bit的整數倍。例如某個抽樣量化後的樣本值爲1011000101,則存儲時需要將其補0爲10110001 01000000,再採用小端序(先存低字節,再存高字節,默認存儲方式)的方式進行存儲,最終該樣值被存爲B1 40。一個需要注意的小細節是在 WAV文件中,8bit的是unsigned 類型的無符號數據,但16bit或更高的量化級的都是signed 類型的有符號數。
將模擬音頻轉化爲二進制的數據後,要想將其存儲在電腦中需要考慮其數據組織的形式,這樣在後續對文件進行操作時會更加方便。WAV文件是一種基於RIFF規範的音頻文件格式。RIFF(Resource Interchange File Format)是一種自包含的文件組織格式,它的基本單位是Chunk,一個基於RIFF規範的文件是由若干個Chunk組成的。
Chunk:
1.基本格式:
struct chunk
{
u32 chunk_id; /* 塊標誌 */
u32 chunk_size; /* 塊大小*/
u8 data[chunk_size]; /* 塊內容*/
};
chunk_id是一個4字節的ASCII標識符,用來標識該Chunk中的數據,不足四字節的再末尾用空位佔位。可以有:'RIFF','LIST','fmt ','data','WAV ','AVI '等,採用小端序。
chunk_size也是四字節,存儲的是data中的數據長度(以字節爲單位),不包括chunk_id和chunk_size本身所佔的內存單元。
data[chunk_size]:該Chunk中的數據,必須爲偶數個字節,若長度爲奇數則在最後添一個空字節。
2.各種子類:
Chunk有多種子類,其中兩種類型爲“RIFF”和“LIST”的兩種Chunk可以包含其他塊,其他的Chunk則只能有數據。
“RIFF”/“LIST”子類格式如下:
struct chunk
{
u32 chunk_ id; /* 塊標誌 */
u32 chunk_size; /* 塊大小 ,由於此時的data部分分爲type和restdata兩部分,所以chunk_size應該爲type和restdata數據長度之和*/
u32 type; /* 類型 */
u8 restdata[chunk_size-4] /* data中除了type4個字節後的數據,可以有包含的其他Chunk的數據 */
};
WAV文件格式:
一個WAV文件就是一個RIFF文件。其組成方式爲:一個RIFF Chunk,其type爲“WAVE”,其restdata部分包含了兩個Chunk分別爲“fmt” Chunk和“data” Chunk。
其詳細的結構如下:
ChunkID:四字節,“RIFF”(ASCII字符);
ChunkSize:四字節,表示該WAV文件除去ChunkID和ChunkSize之外的所有數據長度的總和,等於Format長度+SubChunk1長度(綠色部分)+Subchunk2長度(橙色部分),即4+(4+4+Subchunk Size)+(4+4+Subchunk2 Size)=4+24+(8+Subchunk2 Size)=36+Subchunk2 Size,由於只能用4字節來表示文件的大小,因此WAV文件限制在4GB內(有的程序限制其大小爲2GB);
Format:四字節,,表示該RIFF文件的類型,此處爲:“WAVE”(ASCII字符);
Subchunk1ID:四字節,“fmt ”(注意末尾有一個空格佔位,因爲一個Chunk的ID必須爲四位的ASCII字符);
Subchunk1Size:四字節,“fmt”chunk除去Subchunk1ID和Subchunk1Size之外的所有數據長度之和,爲2+2+4+4+2+2=16;
AudioFormat:兩字節,表示音頻數據的編碼方式,PCM=1,若不爲1則表示其他的數據編碼方式,其值所代表的詳細編碼方式可以見文章末尾;
NumChannels:兩字節,表示聲道數,Mono = 1,Stereo = 2等
SampleRate:四字節,採樣率,常見的採樣率有8000,44100等(單位爲Hz);
ByteRate:四字節,表示一秒鐘內的音頻信號數據需要多少個字節來存儲,爲SampleRate* NumChannels * BitsPerSample/8
BlockAlign:兩字節,表示每一時刻的音頻信號的抽樣值需要幾個字節來表示,爲NumChannels* BitsPerSample/8
BitsPerSample:兩字節,表示量化比特數,8bits = 8, 16 bits = 16等;
(若該音頻文件不是PCM 編碼,則其fmt chunk後還會有一些其他的參數)
Subchunk2 ID:四字節,“data”(ASCII字符);
Subchunk2 Size:四字節,data部分數據的長度,若爲奇數則在末尾添加空字節使得長度爲偶數;
Data:Subchunk2Size個字節,實際的聲音數據。
下面是舉例說明一個WAV文件中的數據(只列舉了文件的前72字節):
其顏色與上面的結構圖相對應。由圖可知該WAV文件是雙聲道、16bit量化的,因此某一時刻的樣本值由四字節來表示。文件的音頻信號樣值若爲多聲道,其值是交叉排列的,例如雙聲道爲:左聲道樣值、右聲道樣值、左聲道樣值、右聲道樣值……如此排列,多聲道同理。
由Audio Format這個參數的值,可以得知WAV文件中音頻數據的編碼方式,下列是目前WAV文件支持的編碼方式:
Code Description
0 (0x0000) Unknown
1 (0x0001) PCM/uncompressed
2 (0x0002) Microsoft ADPCM
6 (0x0006) ITU G.711 a-law
7 (0x0007) ITU G.711 µ-law
17 (0x0011) IMA ADPCM
20 (0x0016) ITU G.723 ADPCM (Yamaha)
49 (0x0031) GSM 6.10
64 (0x0040) ITU G.721 ADPCM
80 (0x0050) MPEG
65,536 (0xFFFF) Experimental
本文參考網址:
http://www.codeguru.com/cpp/g-m/multimedia/audio/article.php/c8935/PCM-Audio-and-Wave-Files.htm
http://soundfile.sapp.org/doc/WaveFormat/