1. 程式人生 > >基於傅裏葉變換的音頻重采樣算法 (附完整c代碼)

基於傅裏葉變換的音頻重采樣算法 (附完整c代碼)

操作 endif 傅裏葉變換 思路 lis fin log 替換 我們

前面有提到音頻采樣算法:

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代碼)