一、PCM文件
PCM文件:模擬音頻信號經模數轉換(A/D變換)直接形成的二進制序列,該文件沒有附加的文件頭和文件結束標志。Windows的Convert工具能夠把PCM音頻格式的文件轉換成Microsoft的WAV格式的文件。
將音頻數字化:事實上就是將聲音數字化。最常見的方式是透過脈沖編碼調制PCM(Pulse Code Modulation) 。
運作原理例如以下:首先我們考慮聲音經過麥克風,轉換成一連串電壓變化的信號。例如以下圖所看到的。這張圖的橫座標為秒。縱座標為電壓大小。要將這種信號轉為 PCM 格式的方法,是使用三個參數來表示聲音。它們是:聲道數、採樣位數和採樣頻率。
採樣頻率:即取樣頻率,指每秒鍾取得聲音樣本的次數。採樣頻率越高,聲音的質量也就越好,聲音的還原也就越真實,但同一時候它占的資源比較多。因為人耳的分辨率非常有限,太高的頻率並不能分辨出來。在16位聲卡中有22KHz、44KHz等幾級,當中,22KHz相當於普通FM廣播的音質,44KHz已相當於CD音質了,眼下的經常使用採樣頻率都不超過48KHz。
採樣值或取樣值(就是將採樣樣本幅度量化):它是用來衡量聲音波動變化的一個參數。也能夠說是聲卡的分辨率。它的數值越大,分辨率也就越高。所發出聲音的能力越強。
聲道數:非常好理解,有單聲道和立體聲之分,單聲道的聲音僅僅能使用一個喇叭發聲(有的也處理成兩個喇叭輸出同一個聲道的聲音)。立體聲的PCM 能夠使兩個喇叭都發聲(一般左右聲道有分工) ,更能感受到空間效果。
以下再用圖解來看看採樣位數和採樣頻率的概念。讓我們來看看這幾幅圖。圖中的黑色曲線表示的是PCM 文件錄制的自然界的聲波,紅色曲線表示的是PCM 文件輸出的聲波。橫坐標便是採樣頻率;縱坐標便是採樣位數。這幾幅圖中的格子從左到右,逐漸加密,先是加大橫坐標的密度,然后加大縱坐標的密度。顯然,當橫坐標的單位越小即兩個採樣時刻的間隔越小。則越有利於保持原始聲音的真實情況,換句話說,採樣的頻率越大則音質越有保證;同理,當縱坐標的單位越小則越有利於音質的提高。即採樣的位數越大越好。
在計算機中採樣位數一般有8位和16位之分。但有一點請大家注意,8位不是說把縱坐標分成8份,而是分成2的8次方即256份; 同理16位是把縱坐標分成2的16次方65536份; 而採樣頻率一般有11025HZ(11KHz),22050HZ(22KHz)、44100Hz(44KHz)三種。
那么,如今我們就能夠得到PCM文件所占容量的公式:存儲量 = (採樣頻率*採樣位數*聲道)*時間/8(單位:字節數).比如,數字激光唱盤(CD-DA。紅皮書標准)的標准採樣頻率為44.lkHz。採樣數位為16位,立體聲(2聲道),能夠差點兒無失真地播出頻率高達22kHz的聲音,這也是人類所能聽到的最高頻率聲音。
激光唱盤一分鍾音樂須要的存儲量為:
(44.1*1000*l6*2)*60/8=10。584。000(字節)=10.584MBytes
這個數值就是PCM聲音文件在硬盤中所占磁盤空間的存儲量。
計算機音頻文件的格式決定了其聲音的品質,日常生活中電話、收音機等均為模擬音頻信號。即不存在採樣頻率和採樣位數的概念,我們能夠這樣比較一下:
44KHz,16BIT的聲音稱作:CD音質;
22KHz、16Bit的聲音效果近似於立體聲(FM Stereo)廣播。稱作:廣播音質;
11kHz、8Bit的聲音,稱作:電話音質。
音頻參數
經常見到這樣的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等.
- 44100HZ 16bit stereo:
每秒鍾有 44100 次采樣, 采樣數據用 16 位(2字節)記錄, 雙聲道(立體聲);
- 22050HZ 8bit mono:
每秒鍾有 22050 次采樣, 采樣數據用 8 位(1字節)記錄, 單聲道;
什么是PCM音頻數據
PCM(Pulse Code Modulation)也被稱為脈沖編碼調制。
PCM音頻數據是未經壓縮的音頻采樣數據裸流,它是由模擬信號經過采樣、量化、編碼轉換成的標准的數字音頻數據。
PCM數據存儲格式
PCM數據存儲格式
本文中聲音樣值的采樣頻率一律是44100Hz,采樣格式一律為16LE。
“16”代表采樣位數是16bit。由於1Byte=8bit,所以一個聲道的一個采樣值占用2Byte。
“LE”代表Little Endian,代表2 Byte采樣值的存儲方式為高位存在高地址中。
立體聲的左右聲道的數據是一樣的嗎?
原來一直理解立體聲的左右聲道是一樣的,但是通過查看實際的數據,發現並不一樣。比如:

