xref: /aosp_15_r20/external/speex/libspeexdsp/preprocess.c (revision 28e138c64d234588b5cd2a8a403b584bd3036e4e)
1*28e138c6SAndroid Build Coastguard Worker /* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin)
2*28e138c6SAndroid Build Coastguard Worker    Copyright (C) 2004-2006 Epic Games
3*28e138c6SAndroid Build Coastguard Worker 
4*28e138c6SAndroid Build Coastguard Worker    File: preprocess.c
5*28e138c6SAndroid Build Coastguard Worker    Preprocessor with denoising based on the algorithm by Ephraim and Malah
6*28e138c6SAndroid Build Coastguard Worker 
7*28e138c6SAndroid Build Coastguard Worker    Redistribution and use in source and binary forms, with or without
8*28e138c6SAndroid Build Coastguard Worker    modification, are permitted provided that the following conditions are
9*28e138c6SAndroid Build Coastguard Worker    met:
10*28e138c6SAndroid Build Coastguard Worker 
11*28e138c6SAndroid Build Coastguard Worker    1. Redistributions of source code must retain the above copyright notice,
12*28e138c6SAndroid Build Coastguard Worker    this list of conditions and the following disclaimer.
13*28e138c6SAndroid Build Coastguard Worker 
14*28e138c6SAndroid Build Coastguard Worker    2. Redistributions in binary form must reproduce the above copyright
15*28e138c6SAndroid Build Coastguard Worker    notice, this list of conditions and the following disclaimer in the
16*28e138c6SAndroid Build Coastguard Worker    documentation and/or other materials provided with the distribution.
17*28e138c6SAndroid Build Coastguard Worker 
18*28e138c6SAndroid Build Coastguard Worker    3. The name of the author may not be used to endorse or promote products
19*28e138c6SAndroid Build Coastguard Worker    derived from this software without specific prior written permission.
20*28e138c6SAndroid Build Coastguard Worker 
21*28e138c6SAndroid Build Coastguard Worker    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22*28e138c6SAndroid Build Coastguard Worker    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23*28e138c6SAndroid Build Coastguard Worker    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24*28e138c6SAndroid Build Coastguard Worker    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25*28e138c6SAndroid Build Coastguard Worker    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26*28e138c6SAndroid Build Coastguard Worker    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27*28e138c6SAndroid Build Coastguard Worker    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*28e138c6SAndroid Build Coastguard Worker    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29*28e138c6SAndroid Build Coastguard Worker    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30*28e138c6SAndroid Build Coastguard Worker    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31*28e138c6SAndroid Build Coastguard Worker    POSSIBILITY OF SUCH DAMAGE.
32*28e138c6SAndroid Build Coastguard Worker */
33*28e138c6SAndroid Build Coastguard Worker 
34*28e138c6SAndroid Build Coastguard Worker 
35*28e138c6SAndroid Build Coastguard Worker /*
36*28e138c6SAndroid Build Coastguard Worker    Recommended papers:
37*28e138c6SAndroid Build Coastguard Worker 
38*28e138c6SAndroid Build Coastguard Worker    Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
39*28e138c6SAndroid Build Coastguard Worker    short-time spectral amplitude estimator". IEEE Transactions on Acoustics,
40*28e138c6SAndroid Build Coastguard Worker    Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984.
41*28e138c6SAndroid Build Coastguard Worker 
42*28e138c6SAndroid Build Coastguard Worker    Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
43*28e138c6SAndroid Build Coastguard Worker    log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and
44*28e138c6SAndroid Build Coastguard Worker    Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985.
45*28e138c6SAndroid Build Coastguard Worker 
46*28e138c6SAndroid Build Coastguard Worker    I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments".
47*28e138c6SAndroid Build Coastguard Worker    Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001.
48*28e138c6SAndroid Build Coastguard Worker 
49*28e138c6SAndroid Build Coastguard Worker    Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic
50*28e138c6SAndroid Build Coastguard Worker    approach to combined acoustic echo cancellation and noise reduction". IEEE
51*28e138c6SAndroid Build Coastguard Worker    Transactions on Speech and Audio Processing, 2002.
52*28e138c6SAndroid Build Coastguard Worker 
53*28e138c6SAndroid Build Coastguard Worker    J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation
54*28e138c6SAndroid Build Coastguard Worker    of simultaneous non-stationary sources". In Proceedings IEEE International
55*28e138c6SAndroid Build Coastguard Worker    Conference on Acoustics, Speech, and Signal Processing, 2004.
56*28e138c6SAndroid Build Coastguard Worker */
57*28e138c6SAndroid Build Coastguard Worker 
58*28e138c6SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
59*28e138c6SAndroid Build Coastguard Worker #include "config.h"
60*28e138c6SAndroid Build Coastguard Worker #endif
61*28e138c6SAndroid Build Coastguard Worker 
62*28e138c6SAndroid Build Coastguard Worker #include <math.h>
63*28e138c6SAndroid Build Coastguard Worker #include "speex/speex_preprocess.h"
64*28e138c6SAndroid Build Coastguard Worker #include "speex/speex_echo.h"
65*28e138c6SAndroid Build Coastguard Worker #include "arch.h"
66*28e138c6SAndroid Build Coastguard Worker #include "fftwrap.h"
67*28e138c6SAndroid Build Coastguard Worker #include "filterbank.h"
68*28e138c6SAndroid Build Coastguard Worker #include "math_approx.h"
69*28e138c6SAndroid Build Coastguard Worker #include "os_support.h"
70*28e138c6SAndroid Build Coastguard Worker 
71*28e138c6SAndroid Build Coastguard Worker #define LOUDNESS_EXP 5.f
72*28e138c6SAndroid Build Coastguard Worker #define AMP_SCALE .001f
73*28e138c6SAndroid Build Coastguard Worker #define AMP_SCALE_1 1000.f
74*28e138c6SAndroid Build Coastguard Worker 
75*28e138c6SAndroid Build Coastguard Worker #define NB_BANDS 24
76*28e138c6SAndroid Build Coastguard Worker 
77*28e138c6SAndroid Build Coastguard Worker #define SPEECH_PROB_START_DEFAULT       QCONST16(0.35f,15)
78*28e138c6SAndroid Build Coastguard Worker #define SPEECH_PROB_CONTINUE_DEFAULT    QCONST16(0.20f,15)
79*28e138c6SAndroid Build Coastguard Worker #define NOISE_SUPPRESS_DEFAULT       -15
80*28e138c6SAndroid Build Coastguard Worker #define ECHO_SUPPRESS_DEFAULT        -40
81*28e138c6SAndroid Build Coastguard Worker #define ECHO_SUPPRESS_ACTIVE_DEFAULT -15
82*28e138c6SAndroid Build Coastguard Worker 
83*28e138c6SAndroid Build Coastguard Worker #ifndef NULL
84*28e138c6SAndroid Build Coastguard Worker #define NULL 0
85*28e138c6SAndroid Build Coastguard Worker #endif
86*28e138c6SAndroid Build Coastguard Worker 
87*28e138c6SAndroid Build Coastguard Worker #define SQR(x) ((x)*(x))
88*28e138c6SAndroid Build Coastguard Worker #define SQR16(x) (MULT16_16((x),(x)))
89*28e138c6SAndroid Build Coastguard Worker #define SQR16_Q15(x) (MULT16_16_Q15((x),(x)))
90*28e138c6SAndroid Build Coastguard Worker 
91*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
DIV32_16_Q8(spx_word32_t a,spx_word32_t b)92*28e138c6SAndroid Build Coastguard Worker static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b)
93*28e138c6SAndroid Build Coastguard Worker {
94*28e138c6SAndroid Build Coastguard Worker    if (SHR32(a,7) >= b)
95*28e138c6SAndroid Build Coastguard Worker    {
96*28e138c6SAndroid Build Coastguard Worker       return 32767;
97*28e138c6SAndroid Build Coastguard Worker    } else {
98*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,23))
99*28e138c6SAndroid Build Coastguard Worker       {
100*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,8);
101*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,8);
102*28e138c6SAndroid Build Coastguard Worker       }
103*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,19))
104*28e138c6SAndroid Build Coastguard Worker       {
105*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,4);
106*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,4);
107*28e138c6SAndroid Build Coastguard Worker       }
108*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,15))
109*28e138c6SAndroid Build Coastguard Worker       {
110*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,4);
111*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,4);
112*28e138c6SAndroid Build Coastguard Worker       }
113*28e138c6SAndroid Build Coastguard Worker       a = SHL32(a,8);
114*28e138c6SAndroid Build Coastguard Worker       return PDIV32_16(a,b);
115*28e138c6SAndroid Build Coastguard Worker    }
116*28e138c6SAndroid Build Coastguard Worker 
117*28e138c6SAndroid Build Coastguard Worker }
DIV32_16_Q15(spx_word32_t a,spx_word32_t b)118*28e138c6SAndroid Build Coastguard Worker static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b)
119*28e138c6SAndroid Build Coastguard Worker {
120*28e138c6SAndroid Build Coastguard Worker    if (SHR32(a,15) >= b)
121*28e138c6SAndroid Build Coastguard Worker    {
122*28e138c6SAndroid Build Coastguard Worker       return 32767;
123*28e138c6SAndroid Build Coastguard Worker    } else {
124*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,23))
125*28e138c6SAndroid Build Coastguard Worker       {
126*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,8);
127*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,8);
128*28e138c6SAndroid Build Coastguard Worker       }
129*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,19))
130*28e138c6SAndroid Build Coastguard Worker       {
131*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,4);
132*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,4);
133*28e138c6SAndroid Build Coastguard Worker       }
134*28e138c6SAndroid Build Coastguard Worker       if (b>=QCONST32(1,15))
135*28e138c6SAndroid Build Coastguard Worker       {
136*28e138c6SAndroid Build Coastguard Worker          a = SHR32(a,4);
137*28e138c6SAndroid Build Coastguard Worker          b = SHR32(b,4);
138*28e138c6SAndroid Build Coastguard Worker       }
139*28e138c6SAndroid Build Coastguard Worker       a = SHL32(a,15)-a;
140*28e138c6SAndroid Build Coastguard Worker       return DIV32_16(a,b);
141*28e138c6SAndroid Build Coastguard Worker    }
142*28e138c6SAndroid Build Coastguard Worker }
143*28e138c6SAndroid Build Coastguard Worker #define SNR_SCALING 256.f
144*28e138c6SAndroid Build Coastguard Worker #define SNR_SCALING_1 0.0039062f
145*28e138c6SAndroid Build Coastguard Worker #define SNR_SHIFT 8
146*28e138c6SAndroid Build Coastguard Worker 
147*28e138c6SAndroid Build Coastguard Worker #define FRAC_SCALING 32767.f
148*28e138c6SAndroid Build Coastguard Worker #define FRAC_SCALING_1 3.0518e-05
149*28e138c6SAndroid Build Coastguard Worker #define FRAC_SHIFT 1
150*28e138c6SAndroid Build Coastguard Worker 
151*28e138c6SAndroid Build Coastguard Worker #define EXPIN_SCALING 2048.f
152*28e138c6SAndroid Build Coastguard Worker #define EXPIN_SCALING_1 0.00048828f
153*28e138c6SAndroid Build Coastguard Worker #define EXPIN_SHIFT 11
154*28e138c6SAndroid Build Coastguard Worker #define EXPOUT_SCALING_1 1.5259e-05
155*28e138c6SAndroid Build Coastguard Worker 
156*28e138c6SAndroid Build Coastguard Worker #define NOISE_SHIFT 7
157*28e138c6SAndroid Build Coastguard Worker 
158*28e138c6SAndroid Build Coastguard Worker #else
159*28e138c6SAndroid Build Coastguard Worker 
160*28e138c6SAndroid Build Coastguard Worker #define DIV32_16_Q8(a,b) ((a)/(b))
161*28e138c6SAndroid Build Coastguard Worker #define DIV32_16_Q15(a,b) ((a)/(b))
162*28e138c6SAndroid Build Coastguard Worker #define SNR_SCALING 1.f
163*28e138c6SAndroid Build Coastguard Worker #define SNR_SCALING_1 1.f
164*28e138c6SAndroid Build Coastguard Worker #define SNR_SHIFT 0
165*28e138c6SAndroid Build Coastguard Worker #define FRAC_SCALING 1.f
166*28e138c6SAndroid Build Coastguard Worker #define FRAC_SCALING_1 1.f
167*28e138c6SAndroid Build Coastguard Worker #define FRAC_SHIFT 0
168*28e138c6SAndroid Build Coastguard Worker #define NOISE_SHIFT 0
169*28e138c6SAndroid Build Coastguard Worker 
170*28e138c6SAndroid Build Coastguard Worker #define EXPIN_SCALING 1.f
171*28e138c6SAndroid Build Coastguard Worker #define EXPIN_SCALING_1 1.f
172*28e138c6SAndroid Build Coastguard Worker #define EXPOUT_SCALING_1 1.f
173*28e138c6SAndroid Build Coastguard Worker 
174*28e138c6SAndroid Build Coastguard Worker #endif
175*28e138c6SAndroid Build Coastguard Worker 
176*28e138c6SAndroid Build Coastguard Worker /** Speex pre-processor state. */
177*28e138c6SAndroid Build Coastguard Worker struct SpeexPreprocessState_ {
178*28e138c6SAndroid Build Coastguard Worker    /* Basic info */
179*28e138c6SAndroid Build Coastguard Worker    int    frame_size;        /**< Number of samples processed each time */
180*28e138c6SAndroid Build Coastguard Worker    int    ps_size;           /**< Number of points in the power spectrum */
181*28e138c6SAndroid Build Coastguard Worker    int    sampling_rate;     /**< Sampling rate of the input/output */
182*28e138c6SAndroid Build Coastguard Worker    int    nbands;
183*28e138c6SAndroid Build Coastguard Worker    FilterBank *bank;
184*28e138c6SAndroid Build Coastguard Worker 
185*28e138c6SAndroid Build Coastguard Worker    /* Parameters */
186*28e138c6SAndroid Build Coastguard Worker    int    denoise_enabled;
187*28e138c6SAndroid Build Coastguard Worker    int    vad_enabled;
188*28e138c6SAndroid Build Coastguard Worker    int    dereverb_enabled;
189*28e138c6SAndroid Build Coastguard Worker    spx_word16_t  reverb_decay;
190*28e138c6SAndroid Build Coastguard Worker    spx_word16_t  reverb_level;
191*28e138c6SAndroid Build Coastguard Worker    spx_word16_t speech_prob_start;
192*28e138c6SAndroid Build Coastguard Worker    spx_word16_t speech_prob_continue;
193*28e138c6SAndroid Build Coastguard Worker    int    noise_suppress;
194*28e138c6SAndroid Build Coastguard Worker    int    echo_suppress;
195*28e138c6SAndroid Build Coastguard Worker    int    echo_suppress_active;
196*28e138c6SAndroid Build Coastguard Worker    SpeexEchoState *echo_state;
197*28e138c6SAndroid Build Coastguard Worker 
198*28e138c6SAndroid Build Coastguard Worker    spx_word16_t	speech_prob;  /**< Probability last frame was speech */
199*28e138c6SAndroid Build Coastguard Worker 
200*28e138c6SAndroid Build Coastguard Worker    /* DSP-related arrays */
201*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *frame;      /**< Processing frame (2*ps_size) */
202*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *ft;         /**< Processing frame in freq domain (2*ps_size) */
203*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *ps;         /**< Current power spectrum */
204*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *gain2;      /**< Adjusted gains */
205*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *gain_floor; /**< Minimum gain allowed */
206*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *window;     /**< Analysis/Synthesis window */
207*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *noise;      /**< Noise estimate */
208*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */
209*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *old_ps;     /**< Power spectrum for last frame */
210*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *gain;       /**< Ephraim Malah gain */
211*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *prior;      /**< A-priori SNR */
212*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *post;       /**< A-posteriori SNR */
213*28e138c6SAndroid Build Coastguard Worker 
214*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *S;          /**< Smoothed power spectrum */
215*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *Smin;       /**< See Cohen paper */
216*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *Stmp;       /**< See Cohen paper */
217*28e138c6SAndroid Build Coastguard Worker    int *update_prob;         /**< Probability of speech presence for noise update */
218*28e138c6SAndroid Build Coastguard Worker 
219*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *zeta;       /**< Smoothed a priori SNR */
220*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *echo_noise;
221*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *residual_echo;
222*28e138c6SAndroid Build Coastguard Worker 
223*28e138c6SAndroid Build Coastguard Worker    /* Misc */
224*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *inbuf;      /**< Input buffer (overlapped analysis) */
225*28e138c6SAndroid Build Coastguard Worker    spx_word16_t *outbuf;     /**< Output buffer (for overlap and add) */
226*28e138c6SAndroid Build Coastguard Worker 
227*28e138c6SAndroid Build Coastguard Worker    /* AGC stuff, only for floating point for now */
228*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
229*28e138c6SAndroid Build Coastguard Worker    int    agc_enabled;
230*28e138c6SAndroid Build Coastguard Worker    float  agc_level;
231*28e138c6SAndroid Build Coastguard Worker    float  loudness_accum;
232*28e138c6SAndroid Build Coastguard Worker    float *loudness_weight;   /**< Perceptual loudness curve */
233*28e138c6SAndroid Build Coastguard Worker    float  loudness;          /**< Loudness estimate */
234*28e138c6SAndroid Build Coastguard Worker    float  agc_gain;          /**< Current AGC gain */
235*28e138c6SAndroid Build Coastguard Worker    float  max_gain;          /**< Maximum gain allowed */
236*28e138c6SAndroid Build Coastguard Worker    float  max_increase_step; /**< Maximum increase in gain from one frame to another */
237*28e138c6SAndroid Build Coastguard Worker    float  max_decrease_step; /**< Maximum decrease in gain from one frame to another */
238*28e138c6SAndroid Build Coastguard Worker    float  prev_loudness;     /**< Loudness of previous frame */
239*28e138c6SAndroid Build Coastguard Worker    float  init_max;          /**< Current gain limit during initialisation */
240*28e138c6SAndroid Build Coastguard Worker #endif
241*28e138c6SAndroid Build Coastguard Worker    int    nb_adapt;          /**< Number of frames used for adaptation so far */
242*28e138c6SAndroid Build Coastguard Worker    int    was_speech;
243*28e138c6SAndroid Build Coastguard Worker    int    min_count;         /**< Number of frames processed so far */
244*28e138c6SAndroid Build Coastguard Worker    void  *fft_lookup;        /**< Lookup table for the FFT */
245*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
246*28e138c6SAndroid Build Coastguard Worker    int    frame_shift;
247*28e138c6SAndroid Build Coastguard Worker #endif
248*28e138c6SAndroid Build Coastguard Worker };
249*28e138c6SAndroid Build Coastguard Worker 
250*28e138c6SAndroid Build Coastguard Worker 
conj_window(spx_word16_t * w,int len)251*28e138c6SAndroid Build Coastguard Worker static void conj_window(spx_word16_t *w, int len)
252*28e138c6SAndroid Build Coastguard Worker {
253*28e138c6SAndroid Build Coastguard Worker    int i;
254*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<len;i++)
255*28e138c6SAndroid Build Coastguard Worker    {
256*28e138c6SAndroid Build Coastguard Worker       spx_word16_t tmp;
257*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
258*28e138c6SAndroid Build Coastguard Worker       spx_word16_t x = DIV32_16(MULT16_16(32767,i),len);
259*28e138c6SAndroid Build Coastguard Worker #else
260*28e138c6SAndroid Build Coastguard Worker       spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len);
261*28e138c6SAndroid Build Coastguard Worker #endif
262*28e138c6SAndroid Build Coastguard Worker       int inv=0;
263*28e138c6SAndroid Build Coastguard Worker       if (x<QCONST16(1.f,13))
264*28e138c6SAndroid Build Coastguard Worker       {
265*28e138c6SAndroid Build Coastguard Worker       } else if (x<QCONST16(2.f,13))
266*28e138c6SAndroid Build Coastguard Worker       {
267*28e138c6SAndroid Build Coastguard Worker          x=QCONST16(2.f,13)-x;
268*28e138c6SAndroid Build Coastguard Worker          inv=1;
269*28e138c6SAndroid Build Coastguard Worker       } else if (x<QCONST16(3.f,13))
270*28e138c6SAndroid Build Coastguard Worker       {
271*28e138c6SAndroid Build Coastguard Worker          x=x-QCONST16(2.f,13);
272*28e138c6SAndroid Build Coastguard Worker          inv=1;
273*28e138c6SAndroid Build Coastguard Worker       } else {
274*28e138c6SAndroid Build Coastguard Worker          x=QCONST16(2.f,13)-x+QCONST16(2.f,13); /* 4 - x */
275*28e138c6SAndroid Build Coastguard Worker       }
276*28e138c6SAndroid Build Coastguard Worker       x = MULT16_16_Q14(QCONST16(1.271903f,14), x);
277*28e138c6SAndroid Build Coastguard Worker       tmp = SQR16_Q15(QCONST16(.5f,15)-MULT16_16_P15(QCONST16(.5f,15),spx_cos_norm(SHL32(EXTEND32(x),2))));
278*28e138c6SAndroid Build Coastguard Worker       if (inv)
279*28e138c6SAndroid Build Coastguard Worker          tmp=SUB16(Q15_ONE,tmp);
280*28e138c6SAndroid Build Coastguard Worker       w[i]=spx_sqrt(SHL32(EXTEND32(tmp),15));
281*28e138c6SAndroid Build Coastguard Worker    }
282*28e138c6SAndroid Build Coastguard Worker }
283*28e138c6SAndroid Build Coastguard Worker 
284*28e138c6SAndroid Build Coastguard Worker 
285*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
286*28e138c6SAndroid Build Coastguard Worker /* This function approximates the gain function
287*28e138c6SAndroid Build Coastguard Worker    y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
288*28e138c6SAndroid Build Coastguard Worker    which multiplied by xi/(1+xi) is the optimal gain
289*28e138c6SAndroid Build Coastguard Worker    in the loudness domain ( sqrt[amplitude] )
290*28e138c6SAndroid Build Coastguard Worker    Input in Q11 format, output in Q15
291*28e138c6SAndroid Build Coastguard Worker */
hypergeom_gain(spx_word32_t xx)292*28e138c6SAndroid Build Coastguard Worker static inline spx_word32_t hypergeom_gain(spx_word32_t xx)
293*28e138c6SAndroid Build Coastguard Worker {
294*28e138c6SAndroid Build Coastguard Worker    int ind;
295*28e138c6SAndroid Build Coastguard Worker    spx_word16_t frac;
296*28e138c6SAndroid Build Coastguard Worker    /* Q13 table */
297*28e138c6SAndroid Build Coastguard Worker    static const spx_word16_t table[21] = {
298*28e138c6SAndroid Build Coastguard Worker        6730,  8357,  9868, 11267, 12563, 13770, 14898,
299*28e138c6SAndroid Build Coastguard Worker       15959, 16961, 17911, 18816, 19682, 20512, 21311,
300*28e138c6SAndroid Build Coastguard Worker       22082, 22827, 23549, 24250, 24931, 25594, 26241};
301*28e138c6SAndroid Build Coastguard Worker       ind = SHR32(xx,10);
302*28e138c6SAndroid Build Coastguard Worker       if (ind<0)
303*28e138c6SAndroid Build Coastguard Worker          return Q15_ONE;
304*28e138c6SAndroid Build Coastguard Worker       if (ind>19)
305*28e138c6SAndroid Build Coastguard Worker          return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT))));
306*28e138c6SAndroid Build Coastguard Worker       frac = SHL32(xx-SHL32(ind,10),5);
307*28e138c6SAndroid Build Coastguard Worker       return SHL32(DIV32_16(PSHR32(MULT16_16(Q15_ONE-frac,table[ind]) + MULT16_16(frac,table[ind+1]),7),(spx_sqrt(SHL32(xx,15)+6711))),7);
308*28e138c6SAndroid Build Coastguard Worker }
309*28e138c6SAndroid Build Coastguard Worker 
qcurve(spx_word16_t x)310*28e138c6SAndroid Build Coastguard Worker static inline spx_word16_t qcurve(spx_word16_t x)
311*28e138c6SAndroid Build Coastguard Worker {
312*28e138c6SAndroid Build Coastguard Worker    x = MAX16(x, 1);
313*28e138c6SAndroid Build Coastguard Worker    return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x))));
314*28e138c6SAndroid Build Coastguard Worker }
315*28e138c6SAndroid Build Coastguard Worker 
316*28e138c6SAndroid Build Coastguard Worker /* Compute the gain floor based on different floors for the background noise and residual echo */
compute_gain_floor(int noise_suppress,int effective_echo_suppress,spx_word32_t * noise,spx_word32_t * echo,spx_word16_t * gain_floor,int len)317*28e138c6SAndroid Build Coastguard Worker static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len)
318*28e138c6SAndroid Build Coastguard Worker {
319*28e138c6SAndroid Build Coastguard Worker    int i;
320*28e138c6SAndroid Build Coastguard Worker 
321*28e138c6SAndroid Build Coastguard Worker    if (noise_suppress > effective_echo_suppress)
322*28e138c6SAndroid Build Coastguard Worker    {
323*28e138c6SAndroid Build Coastguard Worker       spx_word16_t noise_gain, gain_ratio;
324*28e138c6SAndroid Build Coastguard Worker       noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1)));
325*28e138c6SAndroid Build Coastguard Worker       gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1)));
326*28e138c6SAndroid Build Coastguard Worker 
327*28e138c6SAndroid Build Coastguard Worker       /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */
328*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<len;i++)
329*28e138c6SAndroid Build Coastguard Worker          gain_floor[i] = MULT16_16_Q15(noise_gain,
330*28e138c6SAndroid Build Coastguard Worker                                        spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(PSHR32(noise[i],NOISE_SHIFT) + MULT16_32_Q15(gain_ratio,echo[i]),
331*28e138c6SAndroid Build Coastguard Worker                                              (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15)));
332*28e138c6SAndroid Build Coastguard Worker    } else {
333*28e138c6SAndroid Build Coastguard Worker       spx_word16_t echo_gain, gain_ratio;
334*28e138c6SAndroid Build Coastguard Worker       echo_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),effective_echo_suppress)),1)));
335*28e138c6SAndroid Build Coastguard Worker       gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),noise_suppress-effective_echo_suppress)),1)));
336*28e138c6SAndroid Build Coastguard Worker 
337*28e138c6SAndroid Build Coastguard Worker       /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */
338*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<len;i++)
339*28e138c6SAndroid Build Coastguard Worker          gain_floor[i] = MULT16_16_Q15(echo_gain,
340*28e138c6SAndroid Build Coastguard Worker                                        spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(MULT16_32_Q15(gain_ratio,PSHR32(noise[i],NOISE_SHIFT)) + echo[i],
341*28e138c6SAndroid Build Coastguard Worker                                              (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15)));
342*28e138c6SAndroid Build Coastguard Worker    }
343*28e138c6SAndroid Build Coastguard Worker }
344*28e138c6SAndroid Build Coastguard Worker 
345*28e138c6SAndroid Build Coastguard Worker #else
346*28e138c6SAndroid Build Coastguard Worker /* This function approximates the gain function
347*28e138c6SAndroid Build Coastguard Worker    y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
348*28e138c6SAndroid Build Coastguard Worker    which multiplied by xi/(1+xi) is the optimal gain
349*28e138c6SAndroid Build Coastguard Worker    in the loudness domain ( sqrt[amplitude] )
350*28e138c6SAndroid Build Coastguard Worker */
hypergeom_gain(spx_word32_t xx)351*28e138c6SAndroid Build Coastguard Worker static inline spx_word32_t hypergeom_gain(spx_word32_t xx)
352*28e138c6SAndroid Build Coastguard Worker {
353*28e138c6SAndroid Build Coastguard Worker    int ind;
354*28e138c6SAndroid Build Coastguard Worker    float integer, frac;
355*28e138c6SAndroid Build Coastguard Worker    float x;
356*28e138c6SAndroid Build Coastguard Worker    static const float table[21] = {
357*28e138c6SAndroid Build Coastguard Worker       0.82157f, 1.02017f, 1.20461f, 1.37534f, 1.53363f, 1.68092f, 1.81865f,
358*28e138c6SAndroid Build Coastguard Worker       1.94811f, 2.07038f, 2.18638f, 2.29688f, 2.40255f, 2.50391f, 2.60144f,
359*28e138c6SAndroid Build Coastguard Worker       2.69551f, 2.78647f, 2.87458f, 2.96015f, 3.04333f, 3.12431f, 3.20326f};
360*28e138c6SAndroid Build Coastguard Worker       x = EXPIN_SCALING_1*xx;
361*28e138c6SAndroid Build Coastguard Worker       integer = floor(2*x);
362*28e138c6SAndroid Build Coastguard Worker       ind = (int)integer;
363*28e138c6SAndroid Build Coastguard Worker       if (ind<0)
364*28e138c6SAndroid Build Coastguard Worker          return FRAC_SCALING;
365*28e138c6SAndroid Build Coastguard Worker       if (ind>19)
366*28e138c6SAndroid Build Coastguard Worker          return FRAC_SCALING*(1+.1296/x);
367*28e138c6SAndroid Build Coastguard Worker       frac = 2*x-integer;
368*28e138c6SAndroid Build Coastguard Worker       return FRAC_SCALING*((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f);
369*28e138c6SAndroid Build Coastguard Worker }
370*28e138c6SAndroid Build Coastguard Worker 
qcurve(spx_word16_t x)371*28e138c6SAndroid Build Coastguard Worker static inline spx_word16_t qcurve(spx_word16_t x)
372*28e138c6SAndroid Build Coastguard Worker {
373*28e138c6SAndroid Build Coastguard Worker    return 1.f/(1.f+.15f/(SNR_SCALING_1*x));
374*28e138c6SAndroid Build Coastguard Worker }
375*28e138c6SAndroid Build Coastguard Worker 
compute_gain_floor(int noise_suppress,int effective_echo_suppress,spx_word32_t * noise,spx_word32_t * echo,spx_word16_t * gain_floor,int len)376*28e138c6SAndroid Build Coastguard Worker static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len)
377*28e138c6SAndroid Build Coastguard Worker {
378*28e138c6SAndroid Build Coastguard Worker    int i;
379*28e138c6SAndroid Build Coastguard Worker    float echo_floor;
380*28e138c6SAndroid Build Coastguard Worker    float noise_floor;
381*28e138c6SAndroid Build Coastguard Worker 
382*28e138c6SAndroid Build Coastguard Worker    noise_floor = exp(.2302585f*noise_suppress);
383*28e138c6SAndroid Build Coastguard Worker    echo_floor = exp(.2302585f*effective_echo_suppress);
384*28e138c6SAndroid Build Coastguard Worker 
385*28e138c6SAndroid Build Coastguard Worker    /* Compute the gain floor based on different floors for the background noise and residual echo */
386*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<len;i++)
387*28e138c6SAndroid Build Coastguard Worker       gain_floor[i] = FRAC_SCALING*sqrt(noise_floor*PSHR32(noise[i],NOISE_SHIFT) + echo_floor*echo[i])/sqrt(1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]);
388*28e138c6SAndroid Build Coastguard Worker }
389*28e138c6SAndroid Build Coastguard Worker 
390*28e138c6SAndroid Build Coastguard Worker #endif
speex_preprocess_state_init(int frame_size,int sampling_rate)391*28e138c6SAndroid Build Coastguard Worker EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
392*28e138c6SAndroid Build Coastguard Worker {
393*28e138c6SAndroid Build Coastguard Worker    int i;
394*28e138c6SAndroid Build Coastguard Worker    int N, N3, N4, M;
395*28e138c6SAndroid Build Coastguard Worker 
396*28e138c6SAndroid Build Coastguard Worker    SpeexPreprocessState *st = (SpeexPreprocessState *)speex_alloc(sizeof(SpeexPreprocessState));
397*28e138c6SAndroid Build Coastguard Worker    st->frame_size = frame_size;
398*28e138c6SAndroid Build Coastguard Worker 
399*28e138c6SAndroid Build Coastguard Worker    /* Round ps_size down to the nearest power of two */
400*28e138c6SAndroid Build Coastguard Worker #if 0
401*28e138c6SAndroid Build Coastguard Worker    i=1;
402*28e138c6SAndroid Build Coastguard Worker    st->ps_size = st->frame_size;
403*28e138c6SAndroid Build Coastguard Worker    while(1)
404*28e138c6SAndroid Build Coastguard Worker    {
405*28e138c6SAndroid Build Coastguard Worker       if (st->ps_size & ~i)
406*28e138c6SAndroid Build Coastguard Worker       {
407*28e138c6SAndroid Build Coastguard Worker          st->ps_size &= ~i;
408*28e138c6SAndroid Build Coastguard Worker          i<<=1;
409*28e138c6SAndroid Build Coastguard Worker       } else {
410*28e138c6SAndroid Build Coastguard Worker          break;
411*28e138c6SAndroid Build Coastguard Worker       }
412*28e138c6SAndroid Build Coastguard Worker    }
413*28e138c6SAndroid Build Coastguard Worker 
414*28e138c6SAndroid Build Coastguard Worker 
415*28e138c6SAndroid Build Coastguard Worker    if (st->ps_size < 3*st->frame_size/4)
416*28e138c6SAndroid Build Coastguard Worker       st->ps_size = st->ps_size * 3 / 2;
417*28e138c6SAndroid Build Coastguard Worker #else
418*28e138c6SAndroid Build Coastguard Worker    st->ps_size = st->frame_size;
419*28e138c6SAndroid Build Coastguard Worker #endif
420*28e138c6SAndroid Build Coastguard Worker 
421*28e138c6SAndroid Build Coastguard Worker    N = st->ps_size;
422*28e138c6SAndroid Build Coastguard Worker    N3 = 2*N - st->frame_size;
423*28e138c6SAndroid Build Coastguard Worker    N4 = st->frame_size - N3;
424*28e138c6SAndroid Build Coastguard Worker 
425*28e138c6SAndroid Build Coastguard Worker    st->sampling_rate = sampling_rate;
426*28e138c6SAndroid Build Coastguard Worker    st->denoise_enabled = 1;
427*28e138c6SAndroid Build Coastguard Worker    st->vad_enabled = 0;
428*28e138c6SAndroid Build Coastguard Worker    st->dereverb_enabled = 0;
429*28e138c6SAndroid Build Coastguard Worker    st->reverb_decay = 0;
430*28e138c6SAndroid Build Coastguard Worker    st->reverb_level = 0;
431*28e138c6SAndroid Build Coastguard Worker    st->noise_suppress = NOISE_SUPPRESS_DEFAULT;
432*28e138c6SAndroid Build Coastguard Worker    st->echo_suppress = ECHO_SUPPRESS_DEFAULT;
433*28e138c6SAndroid Build Coastguard Worker    st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT;
434*28e138c6SAndroid Build Coastguard Worker 
435*28e138c6SAndroid Build Coastguard Worker    st->speech_prob_start = SPEECH_PROB_START_DEFAULT;
436*28e138c6SAndroid Build Coastguard Worker    st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT;
437*28e138c6SAndroid Build Coastguard Worker 
438*28e138c6SAndroid Build Coastguard Worker    st->echo_state = NULL;
439*28e138c6SAndroid Build Coastguard Worker 
440*28e138c6SAndroid Build Coastguard Worker    st->nbands = NB_BANDS;
441*28e138c6SAndroid Build Coastguard Worker    M = st->nbands;
442*28e138c6SAndroid Build Coastguard Worker    st->bank = filterbank_new(M, sampling_rate, N, 1);
443*28e138c6SAndroid Build Coastguard Worker 
444*28e138c6SAndroid Build Coastguard Worker    st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
445*28e138c6SAndroid Build Coastguard Worker    st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
446*28e138c6SAndroid Build Coastguard Worker    st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
447*28e138c6SAndroid Build Coastguard Worker 
448*28e138c6SAndroid Build Coastguard Worker    st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
449*28e138c6SAndroid Build Coastguard Worker    st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
450*28e138c6SAndroid Build Coastguard Worker    st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
451*28e138c6SAndroid Build Coastguard Worker    st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
452*28e138c6SAndroid Build Coastguard Worker    st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
453*28e138c6SAndroid Build Coastguard Worker    st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
454*28e138c6SAndroid Build Coastguard Worker    st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
455*28e138c6SAndroid Build Coastguard Worker    st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
456*28e138c6SAndroid Build Coastguard Worker    st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
457*28e138c6SAndroid Build Coastguard Worker    st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
458*28e138c6SAndroid Build Coastguard Worker    st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
459*28e138c6SAndroid Build Coastguard Worker    st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
460*28e138c6SAndroid Build Coastguard Worker 
461*28e138c6SAndroid Build Coastguard Worker    st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
462*28e138c6SAndroid Build Coastguard Worker    st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
463*28e138c6SAndroid Build Coastguard Worker    st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
464*28e138c6SAndroid Build Coastguard Worker    st->update_prob = (int*)speex_alloc(N*sizeof(int));
465*28e138c6SAndroid Build Coastguard Worker 
466*28e138c6SAndroid Build Coastguard Worker    st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
467*28e138c6SAndroid Build Coastguard Worker    st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
468*28e138c6SAndroid Build Coastguard Worker 
469*28e138c6SAndroid Build Coastguard Worker    conj_window(st->window, 2*N3);
470*28e138c6SAndroid Build Coastguard Worker    for (i=2*N3;i<2*st->ps_size;i++)
471*28e138c6SAndroid Build Coastguard Worker       st->window[i]=Q15_ONE;
472*28e138c6SAndroid Build Coastguard Worker 
473*28e138c6SAndroid Build Coastguard Worker    if (N4>0)
474*28e138c6SAndroid Build Coastguard Worker    {
475*28e138c6SAndroid Build Coastguard Worker       for (i=N3-1;i>=0;i--)
476*28e138c6SAndroid Build Coastguard Worker       {
477*28e138c6SAndroid Build Coastguard Worker          st->window[i+N3+N4]=st->window[i+N3];
478*28e138c6SAndroid Build Coastguard Worker          st->window[i+N3]=1;
479*28e138c6SAndroid Build Coastguard Worker       }
480*28e138c6SAndroid Build Coastguard Worker    }
481*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N+M;i++)
482*28e138c6SAndroid Build Coastguard Worker    {
483*28e138c6SAndroid Build Coastguard Worker       st->noise[i]=QCONST32(1.f,NOISE_SHIFT);
484*28e138c6SAndroid Build Coastguard Worker       st->reverb_estimate[i]=0;
485*28e138c6SAndroid Build Coastguard Worker       st->old_ps[i]=1;
486*28e138c6SAndroid Build Coastguard Worker       st->gain[i]=Q15_ONE;
487*28e138c6SAndroid Build Coastguard Worker       st->post[i]=SHL16(1, SNR_SHIFT);
488*28e138c6SAndroid Build Coastguard Worker       st->prior[i]=SHL16(1, SNR_SHIFT);
489*28e138c6SAndroid Build Coastguard Worker    }
490*28e138c6SAndroid Build Coastguard Worker 
491*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
492*28e138c6SAndroid Build Coastguard Worker       st->update_prob[i] = 1;
493*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
494*28e138c6SAndroid Build Coastguard Worker    {
495*28e138c6SAndroid Build Coastguard Worker       st->inbuf[i]=0;
496*28e138c6SAndroid Build Coastguard Worker       st->outbuf[i]=0;
497*28e138c6SAndroid Build Coastguard Worker    }
498*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
499*28e138c6SAndroid Build Coastguard Worker    st->agc_enabled = 0;
500*28e138c6SAndroid Build Coastguard Worker    st->agc_level = 8000;
501*28e138c6SAndroid Build Coastguard Worker    st->loudness_weight = (float*)speex_alloc(N*sizeof(float));
502*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
503*28e138c6SAndroid Build Coastguard Worker    {
504*28e138c6SAndroid Build Coastguard Worker       float ff=((float)i)*.5*sampling_rate/((float)N);
505*28e138c6SAndroid Build Coastguard Worker       /*st->loudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/
506*28e138c6SAndroid Build Coastguard Worker       st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f);
507*28e138c6SAndroid Build Coastguard Worker       if (st->loudness_weight[i]<.01f)
508*28e138c6SAndroid Build Coastguard Worker          st->loudness_weight[i]=.01f;
509*28e138c6SAndroid Build Coastguard Worker       st->loudness_weight[i] *= st->loudness_weight[i];
510*28e138c6SAndroid Build Coastguard Worker    }
511*28e138c6SAndroid Build Coastguard Worker    /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/
512*28e138c6SAndroid Build Coastguard Worker    st->loudness = 1e-15;
513*28e138c6SAndroid Build Coastguard Worker    st->agc_gain = 1;
514*28e138c6SAndroid Build Coastguard Worker    st->max_gain = 30;
515*28e138c6SAndroid Build Coastguard Worker    st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate);
516*28e138c6SAndroid Build Coastguard Worker    st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate);
517*28e138c6SAndroid Build Coastguard Worker    st->prev_loudness = 1;
518*28e138c6SAndroid Build Coastguard Worker    st->init_max = 1;
519*28e138c6SAndroid Build Coastguard Worker #endif
520*28e138c6SAndroid Build Coastguard Worker    st->was_speech = 0;
521*28e138c6SAndroid Build Coastguard Worker 
522*28e138c6SAndroid Build Coastguard Worker    st->fft_lookup = spx_fft_init(2*N);
523*28e138c6SAndroid Build Coastguard Worker 
524*28e138c6SAndroid Build Coastguard Worker    st->nb_adapt=0;
525*28e138c6SAndroid Build Coastguard Worker    st->min_count=0;
526*28e138c6SAndroid Build Coastguard Worker    return st;
527*28e138c6SAndroid Build Coastguard Worker }
528*28e138c6SAndroid Build Coastguard Worker 
speex_preprocess_state_destroy(SpeexPreprocessState * st)529*28e138c6SAndroid Build Coastguard Worker EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st)
530*28e138c6SAndroid Build Coastguard Worker {
531*28e138c6SAndroid Build Coastguard Worker    speex_free(st->frame);
532*28e138c6SAndroid Build Coastguard Worker    speex_free(st->ft);
533*28e138c6SAndroid Build Coastguard Worker    speex_free(st->ps);
534*28e138c6SAndroid Build Coastguard Worker    speex_free(st->gain2);
535*28e138c6SAndroid Build Coastguard Worker    speex_free(st->gain_floor);
536*28e138c6SAndroid Build Coastguard Worker    speex_free(st->window);
537*28e138c6SAndroid Build Coastguard Worker    speex_free(st->noise);
538*28e138c6SAndroid Build Coastguard Worker    speex_free(st->reverb_estimate);
539*28e138c6SAndroid Build Coastguard Worker    speex_free(st->old_ps);
540*28e138c6SAndroid Build Coastguard Worker    speex_free(st->gain);
541*28e138c6SAndroid Build Coastguard Worker    speex_free(st->prior);
542*28e138c6SAndroid Build Coastguard Worker    speex_free(st->post);
543*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
544*28e138c6SAndroid Build Coastguard Worker    speex_free(st->loudness_weight);
545*28e138c6SAndroid Build Coastguard Worker #endif
546*28e138c6SAndroid Build Coastguard Worker    speex_free(st->echo_noise);
547*28e138c6SAndroid Build Coastguard Worker    speex_free(st->residual_echo);
548*28e138c6SAndroid Build Coastguard Worker 
549*28e138c6SAndroid Build Coastguard Worker    speex_free(st->S);
550*28e138c6SAndroid Build Coastguard Worker    speex_free(st->Smin);
551*28e138c6SAndroid Build Coastguard Worker    speex_free(st->Stmp);
552*28e138c6SAndroid Build Coastguard Worker    speex_free(st->update_prob);
553*28e138c6SAndroid Build Coastguard Worker    speex_free(st->zeta);
554*28e138c6SAndroid Build Coastguard Worker 
555*28e138c6SAndroid Build Coastguard Worker    speex_free(st->inbuf);
556*28e138c6SAndroid Build Coastguard Worker    speex_free(st->outbuf);
557*28e138c6SAndroid Build Coastguard Worker 
558*28e138c6SAndroid Build Coastguard Worker    spx_fft_destroy(st->fft_lookup);
559*28e138c6SAndroid Build Coastguard Worker    filterbank_destroy(st->bank);
560*28e138c6SAndroid Build Coastguard Worker    speex_free(st);
561*28e138c6SAndroid Build Coastguard Worker }
562*28e138c6SAndroid Build Coastguard Worker 
563*28e138c6SAndroid Build Coastguard Worker /* FIXME: The AGC doesn't work yet with fixed-point*/
564*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
speex_compute_agc(SpeexPreprocessState * st,spx_word16_t Pframe,spx_word16_t * ft)565*28e138c6SAndroid Build Coastguard Worker static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft)
566*28e138c6SAndroid Build Coastguard Worker {
567*28e138c6SAndroid Build Coastguard Worker    int i;
568*28e138c6SAndroid Build Coastguard Worker    int N = st->ps_size;
569*28e138c6SAndroid Build Coastguard Worker    float target_gain;
570*28e138c6SAndroid Build Coastguard Worker    float loudness=1.f;
571*28e138c6SAndroid Build Coastguard Worker    float rate;
572*28e138c6SAndroid Build Coastguard Worker 
573*28e138c6SAndroid Build Coastguard Worker    for (i=2;i<N;i++)
574*28e138c6SAndroid Build Coastguard Worker    {
575*28e138c6SAndroid Build Coastguard Worker       loudness += 2.f*N*st->ps[i]* st->loudness_weight[i];
576*28e138c6SAndroid Build Coastguard Worker    }
577*28e138c6SAndroid Build Coastguard Worker    loudness=sqrt(loudness);
578*28e138c6SAndroid Build Coastguard Worker       /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) &&
579*28e138c6SAndroid Build Coastguard Worker    loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/
580*28e138c6SAndroid Build Coastguard Worker    if (Pframe>.3f)
581*28e138c6SAndroid Build Coastguard Worker    {
582*28e138c6SAndroid Build Coastguard Worker       /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/
583*28e138c6SAndroid Build Coastguard Worker       rate = .03*Pframe*Pframe;
584*28e138c6SAndroid Build Coastguard Worker       st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP);
585*28e138c6SAndroid Build Coastguard Worker       st->loudness_accum = (1-rate)*st->loudness_accum + rate;
586*28e138c6SAndroid Build Coastguard Worker       if (st->init_max < st->max_gain && st->nb_adapt > 20)
587*28e138c6SAndroid Build Coastguard Worker          st->init_max *= 1.f + .1f*Pframe*Pframe;
588*28e138c6SAndroid Build Coastguard Worker    }
589*28e138c6SAndroid Build Coastguard Worker    /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/
590*28e138c6SAndroid Build Coastguard Worker 
591*28e138c6SAndroid Build Coastguard Worker    target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP);
592*28e138c6SAndroid Build Coastguard Worker 
593*28e138c6SAndroid Build Coastguard Worker    if ((Pframe>.5  && st->nb_adapt > 20) || target_gain < st->agc_gain)
594*28e138c6SAndroid Build Coastguard Worker    {
595*28e138c6SAndroid Build Coastguard Worker       if (target_gain > st->max_increase_step*st->agc_gain)
596*28e138c6SAndroid Build Coastguard Worker          target_gain = st->max_increase_step*st->agc_gain;
597*28e138c6SAndroid Build Coastguard Worker       if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness)
598*28e138c6SAndroid Build Coastguard Worker          target_gain = st->max_decrease_step*st->agc_gain;
599*28e138c6SAndroid Build Coastguard Worker       if (target_gain > st->max_gain)
600*28e138c6SAndroid Build Coastguard Worker          target_gain = st->max_gain;
601*28e138c6SAndroid Build Coastguard Worker       if (target_gain > st->init_max)
602*28e138c6SAndroid Build Coastguard Worker          target_gain = st->init_max;
603*28e138c6SAndroid Build Coastguard Worker 
604*28e138c6SAndroid Build Coastguard Worker       st->agc_gain = target_gain;
605*28e138c6SAndroid Build Coastguard Worker    }
606*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/
607*28e138c6SAndroid Build Coastguard Worker 
608*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<2*N;i++)
609*28e138c6SAndroid Build Coastguard Worker       ft[i] *= st->agc_gain;
610*28e138c6SAndroid Build Coastguard Worker    st->prev_loudness = loudness;
611*28e138c6SAndroid Build Coastguard Worker }
612*28e138c6SAndroid Build Coastguard Worker #endif
613*28e138c6SAndroid Build Coastguard Worker 
preprocess_analysis(SpeexPreprocessState * st,spx_int16_t * x)614*28e138c6SAndroid Build Coastguard Worker static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x)
615*28e138c6SAndroid Build Coastguard Worker {
616*28e138c6SAndroid Build Coastguard Worker    int i;
617*28e138c6SAndroid Build Coastguard Worker    int N = st->ps_size;
618*28e138c6SAndroid Build Coastguard Worker    int N3 = 2*N - st->frame_size;
619*28e138c6SAndroid Build Coastguard Worker    int N4 = st->frame_size - N3;
620*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *ps=st->ps;
621*28e138c6SAndroid Build Coastguard Worker 
622*28e138c6SAndroid Build Coastguard Worker    /* 'Build' input frame */
623*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
624*28e138c6SAndroid Build Coastguard Worker       st->frame[i]=st->inbuf[i];
625*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<st->frame_size;i++)
626*28e138c6SAndroid Build Coastguard Worker       st->frame[N3+i]=x[i];
627*28e138c6SAndroid Build Coastguard Worker 
628*28e138c6SAndroid Build Coastguard Worker    /* Update inbuf */
629*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
630*28e138c6SAndroid Build Coastguard Worker       st->inbuf[i]=x[N4+i];
631*28e138c6SAndroid Build Coastguard Worker 
632*28e138c6SAndroid Build Coastguard Worker    /* Windowing */
633*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<2*N;i++)
634*28e138c6SAndroid Build Coastguard Worker       st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]);
635*28e138c6SAndroid Build Coastguard Worker 
636*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
637*28e138c6SAndroid Build Coastguard Worker    {
638*28e138c6SAndroid Build Coastguard Worker       spx_word16_t max_val=0;
639*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<2*N;i++)
640*28e138c6SAndroid Build Coastguard Worker          max_val = MAX16(max_val, ABS16(st->frame[i]));
641*28e138c6SAndroid Build Coastguard Worker       st->frame_shift = 14-spx_ilog2(EXTEND32(max_val));
642*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<2*N;i++)
643*28e138c6SAndroid Build Coastguard Worker          st->frame[i] = SHL16(st->frame[i], st->frame_shift);
644*28e138c6SAndroid Build Coastguard Worker    }
645*28e138c6SAndroid Build Coastguard Worker #endif
646*28e138c6SAndroid Build Coastguard Worker 
647*28e138c6SAndroid Build Coastguard Worker    /* Perform FFT */
648*28e138c6SAndroid Build Coastguard Worker    spx_fft(st->fft_lookup, st->frame, st->ft);
649*28e138c6SAndroid Build Coastguard Worker 
650*28e138c6SAndroid Build Coastguard Worker    /* Power spectrum */
651*28e138c6SAndroid Build Coastguard Worker    ps[0]=MULT16_16(st->ft[0],st->ft[0]);
652*28e138c6SAndroid Build Coastguard Worker    for (i=1;i<N;i++)
653*28e138c6SAndroid Build Coastguard Worker       ps[i]=MULT16_16(st->ft[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]);
654*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
655*28e138c6SAndroid Build Coastguard Worker       st->ps[i] = PSHR32(st->ps[i], 2*st->frame_shift);
656*28e138c6SAndroid Build Coastguard Worker 
657*28e138c6SAndroid Build Coastguard Worker    filterbank_compute_bank32(st->bank, ps, ps+N);
658*28e138c6SAndroid Build Coastguard Worker }
659*28e138c6SAndroid Build Coastguard Worker 
update_noise_prob(SpeexPreprocessState * st)660*28e138c6SAndroid Build Coastguard Worker static void update_noise_prob(SpeexPreprocessState *st)
661*28e138c6SAndroid Build Coastguard Worker {
662*28e138c6SAndroid Build Coastguard Worker    int i;
663*28e138c6SAndroid Build Coastguard Worker    int min_range;
664*28e138c6SAndroid Build Coastguard Worker    int N = st->ps_size;
665*28e138c6SAndroid Build Coastguard Worker 
666*28e138c6SAndroid Build Coastguard Worker    for (i=1;i<N-1;i++)
667*28e138c6SAndroid Build Coastguard Worker       st->S[i] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1])
668*28e138c6SAndroid Build Coastguard Worker                       + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]);
669*28e138c6SAndroid Build Coastguard Worker    st->S[0] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]);
670*28e138c6SAndroid Build Coastguard Worker    st->S[N-1] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]);
671*28e138c6SAndroid Build Coastguard Worker 
672*28e138c6SAndroid Build Coastguard Worker    if (st->nb_adapt==1)
673*28e138c6SAndroid Build Coastguard Worker    {
674*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N;i++)
675*28e138c6SAndroid Build Coastguard Worker          st->Smin[i] = st->Stmp[i] = 0;
676*28e138c6SAndroid Build Coastguard Worker    }
677*28e138c6SAndroid Build Coastguard Worker 
678*28e138c6SAndroid Build Coastguard Worker    if (st->nb_adapt < 100)
679*28e138c6SAndroid Build Coastguard Worker       min_range = 15;
680*28e138c6SAndroid Build Coastguard Worker    else if (st->nb_adapt < 1000)
681*28e138c6SAndroid Build Coastguard Worker       min_range = 50;
682*28e138c6SAndroid Build Coastguard Worker    else if (st->nb_adapt < 10000)
683*28e138c6SAndroid Build Coastguard Worker       min_range = 150;
684*28e138c6SAndroid Build Coastguard Worker    else
685*28e138c6SAndroid Build Coastguard Worker       min_range = 300;
686*28e138c6SAndroid Build Coastguard Worker    if (st->min_count > min_range)
687*28e138c6SAndroid Build Coastguard Worker    {
688*28e138c6SAndroid Build Coastguard Worker       st->min_count = 0;
689*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N;i++)
690*28e138c6SAndroid Build Coastguard Worker       {
691*28e138c6SAndroid Build Coastguard Worker          st->Smin[i] = MIN32(st->Stmp[i], st->S[i]);
692*28e138c6SAndroid Build Coastguard Worker          st->Stmp[i] = st->S[i];
693*28e138c6SAndroid Build Coastguard Worker       }
694*28e138c6SAndroid Build Coastguard Worker    } else {
695*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N;i++)
696*28e138c6SAndroid Build Coastguard Worker       {
697*28e138c6SAndroid Build Coastguard Worker          st->Smin[i] = MIN32(st->Smin[i], st->S[i]);
698*28e138c6SAndroid Build Coastguard Worker          st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]);
699*28e138c6SAndroid Build Coastguard Worker       }
700*28e138c6SAndroid Build Coastguard Worker    }
701*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
702*28e138c6SAndroid Build Coastguard Worker    {
703*28e138c6SAndroid Build Coastguard Worker       if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > st->Smin[i])
704*28e138c6SAndroid Build Coastguard Worker          st->update_prob[i] = 1;
705*28e138c6SAndroid Build Coastguard Worker       else
706*28e138c6SAndroid Build Coastguard Worker          st->update_prob[i] = 0;
707*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/
708*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "%f ", st->update_prob[i]);*/
709*28e138c6SAndroid Build Coastguard Worker    }
710*28e138c6SAndroid Build Coastguard Worker 
711*28e138c6SAndroid Build Coastguard Worker }
712*28e138c6SAndroid Build Coastguard Worker 
713*28e138c6SAndroid Build Coastguard Worker #define NOISE_OVERCOMPENS 1.
714*28e138c6SAndroid Build Coastguard Worker 
715*28e138c6SAndroid Build Coastguard Worker void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
716*28e138c6SAndroid Build Coastguard Worker 
speex_preprocess(SpeexPreprocessState * st,spx_int16_t * x,spx_int32_t * echo)717*28e138c6SAndroid Build Coastguard Worker EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo)
718*28e138c6SAndroid Build Coastguard Worker {
719*28e138c6SAndroid Build Coastguard Worker    return speex_preprocess_run(st, x);
720*28e138c6SAndroid Build Coastguard Worker }
721*28e138c6SAndroid Build Coastguard Worker 
speex_preprocess_run(SpeexPreprocessState * st,spx_int16_t * x)722*28e138c6SAndroid Build Coastguard Worker EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
723*28e138c6SAndroid Build Coastguard Worker {
724*28e138c6SAndroid Build Coastguard Worker    int i;
725*28e138c6SAndroid Build Coastguard Worker    int M;
726*28e138c6SAndroid Build Coastguard Worker    int N = st->ps_size;
727*28e138c6SAndroid Build Coastguard Worker    int N3 = 2*N - st->frame_size;
728*28e138c6SAndroid Build Coastguard Worker    int N4 = st->frame_size - N3;
729*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *ps=st->ps;
730*28e138c6SAndroid Build Coastguard Worker    spx_word32_t Zframe;
731*28e138c6SAndroid Build Coastguard Worker    spx_word16_t Pframe;
732*28e138c6SAndroid Build Coastguard Worker    spx_word16_t beta, beta_1;
733*28e138c6SAndroid Build Coastguard Worker    spx_word16_t effective_echo_suppress;
734*28e138c6SAndroid Build Coastguard Worker 
735*28e138c6SAndroid Build Coastguard Worker    st->nb_adapt++;
736*28e138c6SAndroid Build Coastguard Worker    if (st->nb_adapt>20000)
737*28e138c6SAndroid Build Coastguard Worker       st->nb_adapt = 20000;
738*28e138c6SAndroid Build Coastguard Worker    st->min_count++;
739*28e138c6SAndroid Build Coastguard Worker 
740*28e138c6SAndroid Build Coastguard Worker    beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt));
741*28e138c6SAndroid Build Coastguard Worker    beta_1 = Q15_ONE-beta;
742*28e138c6SAndroid Build Coastguard Worker    M = st->nbands;
743*28e138c6SAndroid Build Coastguard Worker    /* Deal with residual echo if provided */
744*28e138c6SAndroid Build Coastguard Worker    if (st->echo_state)
745*28e138c6SAndroid Build Coastguard Worker    {
746*28e138c6SAndroid Build Coastguard Worker       speex_echo_get_residual(st->echo_state, st->residual_echo, N);
747*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
748*28e138c6SAndroid Build Coastguard Worker       /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */
749*28e138c6SAndroid Build Coastguard Worker       if (!(st->residual_echo[0] >=0 && st->residual_echo[0]<N*1e9f))
750*28e138c6SAndroid Build Coastguard Worker       {
751*28e138c6SAndroid Build Coastguard Worker          for (i=0;i<N;i++)
752*28e138c6SAndroid Build Coastguard Worker             st->residual_echo[i] = 0;
753*28e138c6SAndroid Build Coastguard Worker       }
754*28e138c6SAndroid Build Coastguard Worker #endif
755*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N;i++)
756*28e138c6SAndroid Build Coastguard Worker          st->echo_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]);
757*28e138c6SAndroid Build Coastguard Worker       filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N);
758*28e138c6SAndroid Build Coastguard Worker    } else {
759*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N+M;i++)
760*28e138c6SAndroid Build Coastguard Worker          st->echo_noise[i] = 0;
761*28e138c6SAndroid Build Coastguard Worker    }
762*28e138c6SAndroid Build Coastguard Worker    preprocess_analysis(st, x);
763*28e138c6SAndroid Build Coastguard Worker 
764*28e138c6SAndroid Build Coastguard Worker    update_noise_prob(st);
765*28e138c6SAndroid Build Coastguard Worker 
766*28e138c6SAndroid Build Coastguard Worker    /* Noise estimation always updated for the 10 first frames */
767*28e138c6SAndroid Build Coastguard Worker    /*if (st->nb_adapt<10)
768*28e138c6SAndroid Build Coastguard Worker    {
769*28e138c6SAndroid Build Coastguard Worker       for (i=1;i<N-1;i++)
770*28e138c6SAndroid Build Coastguard Worker          st->update_prob[i] = 0;
771*28e138c6SAndroid Build Coastguard Worker    }
772*28e138c6SAndroid Build Coastguard Worker    */
773*28e138c6SAndroid Build Coastguard Worker 
774*28e138c6SAndroid Build Coastguard Worker    /* Update the noise estimate for the frequencies where it can be */
775*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
776*28e138c6SAndroid Build Coastguard Worker    {
777*28e138c6SAndroid Build Coastguard Worker       if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT))
778*28e138c6SAndroid Build Coastguard Worker          st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT)));
779*28e138c6SAndroid Build Coastguard Worker    }
780*28e138c6SAndroid Build Coastguard Worker    filterbank_compute_bank32(st->bank, st->noise, st->noise+N);
781*28e138c6SAndroid Build Coastguard Worker 
782*28e138c6SAndroid Build Coastguard Worker    /* Special case for first frame */
783*28e138c6SAndroid Build Coastguard Worker    if (st->nb_adapt==1)
784*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N+M;i++)
785*28e138c6SAndroid Build Coastguard Worker          st->old_ps[i] = ps[i];
786*28e138c6SAndroid Build Coastguard Worker 
787*28e138c6SAndroid Build Coastguard Worker    /* Compute a posteriori SNR */
788*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N+M;i++)
789*28e138c6SAndroid Build Coastguard Worker    {
790*28e138c6SAndroid Build Coastguard Worker       spx_word16_t gamma;
791*28e138c6SAndroid Build Coastguard Worker 
792*28e138c6SAndroid Build Coastguard Worker       /* Total noise estimate including residual echo and reverberation */
793*28e138c6SAndroid Build Coastguard Worker       spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]);
794*28e138c6SAndroid Build Coastguard Worker 
795*28e138c6SAndroid Build Coastguard Worker       /* A posteriori SNR = ps/noise - 1*/
796*28e138c6SAndroid Build Coastguard Worker       st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT));
797*28e138c6SAndroid Build Coastguard Worker       st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT));
798*28e138c6SAndroid Build Coastguard Worker 
799*28e138c6SAndroid Build Coastguard Worker       /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */
800*28e138c6SAndroid Build Coastguard Worker       gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise))));
801*28e138c6SAndroid Build Coastguard Worker 
802*28e138c6SAndroid Build Coastguard Worker       /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */
803*28e138c6SAndroid Build Coastguard Worker       st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15));
804*28e138c6SAndroid Build Coastguard Worker       st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT));
805*28e138c6SAndroid Build Coastguard Worker    }
806*28e138c6SAndroid Build Coastguard Worker 
807*28e138c6SAndroid Build Coastguard Worker    /*print_vec(st->post, N+M, "");*/
808*28e138c6SAndroid Build Coastguard Worker 
809*28e138c6SAndroid Build Coastguard Worker    /* Recursive average of the a priori SNR. A bit smoothed for the psd components */
810*28e138c6SAndroid Build Coastguard Worker    st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15);
811*28e138c6SAndroid Build Coastguard Worker    for (i=1;i<N-1;i++)
812*28e138c6SAndroid Build Coastguard Worker       st->zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])),
813*28e138c6SAndroid Build Coastguard Worker                            MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15);
814*28e138c6SAndroid Build Coastguard Worker    for (i=N-1;i<N+M;i++)
815*28e138c6SAndroid Build Coastguard Worker       st->zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15);
816*28e138c6SAndroid Build Coastguard Worker 
817*28e138c6SAndroid Build Coastguard Worker    /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */
818*28e138c6SAndroid Build Coastguard Worker    Zframe = 0;
819*28e138c6SAndroid Build Coastguard Worker    for (i=N;i<N+M;i++)
820*28e138c6SAndroid Build Coastguard Worker       Zframe = ADD32(Zframe, EXTEND32(st->zeta[i]));
821*28e138c6SAndroid Build Coastguard Worker    Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands)));
822*28e138c6SAndroid Build Coastguard Worker 
823*28e138c6SAndroid Build Coastguard Worker    effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15));
824*28e138c6SAndroid Build Coastguard Worker 
825*28e138c6SAndroid Build Coastguard Worker    compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M);
826*28e138c6SAndroid Build Coastguard Worker 
827*28e138c6SAndroid Build Coastguard Worker    /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale)
828*28e138c6SAndroid Build Coastguard Worker       Technically this is actually wrong because the EM gaim assumes a slightly different probability
829*28e138c6SAndroid Build Coastguard Worker       distribution */
830*28e138c6SAndroid Build Coastguard Worker    for (i=N;i<N+M;i++)
831*28e138c6SAndroid Build Coastguard Worker    {
832*28e138c6SAndroid Build Coastguard Worker       /* See EM and Cohen papers*/
833*28e138c6SAndroid Build Coastguard Worker       spx_word32_t theta;
834*28e138c6SAndroid Build Coastguard Worker       /* Gain from hypergeometric function */
835*28e138c6SAndroid Build Coastguard Worker       spx_word32_t MM;
836*28e138c6SAndroid Build Coastguard Worker       /* Weiner filter gain */
837*28e138c6SAndroid Build Coastguard Worker       spx_word16_t prior_ratio;
838*28e138c6SAndroid Build Coastguard Worker       /* a priority probability of speech presence based on Bark sub-band alone */
839*28e138c6SAndroid Build Coastguard Worker       spx_word16_t P1;
840*28e138c6SAndroid Build Coastguard Worker       /* Speech absence a priori probability (considering sub-band and frame) */
841*28e138c6SAndroid Build Coastguard Worker       spx_word16_t q;
842*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
843*28e138c6SAndroid Build Coastguard Worker       spx_word16_t tmp;
844*28e138c6SAndroid Build Coastguard Worker #endif
845*28e138c6SAndroid Build Coastguard Worker 
846*28e138c6SAndroid Build Coastguard Worker       prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
847*28e138c6SAndroid Build Coastguard Worker       theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
848*28e138c6SAndroid Build Coastguard Worker 
849*28e138c6SAndroid Build Coastguard Worker       MM = hypergeom_gain(theta);
850*28e138c6SAndroid Build Coastguard Worker       /* Gain with bound */
851*28e138c6SAndroid Build Coastguard Worker       st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
852*28e138c6SAndroid Build Coastguard Worker       /* Save old Bark power spectrum */
853*28e138c6SAndroid Build Coastguard Worker       st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]);
854*28e138c6SAndroid Build Coastguard Worker 
855*28e138c6SAndroid Build Coastguard Worker       P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i]));
856*28e138c6SAndroid Build Coastguard Worker       q = Q15_ONE-MULT16_16_Q15(Pframe,P1);
857*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
858*28e138c6SAndroid Build Coastguard Worker       theta = MIN32(theta, EXTEND32(32767));
859*28e138c6SAndroid Build Coastguard Worker /*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1))));
860*28e138c6SAndroid Build Coastguard Worker       tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/
861*28e138c6SAndroid Build Coastguard Worker /*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8));
862*28e138c6SAndroid Build Coastguard Worker       st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp));
863*28e138c6SAndroid Build Coastguard Worker #else
864*28e138c6SAndroid Build Coastguard Worker       st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta));
865*28e138c6SAndroid Build Coastguard Worker #endif
866*28e138c6SAndroid Build Coastguard Worker    }
867*28e138c6SAndroid Build Coastguard Worker    /* Convert the EM gains and speech prob to linear frequency */
868*28e138c6SAndroid Build Coastguard Worker    filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
869*28e138c6SAndroid Build Coastguard Worker    filterbank_compute_psd16(st->bank,st->gain+N, st->gain);
870*28e138c6SAndroid Build Coastguard Worker 
871*28e138c6SAndroid Build Coastguard Worker    /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */
872*28e138c6SAndroid Build Coastguard Worker    if (1)
873*28e138c6SAndroid Build Coastguard Worker    {
874*28e138c6SAndroid Build Coastguard Worker       filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor);
875*28e138c6SAndroid Build Coastguard Worker 
876*28e138c6SAndroid Build Coastguard Worker       /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */
877*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N;i++)
878*28e138c6SAndroid Build Coastguard Worker       {
879*28e138c6SAndroid Build Coastguard Worker          spx_word32_t MM;
880*28e138c6SAndroid Build Coastguard Worker          spx_word32_t theta;
881*28e138c6SAndroid Build Coastguard Worker          spx_word16_t prior_ratio;
882*28e138c6SAndroid Build Coastguard Worker          spx_word16_t tmp;
883*28e138c6SAndroid Build Coastguard Worker          spx_word16_t p;
884*28e138c6SAndroid Build Coastguard Worker          spx_word16_t g;
885*28e138c6SAndroid Build Coastguard Worker 
886*28e138c6SAndroid Build Coastguard Worker          /* Wiener filter gain */
887*28e138c6SAndroid Build Coastguard Worker          prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
888*28e138c6SAndroid Build Coastguard Worker          theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
889*28e138c6SAndroid Build Coastguard Worker 
890*28e138c6SAndroid Build Coastguard Worker          /* Optimal estimator for loudness domain */
891*28e138c6SAndroid Build Coastguard Worker          MM = hypergeom_gain(theta);
892*28e138c6SAndroid Build Coastguard Worker          /* EM gain with bound */
893*28e138c6SAndroid Build Coastguard Worker          g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
894*28e138c6SAndroid Build Coastguard Worker          /* Interpolated speech probability of presence */
895*28e138c6SAndroid Build Coastguard Worker          p = st->gain2[i];
896*28e138c6SAndroid Build Coastguard Worker 
897*28e138c6SAndroid Build Coastguard Worker          /* Constrain the gain to be close to the Bark scale gain */
898*28e138c6SAndroid Build Coastguard Worker          if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i])
899*28e138c6SAndroid Build Coastguard Worker             g = MULT16_16(3,st->gain[i]);
900*28e138c6SAndroid Build Coastguard Worker          st->gain[i] = g;
901*28e138c6SAndroid Build Coastguard Worker 
902*28e138c6SAndroid Build Coastguard Worker          /* Save old power spectrum */
903*28e138c6SAndroid Build Coastguard Worker          st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]);
904*28e138c6SAndroid Build Coastguard Worker 
905*28e138c6SAndroid Build Coastguard Worker          /* Apply gain floor */
906*28e138c6SAndroid Build Coastguard Worker          if (st->gain[i] < st->gain_floor[i])
907*28e138c6SAndroid Build Coastguard Worker             st->gain[i] = st->gain_floor[i];
908*28e138c6SAndroid Build Coastguard Worker 
909*28e138c6SAndroid Build Coastguard Worker          /* Exponential decay model for reverberation (unused) */
910*28e138c6SAndroid Build Coastguard Worker          /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/
911*28e138c6SAndroid Build Coastguard Worker 
912*28e138c6SAndroid Build Coastguard Worker          /* Take into account speech probability of presence (loudness domain MMSE estimator) */
913*28e138c6SAndroid Build Coastguard Worker          /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */
914*28e138c6SAndroid Build Coastguard Worker          tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
915*28e138c6SAndroid Build Coastguard Worker          st->gain2[i]=SQR16_Q15(tmp);
916*28e138c6SAndroid Build Coastguard Worker 
917*28e138c6SAndroid Build Coastguard Worker          /* Use this if you want a log-domain MMSE estimator instead */
918*28e138c6SAndroid Build Coastguard Worker          /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/
919*28e138c6SAndroid Build Coastguard Worker       }
920*28e138c6SAndroid Build Coastguard Worker    } else {
921*28e138c6SAndroid Build Coastguard Worker       for (i=N;i<N+M;i++)
922*28e138c6SAndroid Build Coastguard Worker       {
923*28e138c6SAndroid Build Coastguard Worker          spx_word16_t tmp;
924*28e138c6SAndroid Build Coastguard Worker          spx_word16_t p = st->gain2[i];
925*28e138c6SAndroid Build Coastguard Worker          st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]);
926*28e138c6SAndroid Build Coastguard Worker          tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
927*28e138c6SAndroid Build Coastguard Worker          st->gain2[i]=SQR16_Q15(tmp);
928*28e138c6SAndroid Build Coastguard Worker       }
929*28e138c6SAndroid Build Coastguard Worker       filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
930*28e138c6SAndroid Build Coastguard Worker    }
931*28e138c6SAndroid Build Coastguard Worker 
932*28e138c6SAndroid Build Coastguard Worker    /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */
933*28e138c6SAndroid Build Coastguard Worker    if (!st->denoise_enabled)
934*28e138c6SAndroid Build Coastguard Worker    {
935*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<N+M;i++)
936*28e138c6SAndroid Build Coastguard Worker          st->gain2[i]=Q15_ONE;
937*28e138c6SAndroid Build Coastguard Worker    }
938*28e138c6SAndroid Build Coastguard Worker 
939*28e138c6SAndroid Build Coastguard Worker    /* Apply computed gain */
940*28e138c6SAndroid Build Coastguard Worker    for (i=1;i<N;i++)
941*28e138c6SAndroid Build Coastguard Worker    {
942*28e138c6SAndroid Build Coastguard Worker       st->ft[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]);
943*28e138c6SAndroid Build Coastguard Worker       st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]);
944*28e138c6SAndroid Build Coastguard Worker    }
945*28e138c6SAndroid Build Coastguard Worker    st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]);
946*28e138c6SAndroid Build Coastguard Worker    st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]);
947*28e138c6SAndroid Build Coastguard Worker 
948*28e138c6SAndroid Build Coastguard Worker    /*FIXME: This *will* not work for fixed-point */
949*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
950*28e138c6SAndroid Build Coastguard Worker    if (st->agc_enabled)
951*28e138c6SAndroid Build Coastguard Worker       speex_compute_agc(st, Pframe, st->ft);
952*28e138c6SAndroid Build Coastguard Worker #endif
953*28e138c6SAndroid Build Coastguard Worker 
954*28e138c6SAndroid Build Coastguard Worker    /* Inverse FFT with 1/N scaling */
955*28e138c6SAndroid Build Coastguard Worker    spx_ifft(st->fft_lookup, st->ft, st->frame);
956*28e138c6SAndroid Build Coastguard Worker    /* Scale back to original (lower) amplitude */
957*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<2*N;i++)
958*28e138c6SAndroid Build Coastguard Worker       st->frame[i] = PSHR16(st->frame[i], st->frame_shift);
959*28e138c6SAndroid Build Coastguard Worker 
960*28e138c6SAndroid Build Coastguard Worker    /*FIXME: This *will* not work for fixed-point */
961*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
962*28e138c6SAndroid Build Coastguard Worker    if (st->agc_enabled)
963*28e138c6SAndroid Build Coastguard Worker    {
964*28e138c6SAndroid Build Coastguard Worker       float max_sample=0;
965*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<2*N;i++)
966*28e138c6SAndroid Build Coastguard Worker          if (fabs(st->frame[i])>max_sample)
967*28e138c6SAndroid Build Coastguard Worker             max_sample = fabs(st->frame[i]);
968*28e138c6SAndroid Build Coastguard Worker       if (max_sample>28000.f)
969*28e138c6SAndroid Build Coastguard Worker       {
970*28e138c6SAndroid Build Coastguard Worker          float damp = 28000.f/max_sample;
971*28e138c6SAndroid Build Coastguard Worker          for (i=0;i<2*N;i++)
972*28e138c6SAndroid Build Coastguard Worker             st->frame[i] *= damp;
973*28e138c6SAndroid Build Coastguard Worker       }
974*28e138c6SAndroid Build Coastguard Worker    }
975*28e138c6SAndroid Build Coastguard Worker #endif
976*28e138c6SAndroid Build Coastguard Worker 
977*28e138c6SAndroid Build Coastguard Worker    /* Synthesis window (for WOLA) */
978*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<2*N;i++)
979*28e138c6SAndroid Build Coastguard Worker       st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]);
980*28e138c6SAndroid Build Coastguard Worker 
981*28e138c6SAndroid Build Coastguard Worker    /* Perform overlap and add */
982*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
983*28e138c6SAndroid Build Coastguard Worker       x[i] = WORD2INT(ADD32(EXTEND32(st->outbuf[i]), EXTEND32(st->frame[i])));
984*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N4;i++)
985*28e138c6SAndroid Build Coastguard Worker       x[N3+i] = st->frame[N3+i];
986*28e138c6SAndroid Build Coastguard Worker 
987*28e138c6SAndroid Build Coastguard Worker    /* Update outbuf */
988*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
989*28e138c6SAndroid Build Coastguard Worker       st->outbuf[i] = st->frame[st->frame_size+i];
990*28e138c6SAndroid Build Coastguard Worker 
991*28e138c6SAndroid Build Coastguard Worker    /* FIXME: This VAD is a kludge */
992*28e138c6SAndroid Build Coastguard Worker    st->speech_prob = Pframe;
993*28e138c6SAndroid Build Coastguard Worker    if (st->vad_enabled)
994*28e138c6SAndroid Build Coastguard Worker    {
995*28e138c6SAndroid Build Coastguard Worker       if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue))
996*28e138c6SAndroid Build Coastguard Worker       {
997*28e138c6SAndroid Build Coastguard Worker          st->was_speech=1;
998*28e138c6SAndroid Build Coastguard Worker          return 1;
999*28e138c6SAndroid Build Coastguard Worker       } else
1000*28e138c6SAndroid Build Coastguard Worker       {
1001*28e138c6SAndroid Build Coastguard Worker          st->was_speech=0;
1002*28e138c6SAndroid Build Coastguard Worker          return 0;
1003*28e138c6SAndroid Build Coastguard Worker       }
1004*28e138c6SAndroid Build Coastguard Worker    } else {
1005*28e138c6SAndroid Build Coastguard Worker       return 1;
1006*28e138c6SAndroid Build Coastguard Worker    }
1007*28e138c6SAndroid Build Coastguard Worker }
1008*28e138c6SAndroid Build Coastguard Worker 
speex_preprocess_estimate_update(SpeexPreprocessState * st,spx_int16_t * x)1009*28e138c6SAndroid Build Coastguard Worker EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
1010*28e138c6SAndroid Build Coastguard Worker {
1011*28e138c6SAndroid Build Coastguard Worker    int i;
1012*28e138c6SAndroid Build Coastguard Worker    int N = st->ps_size;
1013*28e138c6SAndroid Build Coastguard Worker    int N3 = 2*N - st->frame_size;
1014*28e138c6SAndroid Build Coastguard Worker    int M;
1015*28e138c6SAndroid Build Coastguard Worker    spx_word32_t *ps=st->ps;
1016*28e138c6SAndroid Build Coastguard Worker 
1017*28e138c6SAndroid Build Coastguard Worker    M = st->nbands;
1018*28e138c6SAndroid Build Coastguard Worker    st->min_count++;
1019*28e138c6SAndroid Build Coastguard Worker 
1020*28e138c6SAndroid Build Coastguard Worker    preprocess_analysis(st, x);
1021*28e138c6SAndroid Build Coastguard Worker 
1022*28e138c6SAndroid Build Coastguard Worker    update_noise_prob(st);
1023*28e138c6SAndroid Build Coastguard Worker 
1024*28e138c6SAndroid Build Coastguard Worker    for (i=1;i<N-1;i++)
1025*28e138c6SAndroid Build Coastguard Worker    {
1026*28e138c6SAndroid Build Coastguard Worker       if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT))
1027*28e138c6SAndroid Build Coastguard Worker       {
1028*28e138c6SAndroid Build Coastguard Worker          st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT));
1029*28e138c6SAndroid Build Coastguard Worker       }
1030*28e138c6SAndroid Build Coastguard Worker    }
1031*28e138c6SAndroid Build Coastguard Worker 
1032*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N3;i++)
1033*28e138c6SAndroid Build Coastguard Worker       st->outbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]);
1034*28e138c6SAndroid Build Coastguard Worker 
1035*28e138c6SAndroid Build Coastguard Worker    /* Save old power spectrum */
1036*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N+M;i++)
1037*28e138c6SAndroid Build Coastguard Worker       st->old_ps[i] = ps[i];
1038*28e138c6SAndroid Build Coastguard Worker 
1039*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<N;i++)
1040*28e138c6SAndroid Build Coastguard Worker       st->reverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]);
1041*28e138c6SAndroid Build Coastguard Worker }
1042*28e138c6SAndroid Build Coastguard Worker 
1043*28e138c6SAndroid Build Coastguard Worker 
speex_preprocess_ctl(SpeexPreprocessState * state,int request,void * ptr)1044*28e138c6SAndroid Build Coastguard Worker EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
1045*28e138c6SAndroid Build Coastguard Worker {
1046*28e138c6SAndroid Build Coastguard Worker    int i;
1047*28e138c6SAndroid Build Coastguard Worker    SpeexPreprocessState *st;
1048*28e138c6SAndroid Build Coastguard Worker    st=(SpeexPreprocessState*)state;
1049*28e138c6SAndroid Build Coastguard Worker    switch(request)
1050*28e138c6SAndroid Build Coastguard Worker    {
1051*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_DENOISE:
1052*28e138c6SAndroid Build Coastguard Worker       st->denoise_enabled = (*(spx_int32_t*)ptr);
1053*28e138c6SAndroid Build Coastguard Worker       break;
1054*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_DENOISE:
1055*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->denoise_enabled;
1056*28e138c6SAndroid Build Coastguard Worker       break;
1057*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
1058*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC:
1059*28e138c6SAndroid Build Coastguard Worker       st->agc_enabled = (*(spx_int32_t*)ptr);
1060*28e138c6SAndroid Build Coastguard Worker       break;
1061*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC:
1062*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->agc_enabled;
1063*28e138c6SAndroid Build Coastguard Worker       break;
1064*28e138c6SAndroid Build Coastguard Worker #ifndef DISABLE_FLOAT_API
1065*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC_LEVEL:
1066*28e138c6SAndroid Build Coastguard Worker       st->agc_level = (*(float*)ptr);
1067*28e138c6SAndroid Build Coastguard Worker       if (st->agc_level<1)
1068*28e138c6SAndroid Build Coastguard Worker          st->agc_level=1;
1069*28e138c6SAndroid Build Coastguard Worker       if (st->agc_level>32768)
1070*28e138c6SAndroid Build Coastguard Worker          st->agc_level=32768;
1071*28e138c6SAndroid Build Coastguard Worker       break;
1072*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_LEVEL:
1073*28e138c6SAndroid Build Coastguard Worker       (*(float*)ptr) = st->agc_level;
1074*28e138c6SAndroid Build Coastguard Worker       break;
1075*28e138c6SAndroid Build Coastguard Worker #endif /* #ifndef DISABLE_FLOAT_API */
1076*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC_INCREMENT:
1077*28e138c6SAndroid Build Coastguard Worker       st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate);
1078*28e138c6SAndroid Build Coastguard Worker       break;
1079*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_INCREMENT:
1080*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size);
1081*28e138c6SAndroid Build Coastguard Worker       break;
1082*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC_DECREMENT:
1083*28e138c6SAndroid Build Coastguard Worker       st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate);
1084*28e138c6SAndroid Build Coastguard Worker       break;
1085*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_DECREMENT:
1086*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size);
1087*28e138c6SAndroid Build Coastguard Worker       break;
1088*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN:
1089*28e138c6SAndroid Build Coastguard Worker       st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr));
1090*28e138c6SAndroid Build Coastguard Worker       break;
1091*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN:
1092*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain));
1093*28e138c6SAndroid Build Coastguard Worker       break;
1094*28e138c6SAndroid Build Coastguard Worker #endif
1095*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_VAD:
1096*28e138c6SAndroid Build Coastguard Worker       speex_warning("The VAD has been replaced by a hack pending a complete rewrite");
1097*28e138c6SAndroid Build Coastguard Worker       st->vad_enabled = (*(spx_int32_t*)ptr);
1098*28e138c6SAndroid Build Coastguard Worker       break;
1099*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_VAD:
1100*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->vad_enabled;
1101*28e138c6SAndroid Build Coastguard Worker       break;
1102*28e138c6SAndroid Build Coastguard Worker 
1103*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_DEREVERB:
1104*28e138c6SAndroid Build Coastguard Worker       st->dereverb_enabled = (*(spx_int32_t*)ptr);
1105*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<st->ps_size;i++)
1106*28e138c6SAndroid Build Coastguard Worker          st->reverb_estimate[i]=0;
1107*28e138c6SAndroid Build Coastguard Worker       break;
1108*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_DEREVERB:
1109*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->dereverb_enabled;
1110*28e138c6SAndroid Build Coastguard Worker       break;
1111*28e138c6SAndroid Build Coastguard Worker 
1112*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL:
1113*28e138c6SAndroid Build Coastguard Worker       /* FIXME: Re-enable when de-reverberation is actually enabled again */
1114*28e138c6SAndroid Build Coastguard Worker       /*st->reverb_level = (*(float*)ptr);*/
1115*28e138c6SAndroid Build Coastguard Worker       break;
1116*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_DEREVERB_LEVEL:
1117*28e138c6SAndroid Build Coastguard Worker       /* FIXME: Re-enable when de-reverberation is actually enabled again */
1118*28e138c6SAndroid Build Coastguard Worker       /*(*(float*)ptr) = st->reverb_level;*/
1119*28e138c6SAndroid Build Coastguard Worker       break;
1120*28e138c6SAndroid Build Coastguard Worker 
1121*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_DEREVERB_DECAY:
1122*28e138c6SAndroid Build Coastguard Worker       /* FIXME: Re-enable when de-reverberation is actually enabled again */
1123*28e138c6SAndroid Build Coastguard Worker       /*st->reverb_decay = (*(float*)ptr);*/
1124*28e138c6SAndroid Build Coastguard Worker       break;
1125*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_DEREVERB_DECAY:
1126*28e138c6SAndroid Build Coastguard Worker       /* FIXME: Re-enable when de-reverberation is actually enabled again */
1127*28e138c6SAndroid Build Coastguard Worker       /*(*(float*)ptr) = st->reverb_decay;*/
1128*28e138c6SAndroid Build Coastguard Worker       break;
1129*28e138c6SAndroid Build Coastguard Worker 
1130*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_PROB_START:
1131*28e138c6SAndroid Build Coastguard Worker       *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr));
1132*28e138c6SAndroid Build Coastguard Worker       st->speech_prob_start = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100);
1133*28e138c6SAndroid Build Coastguard Worker       break;
1134*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_PROB_START:
1135*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100);
1136*28e138c6SAndroid Build Coastguard Worker       break;
1137*28e138c6SAndroid Build Coastguard Worker 
1138*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_PROB_CONTINUE:
1139*28e138c6SAndroid Build Coastguard Worker       *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr));
1140*28e138c6SAndroid Build Coastguard Worker       st->speech_prob_continue = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100);
1141*28e138c6SAndroid Build Coastguard Worker       break;
1142*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_PROB_CONTINUE:
1143*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100);
1144*28e138c6SAndroid Build Coastguard Worker       break;
1145*28e138c6SAndroid Build Coastguard Worker 
1146*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS:
1147*28e138c6SAndroid Build Coastguard Worker       st->noise_suppress = -ABS(*(spx_int32_t*)ptr);
1148*28e138c6SAndroid Build Coastguard Worker       break;
1149*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS:
1150*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->noise_suppress;
1151*28e138c6SAndroid Build Coastguard Worker       break;
1152*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS:
1153*28e138c6SAndroid Build Coastguard Worker       st->echo_suppress = -ABS(*(spx_int32_t*)ptr);
1154*28e138c6SAndroid Build Coastguard Worker       break;
1155*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS:
1156*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->echo_suppress;
1157*28e138c6SAndroid Build Coastguard Worker       break;
1158*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE:
1159*28e138c6SAndroid Build Coastguard Worker       st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr);
1160*28e138c6SAndroid Build Coastguard Worker       break;
1161*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE:
1162*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->echo_suppress_active;
1163*28e138c6SAndroid Build Coastguard Worker       break;
1164*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_ECHO_STATE:
1165*28e138c6SAndroid Build Coastguard Worker       st->echo_state = (SpeexEchoState*)ptr;
1166*28e138c6SAndroid Build Coastguard Worker       break;
1167*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_ECHO_STATE:
1168*28e138c6SAndroid Build Coastguard Worker       (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state;
1169*28e138c6SAndroid Build Coastguard Worker       break;
1170*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
1171*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_LOUDNESS:
1172*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP);
1173*28e138c6SAndroid Build Coastguard Worker       break;
1174*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_GAIN:
1175*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain));
1176*28e138c6SAndroid Build Coastguard Worker       break;
1177*28e138c6SAndroid Build Coastguard Worker #endif
1178*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_PSD_SIZE:
1179*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE:
1180*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->ps_size;
1181*28e138c6SAndroid Build Coastguard Worker       break;
1182*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_PSD:
1183*28e138c6SAndroid Build Coastguard Worker       for(i=0;i<st->ps_size;i++)
1184*28e138c6SAndroid Build Coastguard Worker       	((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i];
1185*28e138c6SAndroid Build Coastguard Worker       break;
1186*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_NOISE_PSD:
1187*28e138c6SAndroid Build Coastguard Worker       for(i=0;i<st->ps_size;i++)
1188*28e138c6SAndroid Build Coastguard Worker       	((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT);
1189*28e138c6SAndroid Build Coastguard Worker       break;
1190*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_PROB:
1191*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100);
1192*28e138c6SAndroid Build Coastguard Worker       break;
1193*28e138c6SAndroid Build Coastguard Worker #ifndef FIXED_POINT
1194*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_SET_AGC_TARGET:
1195*28e138c6SAndroid Build Coastguard Worker       st->agc_level = (*(spx_int32_t*)ptr);
1196*28e138c6SAndroid Build Coastguard Worker       if (st->agc_level<1)
1197*28e138c6SAndroid Build Coastguard Worker          st->agc_level=1;
1198*28e138c6SAndroid Build Coastguard Worker       if (st->agc_level>32768)
1199*28e138c6SAndroid Build Coastguard Worker          st->agc_level=32768;
1200*28e138c6SAndroid Build Coastguard Worker       break;
1201*28e138c6SAndroid Build Coastguard Worker    case SPEEX_PREPROCESS_GET_AGC_TARGET:
1202*28e138c6SAndroid Build Coastguard Worker       (*(spx_int32_t*)ptr) = st->agc_level;
1203*28e138c6SAndroid Build Coastguard Worker       break;
1204*28e138c6SAndroid Build Coastguard Worker #endif
1205*28e138c6SAndroid Build Coastguard Worker    default:
1206*28e138c6SAndroid Build Coastguard Worker       speex_warning_int("Unknown speex_preprocess_ctl request: ", request);
1207*28e138c6SAndroid Build Coastguard Worker       return -1;
1208*28e138c6SAndroid Build Coastguard Worker    }
1209*28e138c6SAndroid Build Coastguard Worker    return 0;
1210*28e138c6SAndroid Build Coastguard Worker }
1211*28e138c6SAndroid Build Coastguard Worker 
1212*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_DEBUG
1213*28e138c6SAndroid Build Coastguard Worker long long spx_mips=0;
1214*28e138c6SAndroid Build Coastguard Worker #endif
1215*28e138c6SAndroid Build Coastguard Worker 
1216