痞子衡嵌入式:PCM編碼與Waveform音頻文件(.wav)格式詳解


  你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是PCM編碼及Waveform音頻文件格式html

  嵌入式裏有時候也會和音頻打交道,好比最近特別火的智能音箱產品,離不開前端的音頻信號採集、降噪,中間的語音識別(ASR)、天然語言處理(NLP),以及後端的文語合成(TTS)、音頻播放。音頻信號採集是處理聲音的第一步,要採集音頻就離不開PCM編碼,音頻採集完成天然須要保存,waveform格式(.wav)是一種最經典的音頻文件格式。今天痞子衡就給你們詳細介紹PCM編碼以及waveform文件格式。前端

1、聲音基礎

  衆所周知,聲音是由物體振動產生的聲波,聲音經過介質(空氣或固體、液體)傳播並能被人聽覺器官所感知。發音物體狀況(材料,距離,振動強度等)不一樣,產生的聲音也不一樣。爲了區分不一樣的聲音,咱們主要用以下三個參數來描述聲音的特徵:git

  • 音量:人主觀上感受到的聲音大小(也叫響度),由「振幅」(amplitude)和人離聲源的距離決定。
  • 音調:聲音的高低(高音、低音),由「頻率」(frequency)決定,頻率越高音調越高。
  • 音色:音色是一種抽象的東西,波形決定了聲音的音色。聲音因不一樣發聲物體材料而具備不一樣特性,波形是把這個抽象特性直觀的表現出來。典型的音色波形有方波,鋸齒波,正弦波,脈衝波等。

  三大參數裏除了音色沒有度量單位外(能夠認爲音色是聲音的UID,每種音色都是獨一無二的),音量和音調均有度量單位,這意味着音量和音調是可調整的,也是聲音之間可對比的特徵參數。後端

1.1 音量單位-分貝(dB)

  聲波是一種機械波(壓力波)。聲波(空氣質點)的連續振動,使空氣分子不斷交替的壓縮和鬆弛,使大氣壓迅速產生起伏,這種氣壓的起伏部分,就稱爲聲壓。聲壓的振幅表示質點離開平衡位置的距離,反映從波形波峯到波谷的壓力變化,以及波所攜帶的能量的多少。
  聲壓值雖然能夠反映音量大小,但人們平常生活中遇到的聲音,若以聲壓值表示,變化範圍很是大(達到六個數量級以上),而且人體聽覺對聲信號強弱刺激反應不是線形的,而是成對數比例關係。所以音量並非聲壓值來計量,而是用分貝來計量,首先來看分貝計算的標準公式:app

NdB = 10 * log10 (Pi / Po)編輯器

  上述公式中Po爲基準聲壓值,NdB便是聲壓信號Pi對基準聲壓Po的分貝值。從公式能夠看出分貝是指兩個相同類型物理量(Pi、Po)的比較結果,它是無量綱的。分貝又稱爲被量度量Pi的"級",它表明被量度量比基準量高出多少"級"。下面列舉常見分貝值:ide

分貝值 人耳感受
1dB 剛能聽到的聲音
1 - 15dB 感受很是安靜
20 - 40dB 耳語音,冰箱的嗡嗡聲
40 - 60dB 室內正常交談的聲音
60 - 70dB 走在鬧市區的感受,有點吵
70 - 85dB 汽車穿梭在馬路上,85dB是保護聽力的通常要求
85 - 100dB 摩托車啓動,裝修電鑽
100 - 150dB 飛機起飛、燃放煙花爆竹

1.2 音調單位-頻率(Hz)

  頻率是每秒通過一給定點的聲波週期數量,其單位是Hz,1KHz表示每秒通過一給定點的聲波有1000個週期。根據頻率範圍,咱們將聲波分爲以下三種:svg

聲波類別 頻率範圍 特性與應用
次聲波 低於20Hz 部分動物(狗、大象)能發出/感知,經常使用於天然災害監測
可聞聲 20Hz ~ 20KHz 人的聽覺感知範圍
超聲波 高於20KHz 部分動物(狗、蝙蝠)能發出/感知,經常使用於深海探測(聲吶)、醫學檢查(B超)

  關於聲波頻率特別要提的是,聲波能夠被分解爲不一樣頻率不一樣強度正弦波的疊加,這種變換(或分解)的過程,稱爲傅立葉變換(Fourier Transform)工具

2、PCM編碼原理

  聲波是一種在時間上和振幅上均連續的模擬量,在嵌入式裏要想研究聲波,首先須要將聲波轉換成一連串電壓變化的模擬電信號,麥克風器件就是一種採集聲波信號並將其轉換成模擬電壓信號輸出的裝置。
  有了聲波的模擬電壓信號,下一步須要將模擬信號數字化,即將模擬信號通過模數轉換器(A/D)後變成數字信號,說白了就是將聲音數字化。最多見的聲音數字化方式就是脈衝編碼調製PCM(Pulse Code Modulation),PCM是70年代末發展起來的技術,最先應用於由飛利浦和索尼公司共同推出的CD上,下圖給出了PCM編碼全過程:動畫

  從上圖中咱們能夠看到PCM編碼主要有三個過程:採樣、量化、編碼,在這過程當中主要有4個參數用於評價PCM:聲道數、採樣率、量化位數、編碼方式。痞子衡會在下面逐一介紹PCM編碼過程時穿插介紹這4個參數:

