在研究MFCC算法时,从网上下了一份代码,经过小改编译通过了,可程序一跑就蹦,费了好几天的功夫也没找到问题的原因。
化了一个月的时间边看资料,边整理代码,参照原有代码自己实现了一份。目前代码调通了,还没有能力验证结果的正确性。
这里使用的FFT算法是从网上下载的。稍后也将其附上。欢迎有MFCC经验的朋友帮忙指正其中存在的问题。
#ifndef MFCC_H
#define MFCC_H
#include <stdio.h>
#include <math.h>
#include <QVector>
#include <QMap>
#define MOD_256 8
#define MOD_512 9
#define MOD_1024 10
class CMFCC
{
public:
CMFCC(int Mod);
int mfcc(double * data,int size);
protected:
void preEmphasis();
void procFrame();
void procHammingWindows(double * buffer);
void fft(double * buffer);
int Melf(double * buffer);
void DCT(double *lnpower,int len,double * dct,int dctnum);
private:
double * m_data;
int m_size;
int m_frameSize;
double m_factor;
double m_hammingFactor;
int m_mod;
int m_resoultSize;
};
#include "MFCC.h"
#include <memory.h>
#include "FFT.h"
#include "Mel.h"
#include "PlotWidget.h"
#include <QDebug>
#include <math.h>
#define PI 3.141592653589793
CMFCC::CMFCC(int mod)
:m_data(0),m_size(0),m_frameSize(pow(2,mod))
,m_factor(0.97),m_hammingFactor(0.46),m_mod(mod)
{
}
int CMFCC::mfcc(double * data,int size)
{
m_data = data;
m_size = size;
this->preEmphasis();
this->procFrame();
return 0;
}
void CMFCC::preEmphasis()
{
for(int i =1; i< m_size; i++)
{
m_data[i] = m_data[i] - m_factor * m_data[i-1];
}
}
void CMFCC::procFrame()
{
//plot("data",0,m_data,m_size,Qt::blue);
int dis = m_frameSize - m_frameSize / 3;
double * buffer = new double[m_frameSize];
int i = 0;
for(; i< m_size-m_frameSize; i+= dis)
{
double * s = m_data + i;
//double * e = m_data + i + m_frameSize;
memcpy(buffer,s,m_frameSize * sizeof(double));
//plot("frame",0,buffer,m_frameSize,Qt::blue);
this->procHammingWindows(buffer);
//plot("ccc",0,buffer,m_frameSize,Qt::red);
this->fft(buffer);
//plot("fft",0,buffer,m_frameSize,Qt::red);
this->Melf(buffer);
//plot("fft",0,buffer,m_frameSize/2,Qt::red);
}
/*
int n = i - m_size;
if(n > 0)
{
memset(buffer,0,m_frameSize*sizeof(double));
memcpy(buffer,m_data+m_size-n,m_frameSize*sizeof(double));
//plot("frame",0,buffer,m_frameSize,Qt::blue);
this->procHammingWindows(buffer);
this->fft(buffer);
this->Melf(buffer);
//plot("fft",0,buffer,m_frameSize,Qt::red);
}
*/
delete[] buffer;
}
void CMFCC::procHammingWindows(double * buffer)
{
int size = m_frameSize -1;
for(int i=0; i<m_frameSize; i++)
{
double d = (2 * PI * i)/size;
double w = (1-m_hammingFactor) - m_hammingFactor * cos(d);
buffer[i] = buffer[i] * w;
}
}
void CMFCC::fft(double * buffer)
{
complex *tx = new complex[m_frameSize];
for(int i = 0; i<m_frameSize; i++)
{
tx[i].real = buffer[i];
tx[i].img = 0;
}
complex * dx = new complex[m_frameSize];
complex * nex_t = new complex[m_frameSize];
memset(dx,0,m_frameSize * sizeof(complex));
memset(nex_t,0,m_frameSize * sizeof(complex));
FFT(tx,dx,nex_t,m_frameSize,m_mod);
for(int i=0; i<m_frameSize; i++)
{
buffer[i] = dx[i].real;
}
delete tx;
delete dx;
delete nex_t;
}
int CMFCC::Melf(double * buffer)
{
CMel mel;
int n = mel.mel(buffer,m_frameSize/2);
//output("mel :",buffer,n);
double dctNum = 10;
double *dct = new double[dctNum];
memset(dct,0,dctNum*sizeof(double));
DCT(buffer,n,dct,dctNum);
//output("dtc :",dct,dctNum);
plot("dtc",0,dct,dctNum,Qt::red);
delete[] dct;
return dctNum;
}
void CMFCC::DCT(double *data,int len,double * dct,int dctnum)
{
//double temp[100];
//memset(temp,0,100*sizeof(double));
//memcpy(temp,data,len*sizeof(double));
double k = pow(2.0/(double)len,0.5);
for(int i=0;i<dctnum;i++)
{
for(int j=0;j<len;j++)
{
double d = data[j];
if(d > std::numeric_limits<double>::min())
{
double d1 = log(data[j]);
double d2 = cos(i*(j-0.5)*3.141592653589793/len);
double d3 = d1 * d2;
double d5 = dct[i];
d5 += d3;
dct[i] += d3;
}
//dct[i] += log(data[j])*cos(i*(j-0.5)*3.141592653589793/len);
}
double md = dct[i];
dct[i] *= k;
}
//double temp2[100];
//memset(temp2,0,100*sizeof(double));
//memcpy(temp2,dct,dctnum*sizeof(double));
//int n = 0;
}