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