在一般電腦平台上,常見音訊檔案的附檔名有 .wav、.au、.mp3、.aif等等,我們都可以使用 MATLAB 來直接讀取這幾種檔案,所用的指令是audioread。例如,若要讀取本章範例程式目錄內的檔案 welcome.wav、畫出音訊的波形並播放出此音訊,可使用下列程式:
在上例中,fs 是取樣頻率(sample rate),其值為 11025,代表當初在錄製這個音訊檔案時,每秒鐘會記錄下11025個聲音訊號的取樣值。而 y 是聲音訊號的向量,使用 sound(y, fs) 可播放出此音訊,所以你會聽到我的聲音「歡迎光臨」。time 則是對應在在時間軸的向量,因此將 y 對 time 做圖,就得到在時間軸上面的音訊波形。
事實上在錄製音訊檔案時,每一個取樣點大部分都是由8或16個位元(bits)所代表,若要知道 welcome.wav 的取樣點是由多少個位元來表示,可使用 audioinfo(‘welcome.wav’) 來回傳各種相關資訊,範例如下:
讀者可能會好奇,為什麼在 welcome.wav 音訊檔案中,每一個取樣點用 8 個位元來表示,但是從音訊波形來看,每一點的值都介於 –1 和 1 之間,這中間是如何轉換的?首先要知道 wav 檔案的 8 位元是以 unsigned integer(不帶符號的整數,即正整數)的方式來儲存,因此所能表示的數值是介於 0 和 255 (2^8-1) 之間,MATLAB 再將此值設定至變數 y 時,會自動將其數值調整至介於 –1 和 1 之間,因此若要將 MATLAB 讀出之數值轉回原先 8 位元所表示之數值,只要將變數 y 乘以 128,再加上 128,就可以得到原先的整數值,例如:
在上例中,變數 difference 的值是零,代表 y0 的值完全是整數。此外,為了增加程式碼的通用性,我們用 2^nbits/2,而不直接使用128。
MATLAB 對於音檔資料的正規化方式,可以列表如下:
音訊檔案內部儲存方式 數值範圍 MATLAB正規化方式 Unsigned 8-bit integer (uint8) y $\in$ [0, $2^8-1$] (y-$2^7$)/$2^7$ Signed 16-bit integer (int16) y $\in$ [$-2^{15}$, $2^{15}-1$] y/$2^{15}$ Signed 32-bit integer (int32) y $\in$ [$-2^{31}$, $2^{31}-1$] y/$2^{31}$ audioread 也可以讀取雙聲道或立體聲(Stereo)的音訊檔案,此時傳回的變數為具有兩直行的陣列,每一直行代表一個聲道的音訊,例如:
此範例會讀取雙聲道的音訊檔 flanger.wav,播放此雙聲道的音訊,並畫出兩個聲道的音訊波形。由於左右聲道的音量(即波形的震幅)相互消長,因此播放出來的效果,感覺好像音源在左右聲道之間游移。(小問題:給你一個單聲道的聲音訊號,你如何使用 MATLAB 對此音訊進行處理,最後產生原音訊在雙聲道之間游移的效果,如同此範例一般?)
如果音訊檔案很大,無法一次讀入記憶體,我們也可以使用 audioread 來讀出音訊檔的其中一部份,例如:
這一段波形代表「歡迎光臨」中的「迎」剛開始發音的波形。由上圖可看出,聲波的外型是很類似一個週期波,其震幅大小就代表音量大小,而其週期的倒數就是「基本頻率」。以上述圖形而言,1000個取樣點大概包含了10個週期,所以每個週期大約包含 100點,對應的時間是 100/fs = 100/11025 = 0.0091秒 = 9.1 ms,而基本頻率則是 1/0.0091 = 110.25 Hz,換算成鋼琴的按鍵,非常接近於中央 la (對應頻率是 440 Hz)降16度(兩個全音階)所得到的音,也就是下圖中的 A4(左邊數來第 5 個白鍵)。
300
人耳對聲音高低的感覺,是與基本頻率的對數成正比。以鋼琴的鍵盤而言,中央 la 的頻率是 440 Hz (Hertz),高八度的中央 la 則是 880 Hz,低八度的中央 la 則是 220 Hz。鋼琴中的每一個全音階包含7個白鍵與5個黑鍵,共有 12 個鍵,代表 12 個半音(semitones),以 MIDI 的標準而言,中央 la 的半音值是 69,對應頻率是 440 Hz,因此半音和頻率之間的轉換程式可寫成下列公式: $$semitone=69+12\log_2\left(\frac{Hz}{440}\right).$$
由一段聲音來求取其音高,在音訊處理上稱為音高追蹤(Pitch Tracking),是音訊處理很重要的一環,相關應用有語音合成、音調辨識、哼唱選歌等。
前面說明過,audioread 會將讀到的音訊壓縮在 -1 和 +1 之間,但如果你想讀取原來音訊儲存在音訊檔案中的原始資料,也可以,範例如下:
由上例可以看出,當我們加入 'native' 當成 audioread 的第三個參數時,所讀出的音訊就會是以原來檔案內的資料型態為準,因此本例中的音訊資料 y 的資料型態為 uint8,同時畫出的波形的震幅範圍也不再限於 -1 和 +1 之間。
MATLAB程式設計:入門篇![]()