/*
* AECX.cpp - AEC(Acoustics Echo Cancellation) CPP program
* homepage: http://www.imtelephone.com
* http://www.easyconfex.com
* http://www.p2piptv.com
* Copyright (C) 2002-2006 imtelephone.com(support@p2piptv.com)
*
* ---------------------------------------------------------------------------
* This program is only distributed for non-commercial use. If you want to use
* it in commercial software, please contact to support@p2piptv.com.
* ---------------------------------------------------------------------------
*/
#include "stdafx.h"
#include "AECX.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define FRAME_SIZE 480 // You can change this value according your sample numbers in each buffer.
#define TAP_NUM 800
#define SOUNDCARD_DELAY 400
#define DECIMAL 1
#define Mu 0.75
#define Alpha2 1E-4
#define ZCR_THRESHOLD 0.02
#define SLIENCE_ZCR_NUM 2.0
#define SILENCE_ENERGY_THRESHOLD 1.5
#define MAX_SILENCES 5
#define DOUBLETALK_WAIT 2400
#define NMD_T 0.005
#define ALPHA 0.015625
#define GRAD_NMD_T 0.1
#define AMPL_SCALE_1 3.0518509E-05
#define AMPL_SCALE_2 32767.0
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAECX::CAECX()
{
m_pNearEndBuf = NULL;
m_pTap = NULL;
m_pTap_Old = NULL;
m_pFIRBuf = NULL;
m_pE = NULL;
}
CAECX::~CAECX()
{
if (m_pNearEndBuf)
delete m_pNearEndBuf;
if (m_pE)
delete m_pE;
if (m_pFIRBuf)
delete m_pFIRBuf;
if (m_pTap)
delete m_pTap;
if (m_pTap_Old)
delete m_pTap_Old;
DeleteCriticalSection(&m_Aec_Critical_Section);
}
//////////////////////////////////////////////////////////////////////
// Initialize the AEC
// RETURN : FALSE = ERROR
//////////////////////////////////////////////////////////////////////
BOOL CAECX::InitAEC()
{
if ((m_pNearEndBuf = new double[sizeof(double)*FRAME_SIZE]) == NULL )
return FALSE;
if ((m_pE = new double[sizeof(double)*FRAME_SIZE]) == NULL )
return FALSE;
if ((m_pFIRBuf = new double[sizeof(double)*(TAP_NUM+SOUNDCARD_DELAY+FRAME_SIZE)]) == NULL )
return FALSE;
if ((m_pTap = new double[sizeof(double)*TAP_NUM]) == NULL )
return FALSE;
if ((m_pTap_Old = new double[sizeof(double)*TAP_NUM]) == NULL )
return FALSE;
ZeroMemory(m_pNearEndBuf,sizeof(double)*FRAME_SIZE);
ZeroMemory(m_pFIRBuf,sizeof(double)*(TAP_NUM+SOUNDCARD_DELAY+FRAME_SIZE));
ZeroMemory(m_pTap,sizeof(double)*TAP_NUM);
ZeroMemory(m_pTap_Old,sizeof(double)*TAP_NUM);
ZeroMemory(m_pE,sizeof(double)*FRAME_SIZE);
InitializeCriticalSection(&m_Aec_Critical_Section);
m_nBufCount = 0;
m_FarEnergy = 0.0;
m_FarZCR = 0.0;
m_NearEnergy = 0.0;
m_NearZCR = 0.0;
m_Ee = 0.0;
m_dNMD[0]=0.0;m_dNMD[1]=0.0;
m_dGRAD_NMD = 0.0;
m_bFarEndActive = FALSE;
m_nFarEndSilenceCount = 0;
m_bDoubleTalk = FALSE;
m_nDoubleTalkCount = 0;
m_nUnStableCount =0;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// Save one frame of remote voice sample and
// calculate the parameters
// return: TRUE = Remote ACTIVE, mean remote user is speaking
// FALSE= Remote UNACTIVE, mean remote user is not speaking
//////////////////////////////////////////////////////////////////////
BOOL CAECX::SaveSample(double *buf)
{
int i;
EnterCriticalSection(&m_Aec_Critical_Section);
// The bug content
// FIR Register Soundcard delay New samples
// |____________|______________|___|
// | | |
// \
//
CopyMemory((m_pFIRBuf+TAP_NUM+SOUNDCARD_DELAY),buf,sizeof(double)*FRAME_SIZE);
for (i=0;i<FRAME_SIZE;i++)
*(m_pFIRBuf+TAP_NUM+SOUNDCARD_DELAY+i) *= AMPL_SCALE_1;
FarEndPreFilter( m_pFIRBuf+TAP_NUM+SOUNDCARD_DELAY);
m_FarEnergy = FrameEnergy(m_pFIRBuf,FRAME_SIZE+TAP_NUM);
m_FarZCR = FrameZCR(m_pFIRBuf,FRAME_SIZE+TAP_NUM);
if (m_FarEnergy>SILENCE_ENERGY_THRESHOLD && m_FarZCR>SLIENCE_ZCR_NUM)
m_nFarEndSilenceCount = 0;
else
{
m_nFarEndSilenceCount++;
m_nFarEndSilenceCount &= 0xFF;
}
if (m_nFarEndSilenceCount<MAX_SILENCES)
m_bFarEndActive = TRUE;
else
{
m_bFarEndActive = FALSE;
m_nDoubleTalkCount = 0;
}
LeaveCriticalSection(&m_Aec_Critical_Section);
return m_bFarEndActive;
}
//////////////////////////////////////////////////////////////////////
// Input one frame of local voice. Do AEC to this frame
// Return: TRUE = double-talk
// FALSE= no double-talk
//////////////////////////////////////////////////////////////////////
BOOL CAECX::AECFilter(double *buf)
{
int i;
EnterCriticalSection(&m_Aec_Critical_Section);
CopyMemory(m_pNearEndBuf,buf,sizeof(double)*FRAME_SIZE);
for (i=0;i<FRAME_SIZE;i++)
*(m_pNearEndBuf+i) *= AMPL_SCALE_1;
NearEndPreFilter(m_pNearEndBuf);
m_NearEnergy = FrameEnergy(m_pNearEndBuf,FRAME_SIZE);
m_NearZCR = FrameZCR(m_pNearEndBuf,FRAME_SIZE);
if (m_bFarEndActive )
{
m_bDoubleTalk = NLMS();
for (i=0;i<FRAME_SIZE;i++)
*(m_pE+i) *= AMPL_SCALE_2;
CopyMemory(buf,m_pE,sizeof(double)*FRAME_SIZE);
}
MoveMemory(m_pFIRBuf,m_pFIRBuf+FRAME_SIZE,sizeof(double)*(TAP_NUM+SOUNDCARD_DELAY));
ZeroMemory((m_pFIRBuf+TAP_NUM+SOUNDCARD_DELAY),sizeof(double)*FRAME_SIZE);
LeaveCriticalSection(&m_Aec_Critical_Section);
return m_bDoubleTalk;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
double CAECX::FrameEnergy(double *buff,int n)
{
double amp = 0.0;
for (int i=0; i<n; i++)
amp += fabs(*(buff+i));
return amp;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
double CAECX::FrameZCR(double *buff,int n)
{
double zcr = 0.0;
for (int i=0; i<n-1; i++)
{
double tmp1 = *buff++;
double tmp2 = *buff;
if (tmp1*tmp2<0 && fabs(tmp1-tmp2)>ZCR_THRESHOLD)
zcr++;
}
return zcr;
}
//////////////////////////////////////////////////////////////////////
//
// H(z) = 1-0.9735z^-1
//
//////////////////////////////////////////////////////////////////////
void CAECX::FarEndPreFilter(double *buff)
{
int i;
static double tmp1=0.0, tmp2=0.0;
for (i=0; i<FRAME_SIZE; i++)
{
tmp1 = *buff - tmp2*0.9375;
tmp2 = *buff;
*(buff++) = tmp1;
}
}
void CAECX::NearEndPreFilter(double *buff)
{
int i;
static double tmp1=0.0, tmp2=0.0;
for (i=0; i<FRAME_SIZE; i++)
{
tmp1 = *buff - tmp2*0.9375;
tmp2 = *buff;
*(buff++) = tmp1;
}
}
//////////////////////////////////////////////////////////////////////
// NLMS
// RETURN: TRUE = doubletalk
//////////////////////////////////////////////////////////////////////
BOOL CAECX::NLMS()
{
register int i,n;
double * pFIR;
double * pE;
double * pW;
double * pD;
double d_hat;
static double D2;
pFIR = m_pFIRBuf;
pD = m_pNearEndBuf;
pE = m_pE;
pW = m_pTap;
D2 = 0.0;
for (n=0;n<TAP_NUM;n++)
D2 += pFIR[n]*pFIR[n];
for (i=0;i<FRAME_SIZE;i++)
{
if (m_nBufCount<TAP_NUM+SOUNDCARD_DELAY+FRAME_SIZE)
{
m_nBufCount++;
continue;
}
d_hat = 0.0;
for (n=0;n<TAP_NUM;n++)
d_hat += pFIR[n+i] * pW[n];
pE[i] = pD[i] - d_hat;
if (m_nDoubleTalkCount >1)
m_nDoubleTalkCount --;
else if (i%DECIMAL == 0)
{
for (n=0;n<TAP_NUM;n++)
pW[n] += pE[i]*Mu*pFIR[n+i] / (D2 + Alpha2);
m_dNMD[1] = m_dNMD[0]; m_dNMD[0] = 0;
for (n=0;n<TAP_NUM;n++)
m_dNMD[0] += pW[n]*pW[n];
m_dNMD[0] /= TAP_NUM;
m_dGRAD_NMD = (m_dNMD[0]-m_dNMD[1])*ALPHA*10000+(1-ALPHA)*m_dGRAD_NMD;
if (m_dGRAD_NMD>GRAD_NMD_T)
{
m_bDoubleTalk = TRUE;
m_nDoubleTalkCount = DOUBLETALK_WAIT;
CopyMemory(m_pTap,m_pTap_Old,sizeof(double)*TAP_NUM);
}
else
m_bDoubleTalk = FALSE;
if (m_dGRAD_NMD<GRAD_NMD_T/10 && m_dNMD[0]<NMD_T)
CopyMemory(m_pTap_Old,m_pTap,sizeof(double)*TAP_NUM);
}
D2 -= pFIR[i]*pFIR[i];
D2 += pFIR[TAP_NUM+i]*pFIR[TAP_NUM+i];
}
return m_bDoubleTalk;
}
/*
* AECX.h - AEC(Acoustics Echo Cancellation) header file
* homepage: http://www.imtelephone.com
* http://www.easyconfex.com
* http://www.p2piptv.com
* Copyright (C) 2002-2006 imtelephone.com(support@p2piptv.com)
*
* ---------------------------------------------------------------------------
* This program is only distributed for non-commercial use. If you want to use
* it in commercial software, please contact to support@p2piptv.com.
* ---------------------------------------------------------------------------
*/
/*
* It is very easy to use this AEC
* Before you use AEC, please call InitAEC(), it usually called when you start your application.
* For every audio sample you received from remote user, call SaveSample()
* For every audio sample you received from sourd card, call AECFilter()
* Please note, the parameter of AECFilter() and SaveSample() need be double, if you samples are not float,
* please convert them to double first.
* the macro of FRAME_SIZE define the sample number of each buffer. The default is 480( include 60 milisecond
* samples for 8K hz audio). You can change it according your software.
*/
#if !defined(__AECX_H__)
#define __AECX_H__
#include <math.h>
class CAECX
{
public:
BOOL InitAEC();
BOOL SaveSample(double * buf);
BOOL AECFilter(double *buf);
CAECX();
virtual ~CAECX();
private:
double m_dGRAD_NMD;
double m_dNMD[2];
CRITICAL_SECTION m_Aec_Critical_Section;
BOOL m_bFarEndActive;
BOOL m_bDoubleTalk;
int m_nUnStableCount;
int m_nBufCount;
int m_nFarEndSilenceCount;
int m_nDoubleTalkCount;
BOOL NLMS(void);
double FrameZCR(double * buff,int n);
void FarEndPreFilter(double *buff);
void NearEndPreFilter(double *buff);
double m_FarZCR;
double m_NearZCR;
double m_FarEnergy;
double m_NearEnergy;
double m_Ee;
double FrameEnergy(double * buff,int n);
double * m_pFIRBuf;
double * m_pNearEndBuf;
double * m_pE;
double * m_pTap;
double * m_pTap_Old;
};
#endif
我在网上下载了这2个文件,用VC++6编译时总是出错(其中的test4.cpp就是AEC.cpp就是改了名字而已):
Compiling...
test4.cpp
E:\down\test4\test4.cpp(80) : error C2065: 'DEBUG_NEW' : undeclared identifier
E:\down\test4\test4.cpp(80) : error C2440: '=' : cannot convert from 'int' to 'double *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
E:\down\test4\test4.cpp(80) : error C2144: syntax error : missing ')' before type 'double'
E:\down\test4\test4.cpp(80) : error C2059: syntax error : ')'
E:\down\test4\test4.cpp(83) : error C2440: '=' : cannot convert from 'int' to 'double *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
E:\down\test4\test4.cpp(83) : error C2144: syntax error : missing ')' before type 'double'
E:\down\test4\test4.cpp(83) : error C2059: syntax error : ')'
E:\down\test4\test4.cpp(86) : error C2440: '=' : cannot convert from 'int' to 'double *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
E:\down\test4\test4.cpp(86) : error C2144: syntax error : missing ')' before type 'double'
E:\down\test4\test4.cpp(86) : error C2059: syntax error : ')'
E:\down\test4\test4.cpp(89) : error C2440: '=' : cannot convert from 'int' to 'double *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
E:\down\test4\test4.cpp(89) : error C2144: syntax error : missing ')' before type 'double'
E:\down\test4\test4.cpp(89) : error C2059: syntax error : ')'
E:\down\test4\test4.cpp(92) : error C2440: '=' : cannot convert from 'int' to 'double *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
E:\down\test4\test4.cpp(92) : error C2144: syntax error : missing ')' before type 'double'
E:\down\test4\test4.cpp(92) : error C2059: syntax error : ')'
Error executing cl.exe.
test4.obj - 16 error(s), 0 warning(s)
请教各位DX,该怎么编译?看得出来,我是个超级菜鸟