基於傅裏葉變換的音頻重采樣算法 (附完整c代碼)
前面有提到音頻采樣算法:
WebRTC 音頻采樣算法 附完整C++示例代碼
簡潔明了的插值音頻重采樣算法例子 (附完整C代碼)
近段時間有不少朋友給我寫過郵件,說了一些他們使用的情況和問題。
坦白講,我精力有限,但一般都會抽空回復一下。
大多數情況,閱讀一下代碼就能解決的問題,
也是要嘗試一下的。
沒準,你就解決了呢?
WebRtc的采樣算法本身就考慮到它的自身應用場景,
所以它會有一些局限性,例如不支持任意采樣率等等。
而簡潔插值的這個算法,
我個人也一直在使用,因為簡潔明了,簡單粗暴。
我自然也就沒有進一步去細究采樣算法,
當然網上還有不少開源的采樣算法也是極其不錯的。
一直也想抽時間再做一個兼顧簡潔和質量的算法出來,不了了之。
最近一直在死磕傅裏葉變換,網上的資源看了一籮筐。
徘徊到最後,毫無疑問FFTW3必須是你的首選,
從歲數性能以及使用的概率來說,當之無愧的王者。
當然也順帶整理一下,其他的一些FFT實現,各有優劣。
用於學習,作為參考資料也是不二之選。
有興趣的小夥伴,可以參閱之.
https://github.com/cpuimage/StockhamFFT
https://github.com/cpuimage/uFFT
https://github.com/cpuimage/BluesteinCrz
https://github.com/cpuimage/fftw3
當然最佳的參考資料,還是fftw3,
我的這個git做了以下工作:
1.梳理調整目錄結構
2.移除一些影響閱讀調試,讓人頭大的宏定義
3.合並代碼至fftw_api.c,移除一些不常用的代碼
註意:未經過嚴格測試驗證
也許這個git存在的意義在於方便眾人閱讀學習fftw的算法思路,
以及調試,扣代碼等等諸如此類的行為。
所以有需要的同學可以,參考之。
回到本次的主題,
在以前做圖像算法的時候,就一直在想一個問題,
是否可以利用傅裏葉變換的特性進行圖像的重采樣呢?
這個一直是我心中的一個小石頭,一直沒放下。
從理論上來說,可行的,只是估計最終質量並不能保證。
最佳的嘗試莫過於音頻重采樣,在很多時候,
我們經常需要對一個音頻進行傅裏葉變換,然後進行上采樣或下采樣的操作。
那是不是可以直接就在頻域進行重采樣呢?
這樣的做法是不是質量就能有所保障呢?
事實證明,這是可行的。
經過簡單試驗,基於傅裏葉變換的音頻重采樣算法就這樣出爐了。
目前示例采用hsfft 這個開源傅裏葉變換進行驗證,
沒有采用fftw3的原因也很簡單,因為fftw3編譯器來有點麻煩。
而hsfft的函數風格與fftw3類似,只是速度性能上不及fftw3而已。
這樣也符合我的要求,真正應用的時候再使用fftw3替換之即可,
在驗證思路的時候,沒必要動用fftw3,
這也是我為什麽使用簡潔重采樣的原因之一。
每個步驟都要有策略和方法,不必太過較真。
如果特定情況下需要,我也可以上matlab,python,delphi,c#,c++等等。
語言只是工具,關鍵還是思路和思想。
貼上主要代碼:
#ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif void FFTResample(float *input, float *output, int sizeIn, int sizeOut) { fft_t *fftin = (fft_t *) calloc(sizeof(fft_t), sizeIn); fft_t *fftout = (fft_t *) calloc(sizeof(fft_t), sizeOut); if (fftin == NULL || fftout == NULL) { if (fftout) free(fftout); if (fftin) free(fftin);
return; } fft_real_object fftPlan = fft_real_init(sizeIn, 1); fft_r2c_exec(fftPlan, input, fftin); free_real_fft(fftPlan); int halfIn = (sizeIn / 2) + 1; int halfOut = (sizeOut / 2) + 1; for (int i = 0; i < MIN(halfIn, halfOut); ++i) { fftout[i].re = fftin[i].re; fftout[i].im = fftin[i].im; } fft_real_object ifftPlan = fft_real_init(sizeOut, -1); fft_c2r_exec(ifftPlan, fftout, output); free_real_fft(ifftPlan); float norm = 1.f / sizeIn; for (int i = 0; i < sizeOut; ++i) { output[i] = (output[i] * norm); } free(fftout); free(fftin); }
算法非常簡單,用一句時髦的語言來描述這個算法,就是“多退少補“。
需要補課FFT的可以移步:
從多項式乘法到快速傅裏葉變換
項目地址:
https://github.com/cpuimage/fftResample
采用Cmake編譯即可,示例代碼也很簡潔。
不多做解釋了~
以上,權當拋磚引玉。
若有其他相關問題或者需求也可以郵件聯系俺探討。
郵箱地址是:
[email protected]
基於傅裏葉變換的音頻重采樣算法 (附完整c代碼)