0. 前言
關於MFCC相關原理,這裏就不過多敘述了,網上的參考資料也比較多,自己對MFCC原理理解也不是很深刻(方向不一樣),主要介紹本人對kaldi mfcc特徵提取代碼裁剪後的接口,此處開源的MFCC不含pitch特徵提取。
1. Github代碼結構介紹
在介紹之前,提及一點,若要運行,請先閱讀README.md編譯外部庫。
特徵提取的代碼在src/feat目錄下,測試代碼在src/main/feat-test.cc
MFCC最後提交commit 1d1d3fef56b3325352f29e1e08c78516a5ba12f5,切換到commit後,可以知道調用了哪些數學運算,其中openblas調用了兩個接口:**cblas_sdot **、cblas_sgemv
文件源程序結構:
如果想要編譯測試代碼src/main/feat-test.cc,請修改src/build/Makefile
以上代碼文件中,計算特徵的接口在compute-feat.h中,其他mel-banks和srfft相關操作可以不用管。
關於mfcc參數設置,代碼中採用的宏定義的方式,具體的配置在feat-params.h中,需要特別注意的是如果改變了窗函數的大小,需要手動計算一下 PADDING_WINDOWS_SIZE, 計算PADDING_WINDOWS_SIZE方式如下:
// 計算窗函數方式, 傳入參數爲WINDOW_SIZE
static inline int32 RoundUpToNearestPowerOfTwo(int32 n)
{
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n+1;
}
#define WINDOW_SHIFT (static_cast<int32> ((SAMPLEING_RATE) * 0.001f * (FRAME_SHIFT_MS)))
#define WINDOW_SIZE (static_cast<int32> ((SAMPLEING_RATE) * 0.001f * (FRAME_LENGHT_MS)))
//#define PADDING_WINDOWS_SIZE ((RoundUpToNearestPowerOfTwo(WINDOW_SIZE)))
#define PADDING_WINDOWS_SIZE (512) // 此處手動填入的計算值
因爲在程序中使用PADDING_WINDOWS_SIZE來創建一個全局數組,而用函數時是在運行時才確定數組大小,所以編譯會報錯,怎麼寫帶返回值的RoundUpToNearestPowerOfTwo宏定義函數,歡迎大佬指點一下,不勝感激!
2. APIs說明
Api | 說明 |
---|---|
ComputeFeatInit() | 初始化特徵提取的一些變量及mel-banks、srfft |
ComputeFeatures(const vector &waveform, vector<BaseFloat* > &feats) | 計算mfcc特徵,傳入音頻文件data段(原始PCM流),輸出的結果存在feats中 |
NumFramesReady(const vector<BaseFloat* > &feats) | 獲取當前音頻提取完有多少幀MFCC特徵 |
IsLastFrame(const vector<BaseFloat* > &feats, const int32 frame) | 判斷當前幀是否是最後一幀 |
GetFrame(const vector<BaseFloat* > &feats, const int32 frame) | 根據frame獲得一行mfcc特徵 |
FeatsFree() | 釋放當前音頻文件計算mfcc特徵過程中申請的內存 |
FeatDestroy() | 釋放所有的特徵提取申請的內存, 除featsFree()外還包括mel-banks、srfft申請的內存 |
如果需要修改成C語言,只需要替換掉vector即可,特徵feats可以定義成如下結構體:
typedef struct
{
int32 frames;
BaseFloat**feat;
} MfccFeats;