我們生活中最常見的音頻壓縮算法就是我們的mp3,早些年大家都喜歡下載這種類型的音樂,一首歌3-4M字節(jié),空間占用少,畢竟那時(shí)候的MP3播放器還是256M或者512M的時(shí)候。
單片機(jī)中的音頻播放
音頻播放在小型單片機(jī)系統(tǒng)中也會(huì)經(jīng)常用到,最早我做的地鐵廣播系統(tǒng)中就是用的單片機(jī)播放的音頻。這人中音頻播放大體上有兩種方式,一種是使用vs1003這樣的外置模組來進(jìn)行數(shù)據(jù)解碼,另一種就是單片機(jī)自己解碼。單片機(jī)的運(yùn)算能力有限,因此靠單片機(jī)來計(jì)算MP3還是一項(xiàng)比較沉重的工作,所以,一般的小型系統(tǒng)中,我們往往不使用MP3格式的音頻,而是直接播放wav格式的音頻。說白了,wav格式就是純音頻數(shù)據(jù)存儲(chǔ),沒有進(jìn)行過壓縮的,也就意味著不需要解碼,這樣一來,單片機(jī)只需要將兩通道的音頻數(shù)據(jù)丟到IIS緩存區(qū)即可。沒有IIS外設(shè)的怎么辦?那就用DAC,12bit的DAC播放個(gè)音頻指示或人聲完全沒問題。什么?連DAC也沒有,讓我想想。。。那就用PWM吧,配置一個(gè)PWM,占空比可調(diào),具備10bit可調(diào)范圍的PWM,硬件方面,就在引腳上加一個(gè)RC濾波,一樣可以播放好聽的效果音樂。
PWM也沒有嗎?那也沒關(guān)系,有IO口就能搞,不過今天重點(diǎn)不是說這個(gè),重點(diǎn)是想說,這個(gè)wav文件還是有點(diǎn)大,我們需要對(duì)他做一些壓縮算法來存儲(chǔ)到我們可憐的Flash空間中。
音頻格式初探
ADPCM算法是一種針對(duì)16bit的聲音波形數(shù)據(jù)的一種有損的壓縮算法,他將聲音流中每次采樣的16bit數(shù)據(jù),轉(zhuǎn)變成4bit來存儲(chǔ),所以它的壓縮比為1:4。想想,音頻文件可以節(jié)省4倍,這得省好幾毛錢了,而且這種壓縮算法簡(jiǎn)單,51單片機(jī)就能輕松應(yīng)對(duì),因此這中壓縮算法是一種地空間消耗,高質(zhì)量音頻獲得的好途徑。ADPCM主要是針對(duì)連續(xù)的波形數(shù)據(jù),它保存的是波形的變化情況,以達(dá)到描述整個(gè)波形的目的。先科普一下音頻信號(hào)存儲(chǔ)的知識(shí)。
一般我們?cè)赑C機(jī)的游戲中或者公交車報(bào)站器中使用到的聲音,都是提前錄制好的,這種錄制就是一種模擬轉(zhuǎn)數(shù)字的過程,因此這里面涉及到了香濃的采樣定理。我們一般對(duì)于音頻的采樣率會(huì)設(shè)置在44.1Khz,根據(jù)香濃定律,我們可以還原出22KHz的聲音,這已經(jīng)是大多數(shù)人耳朵能分辨的頻率的上限了。也有異能人士可以聽到更高,或者跟老柴我一樣最高只能分辨到16KHz,因人而異吧。知道了采樣頻率,我們?cè)倏匆幌聦?duì)于一個(gè)升壓,我們需要將他量化存儲(chǔ),到底需要多少個(gè)bit才能表示真?zhèn)€聲音中的大大小小的賦值呢?這個(gè)一般我們音樂是按照16bit處理的,也不是想多高就能多高,還得看采樣的ADC強(qiáng)不強(qiáng)。有了一個(gè)一個(gè)的升壓賦值和采樣頻率,只要我們按照頻率把賦值送給揚(yáng)聲器,我們就可以聽到錄制的音樂了。在wav中,數(shù)據(jù)的存儲(chǔ)非常的簡(jiǎn)單粗暴,就一個(gè)挨著一個(gè)的放,所以我們定好時(shí)間挨著個(gè)的取數(shù)據(jù)就可以了。其實(shí),8bit的采樣深度就足夠人耳享用的了,比如win95的開機(jī)音樂。16bit就已經(jīng)算是高音質(zhì)了,現(xiàn)在很多游戲中采用16bit,單片機(jī)系統(tǒng)中,比如報(bào)站什么的8bit足夠了。有了聲音的基本存儲(chǔ),我們來看看如何壓縮。
ADPCM算法
因?yàn)槁曇粢话闶沁B續(xù)的,也就是頻率足夠快的情況下,前后兩個(gè)采樣值之間的差異會(huì)比較小。我們就利用這個(gè)特性來對(duì)數(shù)據(jù)進(jìn)行壓縮,也就是對(duì)兩次采樣值的差再做一次量化,由于這個(gè)差值比較小,因此我們可以使用更少的bit來存儲(chǔ),這樣就實(shí)現(xiàn)了壓縮的結(jié)果。
如上圖所示,直接存儲(chǔ)的方式中,我們存儲(chǔ)的數(shù)據(jù)是ABC三個(gè)16bit的數(shù)據(jù),如果按照ADPCM壓縮算法,我們存儲(chǔ)的將是相對(duì)值,也就是B-A,C-B這樣的更小的值,當(dāng)然重新播放的時(shí)候,我們要有一個(gè)初值。其實(shí)初值就是0,聲音怎么也得是慢慢變大的,不然喇叭受得了,你耳朵也受不了。接下來,我們看如何二次量化。如果我們想壓縮為4bit,那么也就是一共16個(gè)等級(jí),你可以平均分配,但顯然這樣做很不明智,有大神發(fā)明了兩種重新量化的定律,叫A Law和u Law。其實(shí)就是非線性量化,至于做成什么樣的非線性,這得研究人耳朵對(duì)音樂的敏感性了,不在我們討論范圍內(nèi)。我們來看一個(gè)圖,大致了解下兩個(gè)Law的不同。
乍一看其實(shí)沒太大區(qū)別,所以這種非線性量化其實(shí)也挺隨意的。由于信號(hào)量噪比的不恒定而影響信號(hào)質(zhì)量,為了對(duì)不同的信號(hào)強(qiáng)度保持信號(hào)量噪比恒定,在理論上要求壓縮特性為對(duì)數(shù)特性。為了使信號(hào)量噪比保持恒定,引入A壓縮律與μ壓縮律以及相應(yīng)的近似算法-13折線法和15折線法。一般來說,U律的15折線比A律的13折線,各個(gè)段落的斜率都相差2倍,所以小信號(hào)的信號(hào)量噪比也比A律大一倍,但是對(duì)于大信號(hào)來說,u律比a律差。無論哪個(gè)折線法,到我們寫程序的時(shí)候都變成了一個(gè)數(shù)組而已,我們就根據(jù)采樣值的差值落到那個(gè)區(qū)間內(nèi)來定義他的編碼值。最后我附上代碼,大家可以琢磨一下,需要詳細(xì)討論可以后臺(tái)私我,也可以加入我的星球討論。
代碼
壓縮:
int index = 0, prev_sample = 0;
while (還有數(shù)據(jù)要處理) {
cur_sample = getnextsample(); // 得到當(dāng)前的采樣數(shù)據(jù)
delta = cur_sample-prev_sample; // 計(jì)算出和上一個(gè)的增量
if(delta < 0) delta=-delta,sb=8;
else sb=0; // sb 保存的是符號(hào)位
code = 4*delta/step_table[index]; // 根據(jù) steptable[] 得到一個(gè) 0~7 的值
if (code > 7) code = 7; // 它描述了聲音強(qiáng)度的變化量
index += index_adjust[code]; // 根據(jù)聲音強(qiáng)度調(diào)整下次取steptable 的序號(hào)
if(index < 0) index=0; // 便于下次得到更精確的變化量的描述
else if (index > 88) index = 88;
prev_sample = cur_sample;
outputode(code|sb); // 加上符號(hào)位保存起來
}
解壓縮
int index = 0, cur_sample = 0; //信號(hào)從0開始,否則耳朵不保
while (還有數(shù)據(jù)要處理) {
code=getnextcode(); // 得到下一個(gè)數(shù)據(jù)
if ((code & 8) != 0) sb=1
else sb=0;
code &= 7; // 將 code 分離為數(shù)據(jù)和符號(hào)
delta=(step_table[index]*code) /4 + step_table[index] / 8;
// 后面加的一項(xiàng)是為了減少誤差
if (sb == 1) delta =- delta;
cur_Sample += delta; // 計(jì)算出當(dāng)前的波形數(shù)據(jù)
if (cur_sample > 32767) cur_sample = 32767;
else if (cur_sample < -32768) cur_sample = -32768;
output_sample(cur_sample);
index += index_adjust[code];
if (index < 0) index = 0;
if (index > 88) index = 88;
}
附表
int index_adjust[8] = {-1,-1,-1,-1,2,4,6,8};
int step_table[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };