Загрузка данных
#include "arch.h"
#include "speex/speex_echo.h"
#include "fftwrap.h"
#include "pseudofloat.h"
#include "math_approx.h"
#include "os_support.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifdef FIXED_POINT
#define WEIGHT_SHIFT 11
#define NORMALIZE_SCALEDOWN 5
#define NORMALIZE_SCALEUP 3
#else
#define WEIGHT_SHIFT 0
#endif
/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
#define TWO_PATH
#ifdef FIXED_POINT
static const spx_float_t MIN_LEAK = {20972, -22};
/* Constants for the two-path filter */
static const spx_float_t VAR1_SMOOTH = {23593, -16};
static const spx_float_t VAR2_SMOOTH = {23675, -15};
static const spx_float_t VAR1_UPDATE = {16384, -15};
static const spx_float_t VAR2_UPDATE = {16384, -16};
static const spx_float_t VAR_BACKTRACK = {16384, -12};
#define TOP16(x) ((x)>>16)
#else
static const spx_float_t MIN_LEAK = .005f;
/* Constants for the two-path filter */
static const spx_float_t VAR1_SMOOTH = .36f;
static const spx_float_t VAR2_SMOOTH = .7225f;
static const spx_float_t VAR1_UPDATE = .5f;
static const spx_float_t VAR2_UPDATE = .25f;
static const spx_float_t VAR_BACKTRACK = 4.f;
#define TOP16(x) (x)
#endif
#define PLAYBACK_DELAY 2
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
/** Speex echo cancellation state. */
struct SpeexEchoState_ {
int frame_size; /**< Number of samples processed each time */
int window_size;
int M;
int cancel_count;
int adapted;
int saturated;
int screwed_up;
int C; /** Number of input channels (microphones) */
int K; /** Number of output channels (loudspeakers) */
spx_int32_t sampling_rate;
spx_word16_t spec_average;
spx_word16_t beta0;
spx_word16_t beta_max;
spx_word32_t sum_adapt;
spx_word16_t leak_estimate;
spx_word16_t *e; /* scratch */
spx_word16_t *x; /* Far-end input buffer (2N) */
spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */
spx_word16_t *input; /* scratch */
spx_word16_t *y; /* scratch */
spx_word16_t *last_y;
spx_word16_t *Y; /* scratch */
spx_word16_t *E;
spx_word32_t *PHI; /* scratch */
spx_word32_t *W; /* (Background) filter weights */
#ifdef TWO_PATH
spx_word16_t *foreground; /* Foreground filter weights */
spx_word32_t Davg1; /* 1st recursive average of the residual power difference */
spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */
spx_float_t Dvar1; /* Estimated variance of 1st estimator */
spx_float_t Dvar2; /* Estimated variance of 2nd estimator */
#endif
spx_word32_t *power; /* Power of the far-end signal */
spx_float_t *power_1;/* Inverse power of far-end */
spx_word16_t *wtmp; /* scratch */
#ifdef FIXED_POINT
spx_word16_t *wtmp2; /* scratch */
#endif
spx_word32_t *Rf; /* scratch */
spx_word32_t *Yf; /* scratch */
spx_word32_t *Xf; /* scratch */
spx_word32_t *Eh;
spx_word32_t *Yh;
spx_float_t Pey;
spx_float_t Pyy;
spx_word16_t *window;
spx_word16_t *prop;
void *fft_table;
spx_word16_t *memX, *memD, *memE;
spx_word16_t preemph;
spx_word16_t notch_radius;
spx_mem_t *notch_mem;
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
spx_int16_t *play_buf;
int play_buf_pos;
int play_buf_started;
};
static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
{
int i;
spx_word16_t den2;
#ifdef FIXED_POINT
den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius));
#else
den2 = radius*radius + .7*(1-radius)*(1-radius);
#endif
/*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
for (i=0;i<len;i++)
{
spx_word16_t vin = in[i*stride];
spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
#ifdef FIXED_POINT
mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1);
#else
mem[0] = mem[1] + 2*(-vin + radius*vout);
#endif
mem[1] = SHL32(EXTEND32(vin),15) - MULT16_32_Q15(den2,vout);
out[i] = SATURATE32(PSHR32(MULT16_32_Q15(radius,vout),15),32767);
}
}
/* This inner product is slightly different from the codec version because of fixed-point */
static inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
{
spx_word32_t sum=0;
len >>= 1;
while(len--)
{
spx_word32_t part=0;
part = MAC16_16(part,*x++,*y++);
part = MAC16_16(part,*x++,*y++);
/* HINT: If you had a 40-bit accumulator, you could shift only at the end */
sum = ADD32(sum,SHR32(part,6));
}
return sum;
}
/** Compute power spectrum of a half-complex (packed) vector */
static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N)
{
int i, j;
ps[0]=MULT16_16(X[0],X[0]);
for (i=1,j=1;i<N-1;i+=2,j++)
{
ps[j] = MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
}
ps[j]=MULT16_16(X[i],X[i]);
}
/** Compute power spectrum of a half-complex (packed) vector and accumulate */
static inline void power_spectrum_accum(const spx_word16_t *X, spx_word32_t *ps, int N)
{
int i, j;
ps[0]+=MULT16_16(X[0],X[0]);
for (i=1,j=1;i<N-1;i+=2,j++)
{
ps[j] += MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
}
ps[j]+=MULT16_16(X[i],X[i]);
}
/** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */
#ifdef FIXED_POINT
static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
{
int i,j;
spx_word32_t tmp1=0,tmp2=0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[j*N],TOP16(Y[j*N]));
}
acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
for (i=1;i<N-1;i+=2)
{
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],TOP16(Y[j*N+i])), MULT16_16(X[j*N+i+1],TOP16(Y[j*N+i+1])));
tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],TOP16(Y[j*N+i])), X[j*N+i], TOP16(Y[j*N+i+1]));
}
acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
}
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],TOP16(Y[(j+1)*N-1]));
}
acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
}
static inline void spectral_mul_accum16(const spx_word16_t *X, const spx_word16_t *Y, spx_word16_t *acc, int N, int M)
{
int i,j;
spx_word32_t tmp1=0,tmp2=0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[j*N],Y[j*N]);
}
acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
for (i=1;i<N-1;i+=2)
{
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],Y[j*N+i]), MULT16_16(X[j*N+i+1],Y[j*N+i+1]));
tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],Y[j*N+i]), X[j*N+i], Y[j*N+i+1]);
}
acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
}
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],Y[(j+1)*N-1]);
}
acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
}
#else
static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
{
int i,j;
for (i=0;i<N;i++)
acc[i] = 0;
for (j=0;j<M;j++)
{
acc[0] += X[0]*Y[0];
for (i=1;i<N-1;i+=2)
{
acc[i] += (X[i]*Y[i] - X[i+1]*Y[i+1]);
acc[i+1] += (X[i+1]*Y[i] + X[i]*Y[i+1]);
}
acc[i] += X[i]*Y[i];
X += N;
Y += N;
}
}
#define spectral_mul_accum16 spectral_mul_accum
#endif