在音頻軟件實現中經常會遇到兩個模塊采樣率不一致的情況,比如語音通話時采集到的PCM信號是16k Hz的,但編碼時codec是AMR-NB(AMR-NB是8k Hz采樣),這時就需要把16k Hz采樣的PCM值轉換成8k Hz采樣的PCM值(這叫降采樣或者下采樣),然后再去做AMR-NB編碼。再比如音樂播放時音源是44.1k Hz采樣率編碼的,但是播放時是48k Hz采樣率的,這就需要把解碼后的44.1k Hz采樣率的PCM值轉換成48k Hz采樣的PCM值(這叫升采樣或者上采樣),然后再送給codec芯片播放。采樣率轉換(sampling rate converter, SRC)或者叫重采樣有多種方法,簡單的有線性插值法(算法簡單,load小,但性能一般),復雜的有sinc方法(算法復雜,load大,但性能較好)。好多的音頻類開源代碼里都有重采樣的實現,比如PJSIP和FFMPEG。重采樣的原理這里就不詳細介紹了,有興趣的可以看相關文章。今天我們講的是如何去評估這些開源代碼里的重采樣實現以及選擇最適合的實現。評估主要基於頻響特性,其次看CPU load。評估的開源實現是我用過的PJSIP和SILK codec。PJSIP里的重采樣有兩種實現(線性插值和sinc),通過開關控制選用哪種。SILK里的重采樣用的是三次插值方法。對其他開源實現的評估類似。
在評估前先要做一些准備工作,包括用CoolEdit生成10秒的掃頻文件和包含重采樣算法的應用程序。掃頻文件作為應用程序的輸入,輸出就是重采樣后的PCM文件,再看它的頻譜特性。以下就是制作掃頻文件的步驟:
1,在CoolEdit里新建一個指定采樣率單聲道的文件。如下圖,采樣率指定為16k Hz。
2,選中“生成”菜單里的“音調”,把“固定設置”√去掉,就變成了“初始設置”和“結束設置”。先初始設置,由於是16k Hz采樣率,頻率范圍是50~7k Hz,在初始設置中設置基礎頻率為50Hz,同時設置持續時間為10秒,如下圖:
再選擇“結束設置”,設置基礎頻率為8k Hz,其他用默認設置,選擇“確定”(如下圖),一個掃頻文件就做好了。
3,點擊“頻譜”按鈕可以看到一個從50Hz到8000Hz 頻譜都非常好的掃頻文件,如下圖:
掃頻文件這樣就做好了。再做重采樣應用程序,各種系統下都可以做,我一般是在Ubuntu下做,比較簡單,這里就不具體說了。掃頻文件和重采樣應用程序都做好后就開始評估了。我當時應用的場景是播放側固定成48k采樣,要把8k/16k/44.1k等升采樣到48k。做了三個掃頻文件,8k采樣/16k采樣/44.1k采樣。先看SILK里的重采樣和PJSIP里的線性插值方法在8k->48k和16k->48k下的表現,具體如下:
1,8k轉48k: 初始是8k 窄帶采樣,范圍是300~ 3400, 我做的掃頻文件頻率范圍是200~4000. 原始掃頻文件頻譜如下:
1)pjsip 的線性插值方法,把掃頻文件從8000上采樣到48000,得到PCM文件頻譜如下:
2)silk 的三次插值方法,把掃頻文件從8000上采樣到48000,得到PCM文件頻譜如下:
從上面兩圖看出,上采樣后頻譜特性不好了。
2,16k轉48k: 初始是16k 寬帶采樣,范圍是50~7000, 我做的掃頻文件頻率范圍是50~8000. 原始掃頻文件頻譜如下:
1)pjsip 的線性插值方法,把掃頻文件從16000上采樣到48000,得到PCM文件頻譜如下:
2)silk 的三次插值方法,把掃頻文件從16000上采樣到48000,得到PCM文件頻譜如下:
從上面兩圖看出,上采樣后頻譜特性也不好了。
再看PJSIP里的sinc方法在44.1k->48k下的表現。用sinc方法也有兩種選擇,分別是large_filter(濾波器個數達到8192個,load大)和small_filter(濾波器個數達到1536個,load相對小)。具體如下:44.1k轉48k,范圍是20~20000, 我做的掃頻文件頻率范圍是20~20000. 原始掃頻文件頻譜如下:
1)large_filter下變成48000Hz的文件頻譜,如下圖:
2)small_filter下變成48000Hz的文件頻譜,如下圖:
從上面兩圖看出,用large_filter的since上采樣后頻譜特性依舊很好,用small_filter的since上采樣后頻譜特性在高頻時有些不好。
從上面的頻譜特性可以看出在播放側做上采樣到48k時最好用sinc的large_filter方法,它的頻譜特性最好,但是load會非常高。sinc的small_filter方法頻譜特性次之,只在高頻時有點差,可接受。線性插值方法的頻譜特性就不太好了。綜上在這種情況下如果CPU load 不是問題就可用sinc的large_filter方法,如果CPU load 扛不住就用sinc的small_filter方法,線性插值方法由於頻譜特性不好不建議用。我們當時是在400MHz的處理器上上做實現, load較為敏感,最終選擇了sinc的small_filter方法。
至於其他的場景,方法類似,就不多說了。最后說一句,sinc方法是目前公認的最好的音頻重采樣方法,就是CPU load有點高,可以通過選擇濾波器個數少或者優化的方法解決。