2.1 採樣

  所謂採樣,即按必定的採樣頻率將模擬信號變成時間軸上離散的抽樣信號的過程。原則上採樣頻率越高,聲音的質量也就越好,聲音的還原也就越真實。
  採樣率即每秒從模擬信號中提取並組成離散信號的採樣個數,用赫茲(Hz)來表示。說到採樣率有一個不得不提的著名定律,即香農(Shannon)/奈奎斯特(Nyquist)採樣定律,該定律代表採樣頻率必須大於或等於所傳輸的模擬信號的最高頻率的2倍,才能不失真地恢復模擬信號

最常說的「無損音頻」,通常都是指傳統CD格式中的44.1kHz/16bit的文件格式,而之因此稱爲無損壓縮,是由於其包含了20Hz-22.05kHz這個徹底覆蓋人耳可聞範圍的聲音頻率而得名。

  關於聲道數,其實很是好理解,就是採集聲音的通道數,咱們知道有單聲道(mono),立體聲(雙聲道stereo)、杜比7.1環繞聲,其實就是聲音採集的通道數有差異,聲道越多,越能體現聲音的空間立體效果。

2.2 量化

  前面採樣獲得的抽樣信號雖然是時間軸上離散的信號,但仍然是模擬信號,其採樣值在必定的取值範圍內,可有無限多個值,必須採用「四捨五入」的方法把樣值分級「取整」,使必定取值範圍內的樣值由無限多個值變爲有限個值,這一過程稱爲量化。
  量化位數指的是描述數字信號所使用的位數。如麥克風採集的電壓範圍爲0-3.3V,8bit的量化精度爲3.3V/256,16bit的量化精度爲3.3V/65536。

2.3 編碼

  量化後的抽樣信號就轉化爲按抽樣時序排列的一串十進制數字碼流,即十進制數字信號。簡單高效的數據系統是二進制碼系統,所以,應將十進制數字碼變換成二進制編碼,這種把量化的抽樣信號變換成給定字長(量化位數)的二進制碼流的過程稱爲編碼。
  編碼方式種類很是多,其對比可見 Comparison of audio coding formats,PCM音頻格式編碼常見有四種:PCM(Linear PCM)、ADPCM(Adaptive differential PCM)、 A-law(A律13折線碼)、μ-law(μ律15折線碼),最簡單的固然是下圖所示的LPCM(示例爲4bit),這是一種均勻量化編碼,普遍用於 Audio CD, AES3, WAV, AIFF, AU, M2TS, VOB中。

  除LPCM外,A-law和μ-law是兩種不得不提的非均勻量化編碼,這兩種非均勻量化編碼是爲了提升小信號的信噪比,其基本思想是在量化以前先讓信號通過一次處理,對大信號進行壓縮而對小信號進行較大的放大,這一處理過程一般也稱爲「壓縮量化」。壓縮量化的實質是「壓大補小」,使小信號在整個動態範圍內的信噪比基本一致。下面是這兩種編碼與LPCM的 對比圖

3、Waveform文件格式解析

  前面講的PCM編碼後的聲音數據是須要保存的,WAVE文件經常用來保存PCM編碼數據。WAVE文件是微軟公司(Microsoft)開發的一種聲音文件格式,用於保存Windows平臺的音頻信息資源,被Windows平臺及其應用程序所普遍支持,WAVE文件默認打開工具是WINDOWS的媒體播放器。

3.1 RIFF文件格式標準

  WAVE文件是以微軟RIFF格式爲標準的,RIFF全稱爲資源互換文件格式(Resources Interchange File Format),是Windows下大部分多媒體文件遵循的一種文件結構。RIFF文件所包含的數據類型由該文件的擴展名來標識,能以RIFF格式存儲的數據有不少:音頻視頻交錯格式數據(.AVI)、波形格式數據(.WAV)、位圖數據格式(.RDI)、MIDI格式數據(.RMI)、調色板格式(.PAL)、多媒體電影(.RMN)、動畫光標(.ANI)等。
  以下代碼所示的CK結構體是RIFF文件的基本單元,該基本單元也稱 Chunk。其中ckID用於標識塊中所包含的數據類型,其取值可有'RIFF'、'LIST'、'fmt '、'data'等;ckSize表示存儲在ckData域中的數據長度(不包含ckID和ckSize的大小);ckData存儲數據,數據以字節爲單位存放,若是數據長度爲奇數,則最後添加一個空字節。

因爲RIFF文件結構最初是由Microsoft和IBM爲PC機所定義,RIFF文件是按照小端little-endian字節順序寫入的。

typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef DWORD         FOURCC;    // Four-character code

typedef struct { 
     FOURCC ckID;          // The unique chunk identifier 
     DWORD ckSize;         // The size of field <ckData> 
     BYTE ckData[ckSize];  // The actual data of the chunk 
} CK;

  Chunk是能夠嵌套的,可是隻有ckID爲'RIFF'或者'LIST'的Chunk才能包含其餘的Chunk。標誌爲'RIFF'的Chunk是比較特殊的,每個RIFF文件首先存放的必須是一個'RIFF' Chunk,而且只能有這一個標誌爲'RIFF'的Chunk。

  更多RIFF的知識詳見這個網站連接 RIFF (Resource Interchange File Format),連接裏收集了不少介紹RIFF的資源。

3.2 WAVE文件結構

  WAVE是Microsoft開發的一種音頻文件格式,它符合上面提到的RIFF文件格式標準,能夠看做是RIFF文件的一個具體實例。既然WAVE符合RIFF規範,其基本的組成單元也是Chunk。一個 WAVE文件 一般有三個Chunk以及一個可選Chunk,其在文件中的排列方式依次是:RIFF Chunk,Format Chunk,Fact Chunk(附加塊,可選),Data Chunk,以下圖所示:

  根據上面的WAVE文件結構圖,能夠定義以下44bytes的wave_head_t用來描述WAVE文件的頭。若是你曾經接觸過Windows的音頻接口API,你會發現wave_fmt_t中的部分結構與標準MSDN裏的 WAVEFORMAT 是一致的。

typedef char    int8_t;    //有符號8位整數
typedef short   int16_t;   //有符號16位整數
typedef int     int32_t;   //有符號32位整數

struct _wave_tag
{
    int8_t     riff[4];            //"RIFF",資源交換文件標誌
    int32_t    filesize;           //文件大小(從下個地址開始到文件尾的總字節數)
    int8_t     wave[4];            //"WAVE",文件標誌
} wave_tag_t;
struct _wave_format
{
    int8_t     fmt[4];             //"fmt ",波形格式標誌 
    int32_t    chunksize;          //文件內部Chunk信息大小
    int16_t    wFormatTag;         //音頻數據編碼方式
    int16_t    wChanles;           //聲道數
    int32_t    nSamplesPerSec;     //採樣率
    int32_t    nAvgBytesPerSec;    //波形數據傳輸速率(每秒平均字節數)
    int16_t    nBlockAlign;        //數據的調整數(按字節計算)
    int16_t    wBitsPerSample;     //樣本數據位數
} wave_fmt_t;
struct _wave_data
{
    int8_t     data[4];            //"data",數據標誌符
    int32_t    datasize;           //採樣數據總長度
} wave_dat_t;

struct _wave_head
{
    wave_tag_t   waveTag;
    wave_fmt_t   waveFmt;
    wave_dat_t   waveDat;
} wave_head_t;

  wave_head_t結構體內除了wFormatTag成員以外,其餘均可以根據字面上的意思來理解。關於wFormatTag的具體定義,可見Windows SDK裏的 mmreg.h文件,下面列舉了幾個最多見Format的Tag值定義:

  當WAVE文件的頭被解析成功後,下一步即是獲取WAVE文件裏的聲音源數據,咱們知道聲音文件有單聲道和多聲道之分,對於單聲道文件很好理解,聲音數據就是按序排放,而若是是立體聲(2聲道)文件,那麼左右聲道的聲音數據究竟是怎麼排放的呢?下面以一個示例立體聲文件數據(僅分析前72bytes)進行解釋:

offset(h)
00000000: 52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20
00000010: 10 00 00 00 01 00 02 00 22 56 00 00 88 58 01 00
00000020: 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
00000030: 24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6
00000040: 3c f2 24 f2 11 ce 1a 0d

  下圖是這個72bytes數據解析圖,從圖中能夠看到,左右聲道的聲音數據是按塊(nBlockAlign指定)交替排放的。

  更多WAVE的知識詳見這兩個網站連接 WAVE Audio File FormatAudio File Format Specifications,連接裏收集了不少介紹WAVE的資源。

3.3 WAVE文件實例分析

  WAVE文件格式咱們都瞭解透徹了,下面咱們嘗試分析一個經典的WAVE文件:"Windows XP 啓動.wav",這個文件能夠說是最知名的WAVE文件了,痞子衡特別喜歡這段music,讓咱們直接用二進制編輯器HxD打開它:

  按wave_head_t解析WAVE頭可知,這段wave是44.1kHz/16bit雙聲道線性PCM碼音頻,實際音頻數據總長度爲1361076bytes(1361076(datasize)/176400(nAvgBytesPerSec)=7.7158秒),最後再用Adobe Audition(原Cool Edit)打開查看其波形圖:

  至此,PCM編碼及Waveform音頻文件格式痞子衡便介紹完畢了,掌聲在哪裏~~~

相關文章
相關標籤/搜索