從以上可以看出,剛開始的4個字節是同一個采樣點,其中0x04e8是左聲道,0x01c9是右聲道,發現是不一樣的。
通過cool edit pro查看波形:

可以看出左右聲道,雖然波形相似,但是的確存在不同。
二、WAV文件
FileSize = HeadSize + TimeInSecond * SampleRate * Channels * BitsPerSample / 8
2、其中HeadSize為WAV文件頭部長度;SampleRate,即采樣率,可選8000、16000、32000、44100或48000;Channels表示聲道數量,通常為1或2;BitsPerSample代表單個Sample的位深,可選8、16以及32,其中32位時可以是float類型。
WAV是一種極其簡單的文件格式,如果對其結構足夠熟悉,完全可以自己通過代碼寫入WAV文件,從而免去引入一些復雜中間庫。特別是在對音頻進行調試的時候,能提高效率,降低復雜度。
WAV格式遵循RIFF規范,所有WAV都有一個文件頭,記錄着音頻流的采樣和編碼信息。數據塊的記錄方式是小尾端(little-endian)。
三、RIFF
RIFF,全稱Resource Interchange File Format,是一種按照標記區塊存儲數據的通用文件存儲格式,多用於存儲音頻、視頻等多媒體數據。Microsoft在Windows下的WAV、AVI等都是基於RIFF實現的。
一個標准的RIFF規范規范文件,最小存儲單位為“塊”(Chunk),每個塊(Chunk)包含以下三個信息:
名稱 | 大小 | 類型 | 端序 | 含義 |
---|---|---|---|---|
FOURCC | 4 | 字符 | 大端 | 用於標識Chunk ID或chunk 類型,通常為Chunk ID |
Data Field Size | 4 | 整形 | 小端 | 特別注意,該長度不包含其本身,以及FOURCC |
Data Field | - | - | - | 數據域,如果Chunk ID為"RIFF"或"LIST",則開始四個字節為類型碼 |
只有ID為"RIFF"或者"LIST"的塊允許擁有子塊(SubChunk)。RIFF文件的第一個塊的ID必須是"RIFF",也就是說ID為"LIST"的塊只能是子塊(SubChunk),他們和各個子塊形成了復雜的RIFF文件結構。
RIFF數據域的的起始位置四個字節為類型碼(Form Type),用於說明數據域的格式,比如WAV文件的類型碼為"WAVE"。
"LIST"塊的數據域的起始位置也有一個四字節類型碼(List Type),用於說明LIST數據域的數據內容。比如,類型碼為"INFO"時,其數據域可能包括"ICOP"、"ICRD"塊,用於記錄文件版權和創建時間信息。
四、WAV
以最簡單的無損WAV格式文件為例,此時文件的音頻數據部分為PCM,比較簡單,重點在於WAV頭部。一個典型的WAV文件頭部長度為44字節,包含了采樣率,通道數,位深等信息,如下表所示。
偏移位置 | 大小 | 類型 | 端序 | 含義 |
---|---|---|---|---|
0x00-0x03 | 4 | 字符 | 大端 | "RIFF"塊(0x52494646),標記為RIFF文件格式 |
0x04-0x07 | 4 | 整型 | 小端 | 塊數據域大小(Chunk Size),即從下一個地址開始,到文件末尾的總字節數,或者文件總字節數-8。從0x08開始一直到文件末尾,都是ID為"RIFF"塊的內容,其中會包含兩個子塊,"fmt "和"data" |
0x08-0x0B | 4 | 字符 | 大端 | 類型碼(Form Type),WAV文件格式標記,即"WAVE"四個字母 |
0x0C-0x0F | 4 | 字符 | 大端 | "fmt "子塊(0x666D7420),注意末尾的空格 |
0x10-0x13 | 4 | 整形 | 小端 | 子塊數據域大小(SubChunk Size) |
0x14-0x15 | 2 | 整形 | 小端 | 編碼格式(Audio Format),1代表PCM無損格式 |
0x16-0x17 | 2 | 整形 | 小端 | 聲道數(Channels),1或2 |
0x18-0x1B | 4 | 整形 | 小端 | 采樣率(Sample Rate) |
0x1C-0x1F | 4 | 整形 | 小端 | 傳輸速率(Byte Rate),每秒數據字節數,SampleRate * Channels * BitsPerSample / 8 |
0x20-0x21 | 2 | 整形 | 小端 | 每個采樣所需的字節數BlockAlign,BitsPerSample*Channels/8 |
0x22-0x23 | 2 | 整形 | 小端 | 單個采樣位深(Bits Per Sample),可選8、16或32 |
0x24-0x27 | 4 | 字符 | 大端 | "data"子塊 (0x64617461) |
0x28-0x2B | 4 | 整形 | 小端 | 子塊數據域大小(SubChunk Size) |
0x2C-eos | N | PCM |
上表為典型的WAV頭部格式,從0x00到0x2B總共44字節,從0x2C開始一直到文件末尾都是PCM音頻數據。所以如果你已經知道了PCM的采樣信息,那么可以直接跳過頭部的解析,直接從0x2C開始讀取PCM即可,但是對於另一些無損的WAV文件卻是不行的。
五、WAV擴展
有一些WAV的頭部並不僅僅只有44個字節,比如通過FFmpge編碼而來的WAV文件頭部信息通常大於44個字節。這是因為根據WAV規范,其頭部還支持攜帶附加信息,所以只按照44個字節的長度去解析WAV頭部信息是不一定正確的,還需要考慮附加信息。那么如何知道一個WAV文件頭部是否包含附加信息呢?
根據"fmt "子塊長度來判斷即可。
如果fmt SubChunk Size等於0x10(16),表示頭部不包含附加信息,即WAV頭部信息長度為44;如果等於0x12(18),則包含附加信息,此時頭部信息長度大於44。
當WAV頭部包含附加信息時,fmt SubChunk Size長度為18,並且緊隨是另一個子塊,這個包含了一些自定義的附加信息,接着往下才是"data"子塊,格式如下:
偏移位置 | 大小 | 類型 | 端序 | 含義 |
---|---|---|---|---|
0x00-0x03 | 4 | 字符 | 大端 | "RIFF"塊(0x52494646),標記為RIFF文件格式 |
0x04-0x07 | 4 | 整型 | 小端 | 塊數據域大小(Chunk Size),即從下一個地址開始,到文件末尾的總字節數,或者文件總字節數-8。從0x08開始一直到文件末尾,都是ID為"RIFF"塊的內容,其中會包含兩個子塊,"fmt "和"data" |
0x08-0x0B | 4 | 字符 | 大端 | 類型碼(Form Type),WAV文件格式標記,即"WAVE"四個字母 |
0x0C-0x0F | 4 | 字符 | 大端 | "fmt "子塊(0x666D7420),注意末尾的空格 |
0x10-0x13 | 4 | 整形 | 小端 | 子塊數據域大小(SubChunk Size),這里為0x12 |
0x14-0x15 | 2 | 整形 | 小端 | 編碼格式(Audio Format),1代表PCM無損格式 |
0x16-0x17 | 2 | 整形 | 小端 | 聲道數(Channels),1或2 |
0x18-0x1B | 4 | 整形 | 小端 | 采樣率(Sample Rate) |
0x1C-0x1F | 4 | 整形 | 小端 | 傳輸速率(Byte Rate),每秒數據字節數,SampleRate * Channels * BitsPerSample / 8 |
0x20-0x21 | 2 | 整形 | 小端 | 每個采樣所需的字節數BlockAlign,BitsPerSample*Channels/8 |
0x22-0x23 | 2 | 整形 | 小端 | 單個采樣位深(Bits Per Sample),可選8、16或32 |
0x24-0x25 | 2 | |||
0x26-不定 | - | - | - | 可選附加信息,標准RIFF Chunk |
不定 | 4 | 字符 | 大端 | "data"子塊 (0x64617461) |
不定 | 4 | 整形 | 小端 | 子塊數據域大小(SubChunk Size) |
不定 | N | PCM |
如果一個無損WAV文件頭部包含了附加信息,那么PCM音頻所在的位置就不確定了,但由於附加信息也是一個子塊(SubChunk),根據RIFF規范,該子塊也必然記錄着其長度信息,所以我們還是有辦法能夠動態計算出其位置,下面是計算步驟:
- 判斷fmt塊長度是否為18。
- 如果fmt長度為18,那么必然從0x26位置開始為附加信息塊,0x30-0x33位置記錄着該子塊長度。
- 根據步驟2獲取的子塊長度,假定為N(16進制),那么PCM音頻信息開始位置為:0x34 + N + 8。
六、補充
WAVE文件支持很多不同的比特率、采樣率、多聲道音頻。WAVE是PC機上存儲PCM音頻最流行的文件格式,基本上可以等同於原始數字音頻。
WAVE文件為了與IFF保持一致,數據采用“chunk”來存儲。因此,如果想要在WAVE文件中補充一些新的信息,只需要在在新chunk中添加信息,而不需要改變整個文件。這也是設計IFF最初的目的。
WAVE文件是很多不同的chunk集合,但是對於一個基本的WAVE文件而言,以下三種chunk是必不可少的。
使用WAVE文件的應用程序必須具有讀取以上三種chunk信息的能力,如果程序想要復制WAVE文件,必須拷貝文件中所有的chunk。
文件中第一個chunk是RIFFchunk,然后是fmtchunk,最后是datachunk。對於其他的chunk,順序沒有嚴格的限制。
以下是一個最基本的WAVE文件,包含三種必要chunk。
文件組織形式:
1. 文件頭
RIFF/WAV文件標識段
聲音數據格式說明段
2. 數據體:
由 PCM(脈沖編碼調制)格式表示的樣本組成。
描述WAVE文件的基本單元是“sample”,一個sample代表采樣一次得到的數據。因此如果用44KHz采樣,將在一秒中得到44000個sample。每個sample可以用8位、24位,甚至32位表示(位數沒有限制,只要是8的整數倍即可),位數越高,音頻質量越好。
此處有一個值得注意的細節,8位代表無符號的數值,而16位或16位以上代表有符號的數值。例如,如果有一個10bit的樣本,由於sample位數要求是8的倍數,我們就需要把它填充到16位。16位中:0-5位補0,6-15位是原始的10bit數據。這就是左補零對齊原則。
上述只是單聲道,如果要處理多聲道,就需要在任意給定時刻給出多個sameple。例如,在多聲道中,給出某一時刻,我們需要分辨出哪些sample是左聲道的,哪些sample是右聲道的。因此,我們需要一次讀寫兩個sample.
假如以44KHz取樣立體聲音頻,我們需要一秒讀寫44*2 KHz的sample. 給出公式:
每秒數據大小(字節)=采樣率 * 聲道數 * sample比特數 / 8
處理多聲道音頻時,每個聲道的樣本是交叉存儲的。我們把左右聲道數據交叉存儲在一起:先存儲第一個sample的左聲道數據,然后存儲第一個sample的右聲道數據。
當一個設備需要重現聲音時,它需要同時處理多個聲道,一個sample中多個聲道信息稱為一個樣本幀。
七、實例分析
(1)“52 49 46 46”這個是Ascii字符“RIFF”,這部分是固定格式,表明這是一個WAVE文件頭。
(2)“22 60 28 00”,這個是我這個WAV文件的數據大小,這個大小包括除了前面4個字節的所有字節,也就等於文件總字節數減去8。16進制的“22 60 28 00”對應是十進制的“2646050”。
(3)“57 41 56 45 66 6D 74 20”,也是Ascii字符“WAVEfmt”,這部分是固定格式。
以后是PCMWAVEFORMAT部分
(4)“12 00 00 00”,這是一個DWORD,對應數字18,這個對應定義中的PCMWAVEFORMAT部分的大小,可以看到后面的這個段內容正好是18個字節。一般情況下大小為16,此時最后附加信息沒有,上面這個文件多了兩個字節的附加信息。
(5)“01 00”,這是一個WORD,對應定義為編碼格式(WAVE_FORMAT_PCM格式一般用的是這個)。
(6)“01 00”,這是一個WORD,對應數字1,表示聲道數為1,是個單聲道Wav。
(7)“22 56 00 00”對應數字22050,代表的是采樣頻率22050,采樣率(每秒樣本數),表示每個通道的播放速度
(8)“44 AC 00 00”對應數字44100,代表的是每秒的數據量,波形音頻數據傳送速率,其值為通道數×每秒樣本數×每樣本的數據位數/8(1*22050*16/8)。播放軟件利用此值可以估計緩沖區的大小。
(9)“02 00”對應數字是2,表示塊對齊的內容。數據塊的調整數(按字節算的),其值為通道數×每樣本的數據位值/8。播放軟件需要一次處理多個該值大小的字節數據,以便將其值用於緩沖區的調整。
(10)“10 00”數值為16,采樣大小為16Bits,每樣本的數據位數,表示每個聲道中各個樣本的數據位數。如果有多個聲道,對每個聲道而言,樣本大小都一樣。
(11)“00 00”此處為附加信息(可選),和(4)中的size對應。
(12)“66 61 73 74” Fact是可選字段,一般當wav文件由某些軟件轉化而成,則包含該項,“04 00 00 00”Fact字段的大小為4字節,“F8 2F 14 00”是fact數據。
(13)“64 61 74 61”,這個是Ascii字符“data”,標示頭結束,開始數據區域。
(14)“F0 5F 28 00”十六進制數是“0x285ff0”,對應十進制2646000,是數據區的開頭,以后數據總數,看一下前面正好可以看到,文件大小是2646050,從(2)到(13)包括(13)正好是2646050-2646000=50字節。