如果通過Arduino進行錄音不是單純地接一個駐極電容MIC就可以的,因為自然界中的聲音非常復雜,波形極其復雜,通常我們采用的是脈沖代碼調制編碼。即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續變化的模擬信號轉換為數字編碼。在開始動手之前我們需要先了解一些關於數字編碼的基礎知識。
采樣-采樣率
在音頻采集中叫做采樣率。
由於聲音其實是一種能量波,因此也有頻率和振幅的特征,頻率對應於時間軸線,振幅對應於電平軸線。波是無限光滑的,弦線可以看成由無數點組成,由於存儲空間是相對有限的,數字編碼過程中,必須對弦線的點進行采樣。采樣的過程就是抽取某點的頻率值,很顯然,在一秒中內抽取的點越多,獲取得頻率信息更豐富,為了復原波形,一次振動中,必須有2個點的采樣,人耳能夠感覺到的最高頻率為20kHz,因此要滿足人耳的聽覺要求,則需要至少每秒進行40k次采樣,用40kHz表達,這個40kHz就是采樣率。 我們常見的CD,采樣率為44.1kHz。
量化-采樣大小
光有頻率信息是不夠的,我們還必須獲得該頻率的能量值並量化,用於表示信號強度。采樣大小就是量化的過程,將該頻率的能量值並量化,用於表示信號強度。
量化電平數為 2的整數次冪,我們常見的CD位16bit的采樣大小,即2的16次方。
采樣大小相對采樣率更難理解,因為要顯得抽象點,舉個簡單例子:假設對一個波進行8次采樣,采樣點分別對應的能量值分別為A1-A8,但我們只使用 2bit的采樣大小,結果我們只能保留A1-A8中4個點的值而舍棄另外4個。如果我們進行3bit的采樣大小,則剛好記錄下8個點的所有信息。采樣率和 采樣大小的值越大,記錄的波形更接近原始信號。
采樣率和采樣大小/比特率
采樣率和比特率就像是坐標軸上的橫縱坐標。
橫坐標的采樣率表示了每秒鍾的采樣次數。 縱坐標的比特率表示了用數字量來量化模擬量的時候的精度。
采樣率類似於動態影像的幀數,比如電影的采樣率是24赫茲,PAL制式的采樣率是25赫茲,NTSC制式的采樣率是30赫茲。當我們把采樣到的一個個靜止畫面再以采樣率同樣的速度回放時,看到的就是連續的畫面。同樣的道理,把以44.1kHZ采樣率記錄的CD以同樣的速率播放時,就能聽到連續的聲音。顯然,這個采樣率越高,聽到的聲音和看到的圖像就越連貫。當然,人的聽覺和視覺器官能分辨的采樣率是有限的,基本上高於44.1kHZ采樣的聲音,絕大部分人已經覺察不到其中的分別了。
而聲音的位數就相當於畫面的顏色數,表示每個取樣的數據量,當然數據量越大,回放的聲音越准確,不至於把開水壺的叫聲和火車的鳴笛混淆。同樣的道理,對於畫面來說就是更清晰和准確,不至於把血和西紅柿醬混淆。不過受人的器官的機能限制,16位的聲音和24位的畫面基本已經是普通人類的極限了,更高位數就只能靠儀器才能分辨出來了。比如電話就是3kHZ取樣的7位聲音,而CD是44.1kHZ取樣的16位聲音,所以CD就比電話更清楚。
當你理解了以上這兩個概念,比特率就很容易理解了。以電話為例,每秒3000次取樣,每個取樣是7比特,那么電話的比特率是21000。而CD是每秒 44100次取樣,兩個聲道,每個取樣是13位PCM編碼,所以CD的比特率是44100213=1146600,也就是說CD每秒的數據量大約是 144KB,而一張CD的容量是74分等於4440秒,就是639360KB=640MB。
比特率這個詞有多種翻譯,比如碼率等,表示經過編碼(壓縮)后的音頻數據每秒鍾需要用多少個比特來表示,而比特就是二進制里面最少的單位,要么是 0,要么是1。比特率與音頻壓縮的關系簡單的說就是比特率越高音質就越好,但編碼后的文件就越大;如果比特率越少則情況剛好翻轉。
編碼
根據采樣率和采樣大小可以得知,相對自然界的信號,音頻編碼最多只能做到無限接近,至少目前的技術只能這樣了,相對自然界的信號,任何數字音頻編碼方案都是有損的,因為無法完全還原。在計算機應用中,能夠達到最高保真水平的就是PCM編碼,被廣泛用於素材保存及音樂欣賞,CD、DVD以及我們常見的WAV文件中均有應用。因此,PCM約定俗成了無損編碼,因為PCM代表了數字音頻中最佳的保真水准,並不意味着PCM就能夠確保信號絕對保真,PCM也只能做到 最大程度的無限接近。我們而習慣性的把MP3列入有損音頻編碼范疇,是相對PCM編碼的。強調編碼的相對性的有損和無損,是為了告訴大家,要做到真正的無損是困難的,就像用數字去表達圓周率,不管精度多高,也只是無限接近,而不是真正等於圓周率的值
為什么要使用音頻壓縮技術
要算一個PCM音頻流的碼率是一件很輕松的事情,采樣率值×采樣大小值×聲道數bps。一個采樣率為44.1KHz,采樣大小為16bit,雙聲道的PCM編碼的WAV文件,它的數據速率則為 44.1K×16×2 =1411.2 Kbps。我們常說128K的MP3,對應的WAV的參數,就是這個1411.2 Kbps,這個參數也被稱為數據帶寬,它和ADSL中的帶寬是一個概念。將碼率除以8,就可以得到這個WAV的數據速率,即176.4KB/s。這表示存儲一秒鍾采樣率為44.1KHz,采樣大小為16bit,雙聲道的PCM編碼的音頻信號,需要176.4KB的空間,1分鍾則約為10.34M,這對大部分用戶是不可接受的,尤其是喜歡在電腦上聽音樂的朋友,要降低磁盤占用,只有2種方法,降低采樣指標或者壓縮。降低指標是不可取的,因此專家們研發了各種壓縮方案。由於用途和針對的目標市場不一樣,各種音頻壓縮編碼所達到的音質和壓縮比都不一樣,在后面的文章中我們都會一一提到。有一點是可以肯定的,他們都壓縮過。
頻率與采樣率的關系
采樣率表示了每秒對原始信號采樣的次數,我們常見到的音頻文件采樣率多為44.1KHz,這意味着什么呢?假設我們有2段正弦波信號,分別為20Hz和 20KHz,長度均為一秒鍾,以對應我們能聽到的最低頻和最高頻,分別對這兩段信號進行40KHz的采樣,我們可以得到一個什么樣的結果呢?結果是:20Hz的信號每次振動被采樣了40K/20=2000次,而20K的信號每次振動只有2次采樣。顯然,在相同的采樣率下,記錄低頻的信息遠比高頻的詳細。這也是為什么有些音響發燒友指責CD有數碼聲但不夠真實的原因,CD的44.1KHz采樣也無法保證高頻信號被較好記錄。要較好的記錄高頻信號,看來需要更高的采樣率,於是有些朋友在捕捉CD音軌的時候使用48KHz的采樣率,這是不可取的!這其實對音質沒有任何好處,對抓軌軟件來說,保持和CD提供的44.1KHz一樣的采樣率才是最佳音質的保證之一,而不是去提高它。較高的采樣率只有相對模擬信號的時候才有用,如果被采樣的信號是數字的,請不要去嘗試提高采樣率。
流特征
隨着網絡的發展,人們對在線收聽音樂提出了要求,因此也要求音頻文件能夠一邊讀一邊播放,而不需要把這個文件全部讀出后然后回放,這樣就可以做到不用下載就可以實現收聽了。也可以做到一邊編碼一邊播放,正是這種特征,可以實現在線的直播,架設自己的數字廣播電台成為了現實。
像這么一個曲線,就可以用來描述振膜隨時間變化的關系了。但是想要描述這樣的一個曲線,我們並沒有辦法來描述它,除非我們這樣說:“呃,這個曲線它上來了,然后又下去了,再上來,再下去...”顯然這么描述是不可能的。那么怎么辦?人們想了這么一個辦法:
每隔一個小小的時間間隔,去用尺子量一下這個點的位置在哪里。那么只要這個間隔是一定的,我們就可以把這個曲線描述成:{9,11,12,13,14,14,15,15,15,14,14,13,12,10,9,7...}這樣描述是不是比剛才的方法要精確多了?而且更美妙的是,如果我們把這個時間間隔取得更小,拿的尺子越精確,那么測量得到的,用來描述這個曲線的數字也可以做到更加地精確。用專業的術語來說,我們每兩次測一下位置的時間間隔,就是所謂的采樣率。采樣率等於多少,就意味着我們每秒鍾進行了多少次這樣的測量。
假設你用萬用表去量一秒鍾麥克風傳來的模擬電信號,量的次數越多,越能反映聲音的真實情況,量的數值編程二進制就成了數字信號
采樣率(sampling rate)高,就能保真原信號中越高頻的成份。但是,頻率高過一定值的聲音人耳是分辨不出的,因此采樣率太高沒有必要。采樣率的單位是Hz或S/s(samples per second),這兩個單位是一樣的。平時所說的16-bit和24-bit不是采樣率,而是分辨率(resolution)。它是指聲音的連續強度被數字化之后分為多少級。N-bit的意思聲音的強度被均分為2^N級。16-bit的話,就是65535級。這是一個很大的數了,人可能也分辨不出六萬五千五百三十五分之一的音強差別。也就是說,采樣率針對的是信號的時間(頻率)特性,而分辨率針對的是信號的強度特性,這是兩個不一樣的概念。
好了,講了一大堆的理論也是時候講講應該如何來實現了,本文是基於Arduino來實現這個功能,而Arduino是沒有PCM解碼模塊的但架不住它便宜學習曲線又低。費話不多說了先來看看本文的主角吧:
MAX9814是個錄音放大模塊,本文會使用它與Arduino連接將錄音生成一個wav文件保存到SD上,當然也可以進行直接的播放。我們的目標是使用它進行聲音的采樣。
另外,如果用ESP8266可以不使用SD卡模塊直接將文件存到雲。
BOM
- MAX9814 模塊
- MicroSDCard 模塊
- Arduino Uno
線路圖
代碼
這里我使用了一個叫TMRpcm的庫,這個庫在Arduino上非常好用,它本來是做軟DAC用的,可以用來擴展Arduino進行直接的聲音解碼播放。
注: TMRpcm里面有一個用於錄音的方法,源碼中是被注釋掉的,在安裝該庫之后需要打開源碼庫中的
pcmConfig.h
文件將以下的行取消注釋,否則會編譯不通過:#define buffSize 128. May need to increase. #define ENABLE_RECORDING #define BLOCK_COUNT 10000UL
以下是 Arduino 代碼:
#include <SD.h>
#include <SPI.h>
#include <TMRpcm.h>
#define SD_ChipSelectPin 10 // 如果使用 arduino nano 328 可使用Pin4
TMRpcm audio;
void setup() {
audio.speakerPin = 4;
Serial.begin(115200);
if (!SD.begin(SD_ChipSelectPin)) {
Serial.println("SD Fail");
return;
}else{
Serial.println("SD OK");
}
audio.CSPin = SD_ChipSelectPin;
}
void loop() {
if(Serial.available()){
char c = Serial.read();
Serial.println(c);
switch(c){
case 'r': audio.startRecording("test.wav",16000,A0); break; //以16khz的采樣率開始錄音
case 'R': audio.startRecording("test.wav",16000,A0,1); break; //錄音並直接進行回放
case 't': audio.startRecording("test.wav",16000,A0,2); break; //將錄音直接進行回放
case 's': audio.stopRecording("test.wav"); break; //停止錄音
case 'p': audio.play("test.wav"); break; //回放錄音
case '=': audio.volume(1); break; //增加音量
case '-': audio.volume(0); break; //減小音量
case 'S': audio.stopPlayback(); break; //停止所有的回放
}
}
}
將以上代碼寫入Arduino后需要打開串口監視器運行,由於以上代碼是一個互操作代碼所以你需要通過串口監視器向Arduino發送文字指令。