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