198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Copyright (C) 2003-2008 Jean-Marc Valin
298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   File: mdf.c
498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Echo canceller based on the MDF algorithm (see below)
598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Redistribution and use in source and binary forms, with or without
798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   modification, are permitted provided that the following conditions are
898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   met:
998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   1. Redistributions of source code must retain the above copyright notice,
1198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   this list of conditions and the following disclaimer.
1298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   2. Redistributions in binary form must reproduce the above copyright
1498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   notice, this list of conditions and the following disclaimer in the
1598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   documentation and/or other materials provided with the distribution.
1698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   3. The name of the author may not be used to endorse or promote products
1898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   derived from this software without specific prior written permission.
1998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
2098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   POSSIBILITY OF SUCH DAMAGE.
3198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
3298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
3398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/*
3498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   The echo canceller is based on the MDF algorithm described in:
3598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
3698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter,
3798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2,
3898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   February 1990.
3998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   We use the Alternatively Updated MDF (AUMDF) variant. Robustness to
4198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   double-talk is achieved using a variable learning rate as described in:
4298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo
4498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Cancellation With Double-Talk. IEEE Transactions on Audio,
4598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007.
4698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   http://people.xiph.org/~jm/papers/valin_taslp2006.pdf
4798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   There is no explicit double-talk detection, but a continuous variation
4998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   in the learning rate based on residual echo, double-talk and background
5098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   noise.
5198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
5298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   About the fixed-point version:
5398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   All the signals are represented with 16-bit words. The filter weights
5498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   are represented with 32-bit words, but only the top 16 bits are used
5598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   in most cases. The lower 16 bits are completely unreliable (due to the
5698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fact that the update is done only on the top bits), but help in the
5798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   adaptation -- probably by removing a "threshold effect" due to
5898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   quantization (rounding going to zero) when the gradient is small.
5998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
6098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Another kludge that seems to work good: when performing the weight
6198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   update, we only move half the way toward the "goal" this seems to
6298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   reduce the effect of quantization noise in the update phase. This
6398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   can be seen as applying a gradient descent on a "soft constraint"
6498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   instead of having a hard constraint.
6598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
6698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
6798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
6898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef HAVE_CONFIG_H
6998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "config.h"
7098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
7198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
7298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "arch.h"
7398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "speex/speex_echo.h"
7498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "fftwrap.h"
7598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "pseudofloat.h"
7698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "math_approx.h"
7798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "os_support.h"
7898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
7998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef M_PI
8098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define M_PI 3.14159265358979323846
8198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
8298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
8398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
8498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WEIGHT_SHIFT 11
8598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define NORMALIZE_SCALEDOWN 5
8698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define NORMALIZE_SCALEUP 3
8798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
8898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WEIGHT_SHIFT 0
8998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
9098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
9198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
9298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
9398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
9498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
9598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
9698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
9798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
9898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
9998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define TWO_PATH
10098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
10198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
10298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t MIN_LEAK = {20972, -22};
10398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
10498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Constants for the two-path filter */
10598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR1_SMOOTH = {23593, -16};
10698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR2_SMOOTH = {23675, -15};
10798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR1_UPDATE = {16384, -15};
10898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR2_UPDATE = {16384, -16};
10998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR_BACKTRACK = {16384, -12};
11098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define TOP16(x) ((x)>>16)
11198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
11298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
11398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
11498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t MIN_LEAK = .005f;
11598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
11698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Constants for the two-path filter */
11798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR1_SMOOTH = .36f;
11898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR2_SMOOTH = .7225f;
11998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR1_UPDATE = .5f;
12098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR2_UPDATE = .25f;
12198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const spx_float_t VAR_BACKTRACK = 4.f;
12298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define TOP16(x) (x)
12398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
12498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
12598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
12698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define PLAYBACK_DELAY 2
12798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
12898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectvoid speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
12998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
13098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
13198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Speex echo cancellation state. */
13298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstruct SpeexEchoState_ {
13398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int frame_size;           /**< Number of samples processed each time */
13498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int window_size;
13598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int M;
13698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int cancel_count;
13798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int adapted;
13898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int saturated;
13998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int screwed_up;
14098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int C;                    /** Number of input channels (microphones) */
14198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int K;                    /** Number of output channels (loudspeakers) */
14298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_int32_t sampling_rate;
14398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t spec_average;
14498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t beta0;
14598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t beta_max;
14698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t sum_adapt;
14798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t leak_estimate;
14898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
14998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *e;      /* scratch */
15098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *x;      /* Far-end input buffer (2N) */
15198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *X;      /* Far-end buffer (M+1 frames) in frequency domain */
15298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *input;  /* scratch */
15398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *y;      /* scratch */
15498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *last_y;
15598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *Y;      /* scratch */
15698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *E;
15798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *PHI;    /* scratch */
15898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *W;      /* (Background) filter weights */
15998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
16098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *foreground; /* Foreground filter weights */
16198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t  Davg1;  /* 1st recursive average of the residual power difference */
16298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t  Davg2;  /* 2nd recursive average of the residual power difference */
16398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t   Dvar1;  /* Estimated variance of 1st estimator */
16498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t   Dvar2;  /* Estimated variance of 2nd estimator */
16598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
16698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *power;  /* Power of the far-end signal */
16798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t  *power_1;/* Inverse power of far-end */
16898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *wtmp;   /* scratch */
16998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
17098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *wtmp2;  /* scratch */
17198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
17298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *Rf;     /* scratch */
17398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *Yf;     /* scratch */
17498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *Xf;     /* scratch */
17598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *Eh;
17698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t *Yh;
17798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t   Pey;
17898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t   Pyy;
17998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *window;
18098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *prop;
18198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   void *fft_table;
18298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *memX, *memD, *memE;
18398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t preemph;
18498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t notch_radius;
18598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_mem_t *notch_mem;
18698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
18798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
18898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_int16_t *play_buf;
18998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int play_buf_pos;
19098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int play_buf_started;
19198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project};
19298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
19398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic 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)
19498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
19598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i;
19698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t den2;
19798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
19898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius));
19998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
20098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   den2 = radius*radius + .7*(1-radius)*(1-radius);
20198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
20298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
20398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<len;i++)
20498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
20598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word16_t vin = in[i*stride];
20698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
20798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
20898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1);
20998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
21098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      mem[0] = mem[1] + 2*(-vin + radius*vout);
21198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
21298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      mem[1] = SHL32(EXTEND32(vin),15) - MULT16_32_Q15(den2,vout);
21398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      out[i] = SATURATE32(PSHR32(MULT16_32_Q15(radius,vout),15),32767);
21498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
21598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
21698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
21798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* This inner product is slightly different from the codec version because of fixed-point */
21898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
21998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
22098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t sum=0;
22198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   len >>= 1;
22298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while(len--)
22398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
22498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word32_t part=0;
22598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      part = MAC16_16(part,*x++,*y++);
22698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      part = MAC16_16(part,*x++,*y++);
22798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* HINT: If you had a 40-bit accumulator, you could shift only at the end */
22898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = ADD32(sum,SHR32(part,6));
22998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
23098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return sum;
23198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
23298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
23398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Compute power spectrum of a half-complex (packed) vector */
23498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N)
23598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
23698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i, j;
23798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ps[0]=MULT16_16(X[0],X[0]);
23898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=1,j=1;i<N-1;i+=2,j++)
23998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
24098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      ps[j] =  MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
24198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
24298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ps[j]=MULT16_16(X[i],X[i]);
24398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
24498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
24598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Compute power spectrum of a half-complex (packed) vector and accumulate */
24698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void power_spectrum_accum(const spx_word16_t *X, spx_word32_t *ps, int N)
24798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
24898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i, j;
24998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ps[0]+=MULT16_16(X[0],X[0]);
25098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=1,j=1;i<N-1;i+=2,j++)
25198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
25298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      ps[j] +=  MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
25398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
25498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ps[j]+=MULT16_16(X[i],X[i]);
25598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
25698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
25798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */
25898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
25998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
26098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
26198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i,j;
26298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t tmp1=0,tmp2=0;
26398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<M;j++)
26498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
26598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = MAC16_16(tmp1, X[j*N],TOP16(Y[j*N]));
26698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
26798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
26898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=1;i<N-1;i+=2)
26998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
27098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = tmp2 = 0;
27198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (j=0;j<M;j++)
27298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
27398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         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])));
27498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         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]));
27598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
27698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
27798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
27898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
27998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   tmp1 = tmp2 = 0;
28098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<M;j++)
28198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
28298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],TOP16(Y[(j+1)*N-1]));
28398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
28498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
28598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
28698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void spectral_mul_accum16(const spx_word16_t *X, const spx_word16_t *Y, spx_word16_t *acc, int N, int M)
28798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
28898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i,j;
28998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t tmp1=0,tmp2=0;
29098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<M;j++)
29198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
29298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = MAC16_16(tmp1, X[j*N],Y[j*N]);
29398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
29498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
29598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=1;i<N-1;i+=2)
29698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
29798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = tmp2 = 0;
29898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (j=0;j<M;j++)
29998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
30098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         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]));
30198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],Y[j*N+i]), X[j*N+i], Y[j*N+i+1]);
30298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
30398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
30498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
30598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
30698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   tmp1 = tmp2 = 0;
30798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<M;j++)
30898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
30998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],Y[(j+1)*N-1]);
31098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
31198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
31298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
31398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
31498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
31598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
31698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
31798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i,j;
31898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N;i++)
31998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i] = 0;
32098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<M;j++)
32198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
32298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[0] += X[0]*Y[0];
32398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=1;i<N-1;i+=2)
32498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
32598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         acc[i] += (X[i]*Y[i] - X[i+1]*Y[i+1]);
32698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         acc[i+1] += (X[i+1]*Y[i] + X[i]*Y[i+1]);
32798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
32898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      acc[i] += X[i]*Y[i];
32998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      X += N;
33098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Y += N;
33198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
33298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
33398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define spectral_mul_accum16 spectral_mul_accum
33498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
33598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
33698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */
33798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_float_t p, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N)
33898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
33998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i, j;
34098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t W;
34198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   W = FLOAT_AMULT(p, w[0]);
34298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   prod[0] = FLOAT_MUL32(W,MULT16_16(X[0],Y[0]));
34398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=1,j=1;i<N-1;i+=2,j++)
34498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
34598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      W = FLOAT_AMULT(p, w[j]);
34698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prod[i] = FLOAT_MUL32(W,MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1]));
34798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prod[i+1] = FLOAT_MUL32(W,MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1]));
34898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
34998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   W = FLOAT_AMULT(p, w[j]);
35098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i]));
35198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
35298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
35398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, int P, spx_word16_t *prop)
35498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
35598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i, j, p;
35698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t max_sum = 1;
35798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t prop_sum = 1;
35898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<M;i++)
35998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
36098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word32_t tmp = 1;
36198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (p=0;p<P;p++)
36298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (j=0;j<N;j++)
36398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp += MULT16_16(EXTRACT16(SHR32(W[p*N*M + i*N+j],18)), EXTRACT16(SHR32(W[p*N*M + i*N+j],18)));
36498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
36598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Just a security in case an overflow were to occur */
36698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp = MIN32(ABS32(tmp), 536870912);
36798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
36898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prop[i] = spx_sqrt(tmp);
36998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (prop[i] > max_sum)
37098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         max_sum = prop[i];
37198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
37298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<M;i++)
37398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
37498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prop[i] += MULT16_16_Q15(QCONST16(.1f,15),max_sum);
37598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prop_sum += EXTEND32(prop[i]);
37698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
37798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<M;i++)
37898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
37998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      prop[i] = DIV32(MULT16_16(QCONST16(.99f,15), prop[i]),prop_sum);
38098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*printf ("%f ", prop[i]);*/
38198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
38298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*printf ("\n");*/
38398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
38498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
38598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef DUMP_ECHO_CANCEL_DATA
38698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include <stdio.h>
38798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic FILE *rFile=NULL, *pFile=NULL, *oFile=NULL;
38898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
38998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len)
39098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
39198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (!(rFile && pFile && oFile))
39298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
39398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_fatal("Dump files not open");
39498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
39598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fwrite(rec, sizeof(spx_int16_t), len, rFile);
39698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fwrite(play, sizeof(spx_int16_t), len, pFile);
39798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fwrite(out, sizeof(spx_int16_t), len, oFile);
39898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
39998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
40098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
40198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Creates a new echo canceller state */
40298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
40398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
40498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return speex_echo_state_init_mc(frame_size, filter_length, 1, 1);
40598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
40698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
40798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers)
40898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
40998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i,N,M, C, K;
41098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
41198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
41298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->K = nb_speakers;
41398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->C = nb_mic;
41498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   C=st->C;
41598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   K=st->K;
41698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef DUMP_ECHO_CANCEL_DATA
41798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (rFile || pFile || oFile)
41898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_fatal("Opening dump files twice");
41998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   rFile = fopen("aec_rec.sw", "wb");
42098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   pFile = fopen("aec_play.sw", "wb");
42198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   oFile = fopen("aec_out.sw", "wb");
42298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
42398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
42498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->frame_size = frame_size;
42598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->window_size = 2*frame_size;
42698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   N = st->window_size;
42798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   M = st->M = (filter_length+st->frame_size-1)/frame_size;
42898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->cancel_count=0;
42998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->sum_adapt = 0;
43098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->saturated = 0;
43198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->screwed_up = 0;
43298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* This is the default sampling rate */
43398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->sampling_rate = 8000;
43498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
43598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
43698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate);
43798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate);
43898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
43998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
44098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
44198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
44298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->leak_estimate = 0;
44398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
44498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->fft_table = spx_fft_init(N);
44598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
44698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
44798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t));
44898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t));
44998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
45098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
45198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
45298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
45398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
45498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
45598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
45698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
45798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t));
45898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
45998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
46098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t));
46198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
46298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t));
46398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
46498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
46598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
46698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t));
46798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->window = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
46898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->prop = (spx_word16_t*)speex_alloc(M*sizeof(spx_word16_t));
46998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->wtmp = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
47098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
47198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->wtmp2 = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
47298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N>>1;i++)
47398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
47498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->window[i] = (16383-SHL16(spx_cos(DIV32_16(MULT16_16(25736,i<<1),N)),1));
47598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->window[N-i-1] = st->window[i];
47698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
47798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
47898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N;i++)
47998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->window[i] = .5-.5*cos(2*M_PI*i/N);
48098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
48198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<=st->frame_size;i++)
48298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->power_1[i] = FLOAT_ONE;
48398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*M*K*C;i++)
48498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->W[i] = 0;
48598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
48698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word32_t sum = 0;
48798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Ratio of ~10 between adaptation rate of first and last block */
48898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1);
48998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->prop[0] = QCONST16(.7, 15);
49098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = EXTEND32(st->prop[0]);
49198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=1;i<M;i++)
49298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
49398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->prop[i] = MULT16_16_Q15(st->prop[i-1], decay);
49498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         sum = ADD32(sum, EXTEND32(st->prop[i]));
49598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
49698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=M-1;i>=0;i--)
49798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
49898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum);
49998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
50098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
50198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
50298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t));
50398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
50498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
50598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->preemph = QCONST16(.9,15);
50698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->sampling_rate<12000)
50798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->notch_radius = QCONST16(.9, 15);
50898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else if (st->sampling_rate<24000)
50998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->notch_radius = QCONST16(.982, 15);
51098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else
51198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->notch_radius = QCONST16(.992, 15);
51298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
51398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t));
51498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->adapted = 0;
51598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Pey = st->Pyy = FLOAT_ONE;
51698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
51798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
51898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg1 = st->Davg2 = 0;
51998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
52098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
52198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
52398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
52498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf_started = 0;
52598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return st;
52798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
52898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Resets echo canceller state */
53098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_state_reset(SpeexEchoState *st)
53198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
53298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i, M, N, C, K;
53398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->cancel_count=0;
53498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->screwed_up = 0;
53598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   N = st->window_size;
53698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   M = st->M;
53798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   C=st->C;
53898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   K=st->K;
53998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*M;i++)
54098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->W[i] = 0;
54198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
54298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*M;i++)
54398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->foreground[i] = 0;
54498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
54598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*(M+1);i++)
54698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->X[i] = 0;
54798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<=st->frame_size;i++)
54898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
54998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->power[i] = 0;
55098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->power_1[i] = FLOAT_ONE;
55198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Eh[i] = 0;
55298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Yh[i] = 0;
55398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
55498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<st->frame_size;i++)
55598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
55698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->last_y[i] = 0;
55798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
55898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*C;i++)
55998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
56098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->E[i] = 0;
56198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
56298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N*K;i++)
56398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
56498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->x[i] = 0;
56598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
56698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<2*C;i++)
56798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->notch_mem[i] = 0;
56898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<C;i++)
56998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->memD[i]=st->memE[i]=0;
57098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<K;i++)
57198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->memX[i]=0;
57298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
57398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->saturated = 0;
57498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->adapted = 0;
57598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->sum_adapt = 0;
57698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Pey = st->Pyy = FLOAT_ONE;
57798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
57898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg1 = st->Davg2 = 0;
57998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
58098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
58198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<3*st->frame_size;i++)
58298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->play_buf[i] = 0;
58398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
58498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf_started = 0;
58598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
58698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
58798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
58898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Destroys an echo canceller state */
58998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_state_destroy(SpeexEchoState *st)
59098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
59198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_fft_destroy(st->fft_table);
59298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
59398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->e);
59498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->x);
59598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->input);
59698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->y);
59798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->last_y);
59898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Yf);
59998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Rf);
60098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Xf);
60198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Yh);
60298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Eh);
60398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
60498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->X);
60598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->Y);
60698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->E);
60798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->W);
60898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
60998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->foreground);
61098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
61198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->PHI);
61298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->power);
61398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->power_1);
61498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->window);
61598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->prop);
61698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->wtmp);
61798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
61898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->wtmp2);
61998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
62098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->memX);
62198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->memD);
62298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->memE);
62398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->notch_mem);
62498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
62598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->play_buf);
62698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st);
62798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
62898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef DUMP_ECHO_CANCEL_DATA
62998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fclose(rFile);
63098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fclose(pFile);
63198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   fclose(oFile);
63298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   rFile = pFile = oFile = NULL;
63398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
63498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
63598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
63698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
63798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
63898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i;
63998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/
64098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->play_buf_started = 1;
64198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->play_buf_pos>=st->frame_size)
64298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
64398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_echo_cancellation(st, rec, st->play_buf, out);
64498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->play_buf_pos -= st->frame_size;
64598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->play_buf_pos;i++)
64698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->play_buf[i] = st->play_buf[i+st->frame_size];
64798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
64898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_warning("No playback frame available (your application is buggy and/or got xruns)");
64998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (st->play_buf_pos!=0)
65098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
65198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_warning("internal playback buffer corruption?");
65298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->play_buf_pos = 0;
65398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
65498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
65598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         out[i] = rec[i];
65698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
65798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
65898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
65998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
66098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
66198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
66298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (!st->play_buf_started)
66398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
66498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_warning("discarded first playback frame");
66598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return;
66698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
66798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size)
66898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
66998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      int i;
67098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
67198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->play_buf[st->play_buf_pos+i] = play[i];
67298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->play_buf_pos += st->frame_size;
67398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size)
67498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
67598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)");
67698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (i=0;i<st->frame_size;i++)
67798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->play_buf[st->play_buf_pos+i] = play[i];
67898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->play_buf_pos += st->frame_size;
67998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
68098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
68198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)");
68298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
68398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
68498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
68598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
68698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
68798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
68898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_echo_cancellation(st, in, far_end, out);
68998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
69098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
69198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/** Performs echo cancellation on a frame */
69298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
69398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
69498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i,j, chan, speak;
69598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int N,M, C, K;
69698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t Syy,See,Sxx,Sdd, Sff;
69798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
69898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t Dbf;
69998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int update_foreground;
70098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
70198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t Sey;
70298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t ss, ss_1;
70398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
70498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_float_t alpha, alpha_1;
70598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t RER;
70698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t tmp32;
70798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
70898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   N = st->window_size;
70998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   M = st->M;
71098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   C = st->C;
71198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   K = st->K;
71298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
71398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->cancel_count++;
71498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
71598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ss=DIV32_16(11469,M);
71698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ss_1 = SUB16(32767,ss);
71798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
71898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ss=.35/M;
71998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ss_1 = 1-ss;
72098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
72198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
72298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (chan = 0; chan < C; chan++)
72398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
72498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Apply a notch filter to make sure DC doesn't end up causing problems */
72598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C);
72698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Copy input data to buffer and apply pre-emphasis */
72798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Copy input data to buffer */
72898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
72998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
73098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_word32_t tmp32;
73198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* FIXME: This core has changed a bit, need to merge properly */
73298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan])));
73398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
73498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 > 32767)
73598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
73698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = 32767;
73798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            if (st->saturated == 0)
73898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->saturated = 1;
73998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
74098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 < -32767)
74198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
74298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = -32767;
74398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            if (st->saturated == 0)
74498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->saturated = 1;
74598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
74698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
74798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->memD[chan] = st->input[chan*st->frame_size+i];
74898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
74998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
75098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
75198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
75298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (speak = 0; speak < K; speak++)
75398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
75498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
75598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
75698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_word32_t tmp32;
75798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->x[speak*N+i] = st->x[speak*N+i+st->frame_size];
75898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak])));
75998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
76098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
76198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 > 32767)
76298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
76398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = 32767;
76498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->saturated = M+1;
76598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
76698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 < -32767)
76798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
76898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = -32767;
76998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->saturated = M+1;
77098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
77198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
77298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32);
77398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->memX[speak] = far_end[i*K+speak];
77498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
77598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
77698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
77798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (speak = 0; speak < K; speak++)
77898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
77998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Shift memory: this could be optimized eventually*/
78098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (j=M-1;j>=0;j--)
78198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
78298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (i=0;i<N;i++)
78398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i];
78498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
78598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Convert x (echo input) to frequency domain */
78698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]);
78798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
78898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
78998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Sxx = 0;
79098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (speak = 0; speak < K; speak++)
79198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
79298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
79398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      power_spectrum_accum(st->X+speak*N, st->Xf, N);
79498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
79598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
79698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Sff = 0;
79798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (chan = 0; chan < C; chan++)
79898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
79998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
80098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Compute foreground filter */
80198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K);
80298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N);
80398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
80498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]);
80598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
80698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
80798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
80898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
80998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Adjust proportional adaption rate */
81098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* FIXME: Adjust that for C, K*/
81198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->adapted)
81298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      mdf_adjust_prop (st->W, N, M, C*K, st->prop);
81398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute weight gradient */
81498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->saturated == 0)
81598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
81698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (chan = 0; chan < C; chan++)
81798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
81898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (speak = 0; speak < K; speak++)
81998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
82098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (j=M-1;j>=0;j--)
82198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            {
82298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N);
82398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=0;i<N;i++)
82498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i];
82598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            }
82698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
82798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
82898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
82998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->saturated--;
83098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
83198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
83298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* FIXME: MC conversion required */
83398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Update weight to prevent circular convolution (MDF / AUMDF) */
83498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (chan = 0; chan < C; chan++)
83598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
83698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (speak = 0; speak < K; speak++)
83798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
83898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (j=0;j<M;j++)
83998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
84098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* This is a variant of the Alternatively Updated MDF (AUMDF) */
84198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Remove the "if" to make this an MDF filter */
84298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            if (j==0 || st->cancel_count%(M-1) == j-1)
84398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            {
84498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
84598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=0;i<N;i++)
84698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->wtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16));
84798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
84898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=0;i<st->frame_size;i++)
84998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               {
85098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->wtmp[i]=0;
85198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               }
85298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=st->frame_size;i<N;i++)
85398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               {
85498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
85598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               }
85698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               spx_fft(st->fft_table, st->wtmp, st->wtmp2);
85798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
85898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=0;i<N;i++)
85998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
86098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
86198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp);
86298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               for (i=st->frame_size;i<N;i++)
86398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               {
86498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project                  st->wtmp[i]=0;
86598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               }
86698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]);
86798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
86898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            }
86998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
87098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
87198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
87298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
87398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* So we can use power_spectrum_accum */
87498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<=st->frame_size;i++)
87598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Rf[i] = st->Yf[i] = st->Xf[i] = 0;
87698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
87798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Dbf = 0;
87898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   See = 0;
87998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
88098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Difference in response, this is used to estimate the variance of our residual power estimate */
88198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (chan = 0; chan < C; chan++)
88298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
88398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K);
88498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N);
88598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
88698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]);
88798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
88898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
88998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
89098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
89198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
89298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
89398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
89498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef TWO_PATH
89598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Sff = See;
89698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
89798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
89898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
89998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Logic for updating the foreground filter */
90098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
90198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* For two time windows, compute the mean of the energy difference, as well as the variance */
90298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See)));
90398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See)));
90498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf)));
90598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf)));
90698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
90798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Equivalent float code:
90898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg1 = .6*st->Davg1 + .4*(Sff-See);
90998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Davg2 = .85*st->Davg2 + .15*(Sff-See);
91098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf;
91198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf;
91298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   */
91398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
91498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   update_foreground = 0;
91598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Check if we have a statistically significant reduction in the residual echo */
91698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */
91798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf)))
91898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      update_foreground = 1;
91998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1))))
92098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      update_foreground = 1;
92198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2))))
92298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      update_foreground = 1;
92398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
92498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Do we update? */
92598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (update_foreground)
92698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
92798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Davg1 = st->Davg2 = 0;
92898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
92998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Copy background filter to foreground filter */
93098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<N*M*C*K;i++)
93198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
93298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Apply a smooth transition so as to not introduce blocking artifacts */
93398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (chan = 0; chan < C; chan++)
93498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (i=0;i<st->frame_size;i++)
93598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]);
93698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
93798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      int reset_background=0;
93898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Otherwise, check if the background filter is significantly worse */
93998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf))))
94098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         reset_background = 1;
94198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1)))
94298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         reset_background = 1;
94398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2)))
94498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         reset_background = 1;
94598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (reset_background)
94698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
94798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* Copy foreground filter to background filter */
94898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (i=0;i<N*M*C*K;i++)
94998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
95098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* We also need to copy the output so as to get correct adaptation */
95198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (chan = 0; chan < C; chan++)
95298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
95398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (i=0;i<st->frame_size;i++)
95498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size];
95598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (i=0;i<st->frame_size;i++)
95698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
95798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
95898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         See = Sff;
95998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->Davg1 = st->Davg2 = 0;
96098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
96198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
96298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
96398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
96498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
96598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Sey = Syy = Sdd = 0;
96698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (chan = 0; chan < C; chan++)
96798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
96898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Compute error signal (for the output with de-emphasis) */
96998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
97098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
97198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_word32_t tmp_out;
97298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef TWO_PATH
97398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
97498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
97598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size]));
97698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
97798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
97898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* This is an arbitrary test for saturation in the microphone signal */
97998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
98098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
98198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (st->saturated == 0)
98298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->saturated = 1;
98398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
98498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         out[i*C+chan] = WORD2INT(tmp_out);
98598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->memE[chan] = tmp_out;
98698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
98798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
98898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef DUMP_ECHO_CANCEL_DATA
98998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      dump_audio(in, far_end, out, st->frame_size);
99098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
99198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
99298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Compute error signal (filter update version) */
99398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
99498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
99598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->e[chan*N+i+st->frame_size] = st->e[chan*N+i];
99698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->e[chan*N+i] = 0;
99798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
99898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
99998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Compute a bunch of correlations */
100098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* FIXME: bad merge */
100198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
100298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
100398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size);
100498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
100598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Convert error to frequency domain */
100698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N);
100798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
100898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->y[i+chan*N] = 0;
100998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N);
101098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Compute power spectrum of echo (X), error (E) and filter response (Y) */
101298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      power_spectrum_accum(st->E+chan*N, st->Rf, N);
101398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      power_spectrum_accum(st->Y+chan*N, st->Yf, N);
101498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
101698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
101898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Do some sanity check */
102098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (!(Syy>=0 && Sxx>=0 && See >= 0)
102198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef FIXED_POINT
102298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9)
102398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
102498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      )
102598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
102698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Things have gone really bad */
102798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->screwed_up += 50;
102898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size*C;i++)
102998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         out[i] = 0;
103098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)))
103198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
103298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* AEC seems to add lots of echo instead of removing it, let's see if it will improve */
103398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->screwed_up++;
103498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
103598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Everything's fine */
103698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->screwed_up=0;
103798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
103898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->screwed_up>=50)
103998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
104098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now.");
104198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      speex_echo_state_reset(st);
104298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return;
104398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
104498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
104598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Add a small noise floor to make sure not to have problems when dividing */
104698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   See = MAX32(See, SHR32(MULT16_16(N, 100),6));
104798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
104898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (speak = 0; speak < K; speak++)
104998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
105098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
105198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      power_spectrum_accum(st->X+speak*N, st->Xf, N);
105298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
105398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
105498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
105598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Smooth far end energy estimate over time */
105698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=0;j<=st->frame_size;j++)
105798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
105898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
105998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute filtered spectra and (cross-)correlations */
106098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (j=st->frame_size;j>=0;j--)
106198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
106298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_float_t Eh, Yh;
106398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]);
106498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]);
106598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
106698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
106798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
106898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]);
106998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]);
107098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
107198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j];
107298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
107398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
107498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
107598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
107698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Pyy = FLOAT_SQRT(Pyy);
107798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Pey = FLOAT_DIVU(Pey,Pyy);
107898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
107998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute correlation updatete rate */
108098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   tmp32 = MULT16_32_Q15(st->beta0,Syy);
108198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (tmp32 > MULT16_32_Q15(st->beta_max,See))
108298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp32 = MULT16_32_Q15(st->beta_max,See);
108398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   alpha = FLOAT_DIV32(tmp32, See);
108498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha);
108598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Update correlations (recursive average) */
108698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey));
108798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy));
108898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (FLOAT_LT(st->Pyy, FLOAT_ONE))
108998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Pyy = FLOAT_ONE;
109098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */
109198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy)))
109298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy);
109398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (FLOAT_GT(st->Pey, st->Pyy))
109498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->Pey = st->Pyy;
109598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* leak_estimate is the linear regression result */
109698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14));
109798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */
109898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->leak_estimate > 16383)
109998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->leak_estimate = 32767;
110098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else
110198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->leak_estimate = SHL16(st->leak_estimate,1);
110298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*printf ("%f\n", st->leak_estimate);*/
110398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
110498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute Residual to Error Ratio */
110598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
110698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   tmp32 = MULT16_32_Q15(st->leak_estimate,Syy);
110798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
110898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Check for y in e (lower bound on RER) */
110998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
111098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_float_t bound = PSEUDOFLOAT(Sey);
111198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy)));
111298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (FLOAT_GT(bound, PSEUDOFLOAT(See)))
111398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp32 = See;
111498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else if (tmp32 < FLOAT_EXTRACT32(bound))
111598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp32 = FLOAT_EXTRACT32(bound);
111698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
111798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (tmp32 > SHR32(See,1))
111898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      tmp32 = SHR32(See,1);
111998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
112098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
112198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See;
112298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Check for y in e (lower bound on RER) */
112398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (RER < Sey*Sey/(1+See*Syy))
112498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      RER = Sey*Sey/(1+See*Syy);
112598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (RER > .5)
112698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      RER = .5;
112798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
112898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
112998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* We consider that the filter has had minimal adaptation if the following is true*/
113098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (!st->adapted && st->sum_adapt > SHL32(EXTEND32(M),15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy))
113198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
113298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->adapted = 1;
113398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
113498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
113598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->adapted)
113698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
113798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Normal learning rate calculation once we're past the minimal adaptation phase */
113898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<=st->frame_size;i++)
113998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
114098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_word32_t r, e;
114198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* Compute frequency-domain adaptation mask */
114298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3));
114398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         e = SHL32(st->Rf[i],3)+1;
114498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
114598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (r>SHR32(e,1))
114698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            r = SHR32(e,1);
114798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
114898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (r>.5*e)
114998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            r = .5*e;
115098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
115198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
115298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
115398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
115498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
115598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
115698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Temporary adaption rate if filter is not yet adapted enough */
115798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word16_t adapt_rate=0;
115898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
115998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (Sxx > SHR32(MULT16_16(N, 1000),6))
116098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
116198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
116298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
116398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 > SHR32(See,2))
116498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = SHR32(See,2);
116598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
116698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (tmp32 > .25*See)
116798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            tmp32 = .25*See;
116898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
116998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
117098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
117198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<=st->frame_size;i++)
117298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1);
117398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
117498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
117598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* How much have we adapted so far? */
117698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
117798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
117898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
117998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* FIXME: MC conversion required */
118098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
118198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->last_y[i] = st->last_y[st->frame_size+i];
118298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->adapted)
118398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
118498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* If the filter is adapted, take the filtered echo */
118598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->frame_size;i++)
118698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->last_y[st->frame_size+i] = in[i]-out[i];
118798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
118898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* If filter isn't adapted yet, all we can do is take the far end signal directly */
118998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* moved earlier: for (i=0;i<N;i++)
119098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->last_y[i] = st->x[i];*/
119198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
119298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
119398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
119498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
119598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Compute spectrum of estimated echo for use in an echo post-filter */
119698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectvoid speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len)
119798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
119898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i;
119998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t leak2;
120098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int N;
120198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
120298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   N = st->window_size;
120398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
120498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Apply hanning window (should pre-compute it)*/
120598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<N;i++)
120698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
120798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
120898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute power spectrum of the echo */
120998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_fft(st->fft_table, st->y, st->Y);
121098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   power_spectrum(st->Y, residual_echo, N);
121198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
121298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
121398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->leak_estimate > 16383)
121498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      leak2 = 32767;
121598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else
121698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      leak2 = SHL16(st->leak_estimate, 1);
121798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
121898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->leak_estimate>.5)
121998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      leak2 = 1;
122098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else
122198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      leak2 = 2*st->leak_estimate;
122298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
122398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Estimate residual echo */
122498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<=st->frame_size;i++)
122598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]);
122698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
122798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
122898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
122998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
123098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
123198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   switch(request)
123298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
123398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
123498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case SPEEX_ECHO_GET_FRAME_SIZE:
123598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         (*(int*)ptr) = st->frame_size;
123698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         break;
123798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case SPEEX_ECHO_SET_SAMPLING_RATE:
123898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sampling_rate = (*(int*)ptr);
123998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
124098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
124198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate);
124298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate);
124398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
124498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
124598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
124698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
124798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (st->sampling_rate<12000)
124898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->notch_radius = QCONST16(.9, 15);
124998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         else if (st->sampling_rate<24000)
125098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->notch_radius = QCONST16(.982, 15);
125198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         else
125298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->notch_radius = QCONST16(.992, 15);
125398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         break;
125498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case SPEEX_ECHO_GET_SAMPLING_RATE:
125598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         (*(int*)ptr) = st->sampling_rate;
125698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         break;
125798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
125898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /*FIXME: Implement this for multiple channels */
125998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         *((spx_int32_t *)ptr) = st->M * st->frame_size;
126098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         break;
126198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
126298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
126398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         int M = st->M, N = st->window_size, n = st->frame_size, i, j;
126498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_int32_t *filt = (spx_int32_t *) ptr;
126598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for(j=0;j<M;j++)
126698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
126798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /*FIXME: Implement this for multiple channels */
126898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
126998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (i=0;i<N;i++)
127098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN));
127198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
127298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
127398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
127498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
127598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for(i=0;i<n;i++)
127698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               filt[j*n+i] = PSHR32(MULT16_16(32767,st->wtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN);
127798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
127898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
127998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         break;
128098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      default:
128198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_warning_int("Unknown speex_echo_ctl request: ", request);
128298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return -1;
128398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
128498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return 0;
128598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
1286