153a5a1b3Sopenharmony_ci/* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) 253a5a1b3Sopenharmony_ci Copyright (C) 2004-2006 Epic Games 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci File: preprocess.c 553a5a1b3Sopenharmony_ci Preprocessor with denoising based on the algorithm by Ephraim and Malah 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci Redistribution and use in source and binary forms, with or without 853a5a1b3Sopenharmony_ci modification, are permitted provided that the following conditions are 953a5a1b3Sopenharmony_ci met: 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci 1. Redistributions of source code must retain the above copyright notice, 1253a5a1b3Sopenharmony_ci this list of conditions and the following disclaimer. 1353a5a1b3Sopenharmony_ci 1453a5a1b3Sopenharmony_ci 2. Redistributions in binary form must reproduce the above copyright 1553a5a1b3Sopenharmony_ci notice, this list of conditions and the following disclaimer in the 1653a5a1b3Sopenharmony_ci documentation and/or other materials provided with the distribution. 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci 3. The name of the author may not be used to endorse or promote products 1953a5a1b3Sopenharmony_ci derived from this software without specific prior written permission. 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2253a5a1b3Sopenharmony_ci IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2353a5a1b3Sopenharmony_ci OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2453a5a1b3Sopenharmony_ci DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2553a5a1b3Sopenharmony_ci INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2653a5a1b3Sopenharmony_ci (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2753a5a1b3Sopenharmony_ci SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2853a5a1b3Sopenharmony_ci HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2953a5a1b3Sopenharmony_ci STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3053a5a1b3Sopenharmony_ci ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3153a5a1b3Sopenharmony_ci POSSIBILITY OF SUCH DAMAGE. 3253a5a1b3Sopenharmony_ci*/ 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci/* 3653a5a1b3Sopenharmony_ci Recommended papers: 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error 3953a5a1b3Sopenharmony_ci short-time spectral amplitude estimator". IEEE Transactions on Acoustics, 4053a5a1b3Sopenharmony_ci Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error 4353a5a1b3Sopenharmony_ci log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and 4453a5a1b3Sopenharmony_ci Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". 4753a5a1b3Sopenharmony_ci Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic 5053a5a1b3Sopenharmony_ci approach to combined acoustic echo cancellation and noise reduction". IEEE 5153a5a1b3Sopenharmony_ci Transactions on Speech and Audio Processing, 2002. 5253a5a1b3Sopenharmony_ci 5353a5a1b3Sopenharmony_ci J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation 5453a5a1b3Sopenharmony_ci of simultaneous non-stationary sources". In Proceedings IEEE International 5553a5a1b3Sopenharmony_ci Conference on Acoustics, Speech, and Signal Processing, 2004. 5653a5a1b3Sopenharmony_ci*/ 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 5953a5a1b3Sopenharmony_ci#include "config.h" 6053a5a1b3Sopenharmony_ci#endif 6153a5a1b3Sopenharmony_ci 6253a5a1b3Sopenharmony_ci#include <math.h> 6353a5a1b3Sopenharmony_ci#include "speex/speex_preprocess.h" 6453a5a1b3Sopenharmony_ci#include "speex/speex_echo.h" 6553a5a1b3Sopenharmony_ci#include "arch.h" 6653a5a1b3Sopenharmony_ci#include "fftwrap.h" 6753a5a1b3Sopenharmony_ci#include "filterbank.h" 6853a5a1b3Sopenharmony_ci#include "math_approx.h" 6953a5a1b3Sopenharmony_ci#include "os_support.h" 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci#define LOUDNESS_EXP 5.f 7253a5a1b3Sopenharmony_ci#define AMP_SCALE .001f 7353a5a1b3Sopenharmony_ci#define AMP_SCALE_1 1000.f 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci#define NB_BANDS 24 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_ci#define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) 7853a5a1b3Sopenharmony_ci#define SPEECH_PROB_CONTINUE_DEFAULT QCONST16(0.20f,15) 7953a5a1b3Sopenharmony_ci#define NOISE_SUPPRESS_DEFAULT -15 8053a5a1b3Sopenharmony_ci#define ECHO_SUPPRESS_DEFAULT -40 8153a5a1b3Sopenharmony_ci#define ECHO_SUPPRESS_ACTIVE_DEFAULT -15 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci#ifndef NULL 8453a5a1b3Sopenharmony_ci#define NULL 0 8553a5a1b3Sopenharmony_ci#endif 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_ci#define SQR(x) ((x)*(x)) 8853a5a1b3Sopenharmony_ci#define SQR16(x) (MULT16_16((x),(x))) 8953a5a1b3Sopenharmony_ci#define SQR16_Q15(x) (MULT16_16_Q15((x),(x))) 9053a5a1b3Sopenharmony_ci 9153a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 9253a5a1b3Sopenharmony_cistatic inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) 9353a5a1b3Sopenharmony_ci{ 9453a5a1b3Sopenharmony_ci if (SHR32(a,7) >= b) 9553a5a1b3Sopenharmony_ci { 9653a5a1b3Sopenharmony_ci return 32767; 9753a5a1b3Sopenharmony_ci } else { 9853a5a1b3Sopenharmony_ci if (b>=QCONST32(1,23)) 9953a5a1b3Sopenharmony_ci { 10053a5a1b3Sopenharmony_ci a = SHR32(a,8); 10153a5a1b3Sopenharmony_ci b = SHR32(b,8); 10253a5a1b3Sopenharmony_ci } 10353a5a1b3Sopenharmony_ci if (b>=QCONST32(1,19)) 10453a5a1b3Sopenharmony_ci { 10553a5a1b3Sopenharmony_ci a = SHR32(a,4); 10653a5a1b3Sopenharmony_ci b = SHR32(b,4); 10753a5a1b3Sopenharmony_ci } 10853a5a1b3Sopenharmony_ci if (b>=QCONST32(1,15)) 10953a5a1b3Sopenharmony_ci { 11053a5a1b3Sopenharmony_ci a = SHR32(a,4); 11153a5a1b3Sopenharmony_ci b = SHR32(b,4); 11253a5a1b3Sopenharmony_ci } 11353a5a1b3Sopenharmony_ci a = SHL32(a,8); 11453a5a1b3Sopenharmony_ci return PDIV32_16(a,b); 11553a5a1b3Sopenharmony_ci } 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci} 11853a5a1b3Sopenharmony_cistatic inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) 11953a5a1b3Sopenharmony_ci{ 12053a5a1b3Sopenharmony_ci if (SHR32(a,15) >= b) 12153a5a1b3Sopenharmony_ci { 12253a5a1b3Sopenharmony_ci return 32767; 12353a5a1b3Sopenharmony_ci } else { 12453a5a1b3Sopenharmony_ci if (b>=QCONST32(1,23)) 12553a5a1b3Sopenharmony_ci { 12653a5a1b3Sopenharmony_ci a = SHR32(a,8); 12753a5a1b3Sopenharmony_ci b = SHR32(b,8); 12853a5a1b3Sopenharmony_ci } 12953a5a1b3Sopenharmony_ci if (b>=QCONST32(1,19)) 13053a5a1b3Sopenharmony_ci { 13153a5a1b3Sopenharmony_ci a = SHR32(a,4); 13253a5a1b3Sopenharmony_ci b = SHR32(b,4); 13353a5a1b3Sopenharmony_ci } 13453a5a1b3Sopenharmony_ci if (b>=QCONST32(1,15)) 13553a5a1b3Sopenharmony_ci { 13653a5a1b3Sopenharmony_ci a = SHR32(a,4); 13753a5a1b3Sopenharmony_ci b = SHR32(b,4); 13853a5a1b3Sopenharmony_ci } 13953a5a1b3Sopenharmony_ci a = SHL32(a,15)-a; 14053a5a1b3Sopenharmony_ci return DIV32_16(a,b); 14153a5a1b3Sopenharmony_ci } 14253a5a1b3Sopenharmony_ci} 14353a5a1b3Sopenharmony_ci#define SNR_SCALING 256.f 14453a5a1b3Sopenharmony_ci#define SNR_SCALING_1 0.0039062f 14553a5a1b3Sopenharmony_ci#define SNR_SHIFT 8 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ci#define FRAC_SCALING 32767.f 14853a5a1b3Sopenharmony_ci#define FRAC_SCALING_1 3.0518e-05 14953a5a1b3Sopenharmony_ci#define FRAC_SHIFT 1 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci#define EXPIN_SCALING 2048.f 15253a5a1b3Sopenharmony_ci#define EXPIN_SCALING_1 0.00048828f 15353a5a1b3Sopenharmony_ci#define EXPIN_SHIFT 11 15453a5a1b3Sopenharmony_ci#define EXPOUT_SCALING_1 1.5259e-05 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci#define NOISE_SHIFT 7 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci#else 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci#define DIV32_16_Q8(a,b) ((a)/(b)) 16153a5a1b3Sopenharmony_ci#define DIV32_16_Q15(a,b) ((a)/(b)) 16253a5a1b3Sopenharmony_ci#define SNR_SCALING 1.f 16353a5a1b3Sopenharmony_ci#define SNR_SCALING_1 1.f 16453a5a1b3Sopenharmony_ci#define SNR_SHIFT 0 16553a5a1b3Sopenharmony_ci#define FRAC_SCALING 1.f 16653a5a1b3Sopenharmony_ci#define FRAC_SCALING_1 1.f 16753a5a1b3Sopenharmony_ci#define FRAC_SHIFT 0 16853a5a1b3Sopenharmony_ci#define NOISE_SHIFT 0 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci#define EXPIN_SCALING 1.f 17153a5a1b3Sopenharmony_ci#define EXPIN_SCALING_1 1.f 17253a5a1b3Sopenharmony_ci#define EXPOUT_SCALING_1 1.f 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci#endif 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci/** Speex pre-processor state. */ 17753a5a1b3Sopenharmony_cistruct SpeexPreprocessState_ { 17853a5a1b3Sopenharmony_ci /* Basic info */ 17953a5a1b3Sopenharmony_ci int frame_size; /**< Number of samples processed each time */ 18053a5a1b3Sopenharmony_ci int ps_size; /**< Number of points in the power spectrum */ 18153a5a1b3Sopenharmony_ci int sampling_rate; /**< Sampling rate of the input/output */ 18253a5a1b3Sopenharmony_ci int nbands; 18353a5a1b3Sopenharmony_ci FilterBank *bank; 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_ci /* Parameters */ 18653a5a1b3Sopenharmony_ci int denoise_enabled; 18753a5a1b3Sopenharmony_ci int vad_enabled; 18853a5a1b3Sopenharmony_ci int dereverb_enabled; 18953a5a1b3Sopenharmony_ci spx_word16_t reverb_decay; 19053a5a1b3Sopenharmony_ci spx_word16_t reverb_level; 19153a5a1b3Sopenharmony_ci spx_word16_t speech_prob_start; 19253a5a1b3Sopenharmony_ci spx_word16_t speech_prob_continue; 19353a5a1b3Sopenharmony_ci int noise_suppress; 19453a5a1b3Sopenharmony_ci int echo_suppress; 19553a5a1b3Sopenharmony_ci int echo_suppress_active; 19653a5a1b3Sopenharmony_ci SpeexEchoState *echo_state; 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci spx_word16_t speech_prob; /**< Probability last frame was speech */ 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci /* DSP-related arrays */ 20153a5a1b3Sopenharmony_ci spx_word16_t *frame; /**< Processing frame (2*ps_size) */ 20253a5a1b3Sopenharmony_ci spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ 20353a5a1b3Sopenharmony_ci spx_word32_t *ps; /**< Current power spectrum */ 20453a5a1b3Sopenharmony_ci spx_word16_t *gain2; /**< Adjusted gains */ 20553a5a1b3Sopenharmony_ci spx_word16_t *gain_floor; /**< Minimum gain allowed */ 20653a5a1b3Sopenharmony_ci spx_word16_t *window; /**< Analysis/Synthesis window */ 20753a5a1b3Sopenharmony_ci spx_word32_t *noise; /**< Noise estimate */ 20853a5a1b3Sopenharmony_ci spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */ 20953a5a1b3Sopenharmony_ci spx_word32_t *old_ps; /**< Power spectrum for last frame */ 21053a5a1b3Sopenharmony_ci spx_word16_t *gain; /**< Ephraim Malah gain */ 21153a5a1b3Sopenharmony_ci spx_word16_t *prior; /**< A-priori SNR */ 21253a5a1b3Sopenharmony_ci spx_word16_t *post; /**< A-posteriori SNR */ 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci spx_word32_t *S; /**< Smoothed power spectrum */ 21553a5a1b3Sopenharmony_ci spx_word32_t *Smin; /**< See Cohen paper */ 21653a5a1b3Sopenharmony_ci spx_word32_t *Stmp; /**< See Cohen paper */ 21753a5a1b3Sopenharmony_ci int *update_prob; /**< Probability of speech presence for noise update */ 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci spx_word16_t *zeta; /**< Smoothed a priori SNR */ 22053a5a1b3Sopenharmony_ci spx_word32_t *echo_noise; 22153a5a1b3Sopenharmony_ci spx_word32_t *residual_echo; 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci /* Misc */ 22453a5a1b3Sopenharmony_ci spx_word16_t *inbuf; /**< Input buffer (overlapped analysis) */ 22553a5a1b3Sopenharmony_ci spx_word16_t *outbuf; /**< Output buffer (for overlap and add) */ 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci /* AGC stuff, only for floating point for now */ 22853a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 22953a5a1b3Sopenharmony_ci int agc_enabled; 23053a5a1b3Sopenharmony_ci float agc_level; 23153a5a1b3Sopenharmony_ci float loudness_accum; 23253a5a1b3Sopenharmony_ci float *loudness_weight; /**< Perceptual loudness curve */ 23353a5a1b3Sopenharmony_ci float loudness; /**< Loudness estimate */ 23453a5a1b3Sopenharmony_ci float agc_gain; /**< Current AGC gain */ 23553a5a1b3Sopenharmony_ci float max_gain; /**< Maximum gain allowed */ 23653a5a1b3Sopenharmony_ci float max_increase_step; /**< Maximum increase in gain from one frame to another */ 23753a5a1b3Sopenharmony_ci float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ 23853a5a1b3Sopenharmony_ci float prev_loudness; /**< Loudness of previous frame */ 23953a5a1b3Sopenharmony_ci float init_max; /**< Current gain limit during initialisation */ 24053a5a1b3Sopenharmony_ci#endif 24153a5a1b3Sopenharmony_ci int nb_adapt; /**< Number of frames used for adaptation so far */ 24253a5a1b3Sopenharmony_ci int was_speech; 24353a5a1b3Sopenharmony_ci int min_count; /**< Number of frames processed so far */ 24453a5a1b3Sopenharmony_ci void *fft_lookup; /**< Lookup table for the FFT */ 24553a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 24653a5a1b3Sopenharmony_ci int frame_shift; 24753a5a1b3Sopenharmony_ci#endif 24853a5a1b3Sopenharmony_ci}; 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_cistatic void conj_window(spx_word16_t *w, int len) 25253a5a1b3Sopenharmony_ci{ 25353a5a1b3Sopenharmony_ci int i; 25453a5a1b3Sopenharmony_ci for (i=0;i<len;i++) 25553a5a1b3Sopenharmony_ci { 25653a5a1b3Sopenharmony_ci spx_word16_t tmp; 25753a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 25853a5a1b3Sopenharmony_ci spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); 25953a5a1b3Sopenharmony_ci#else 26053a5a1b3Sopenharmony_ci spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); 26153a5a1b3Sopenharmony_ci#endif 26253a5a1b3Sopenharmony_ci int inv=0; 26353a5a1b3Sopenharmony_ci if (x<QCONST16(1.f,13)) 26453a5a1b3Sopenharmony_ci { 26553a5a1b3Sopenharmony_ci } else if (x<QCONST16(2.f,13)) 26653a5a1b3Sopenharmony_ci { 26753a5a1b3Sopenharmony_ci x=QCONST16(2.f,13)-x; 26853a5a1b3Sopenharmony_ci inv=1; 26953a5a1b3Sopenharmony_ci } else if (x<QCONST16(3.f,13)) 27053a5a1b3Sopenharmony_ci { 27153a5a1b3Sopenharmony_ci x=x-QCONST16(2.f,13); 27253a5a1b3Sopenharmony_ci inv=1; 27353a5a1b3Sopenharmony_ci } else { 27453a5a1b3Sopenharmony_ci x=QCONST16(2.f,13)-x+QCONST16(2.f,13); /* 4 - x */ 27553a5a1b3Sopenharmony_ci } 27653a5a1b3Sopenharmony_ci x = MULT16_16_Q14(QCONST16(1.271903f,14), x); 27753a5a1b3Sopenharmony_ci tmp = SQR16_Q15(QCONST16(.5f,15)-MULT16_16_P15(QCONST16(.5f,15),spx_cos_norm(SHL32(EXTEND32(x),2)))); 27853a5a1b3Sopenharmony_ci if (inv) 27953a5a1b3Sopenharmony_ci tmp=SUB16(Q15_ONE,tmp); 28053a5a1b3Sopenharmony_ci w[i]=spx_sqrt(SHL32(EXTEND32(tmp),15)); 28153a5a1b3Sopenharmony_ci } 28253a5a1b3Sopenharmony_ci} 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 28653a5a1b3Sopenharmony_ci/* This function approximates the gain function 28753a5a1b3Sopenharmony_ci y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) 28853a5a1b3Sopenharmony_ci which multiplied by xi/(1+xi) is the optimal gain 28953a5a1b3Sopenharmony_ci in the loudness domain ( sqrt[amplitude] ) 29053a5a1b3Sopenharmony_ci Input in Q11 format, output in Q15 29153a5a1b3Sopenharmony_ci*/ 29253a5a1b3Sopenharmony_cistatic inline spx_word32_t hypergeom_gain(spx_word32_t xx) 29353a5a1b3Sopenharmony_ci{ 29453a5a1b3Sopenharmony_ci int ind; 29553a5a1b3Sopenharmony_ci spx_word16_t frac; 29653a5a1b3Sopenharmony_ci /* Q13 table */ 29753a5a1b3Sopenharmony_ci static const spx_word16_t table[21] = { 29853a5a1b3Sopenharmony_ci 6730, 8357, 9868, 11267, 12563, 13770, 14898, 29953a5a1b3Sopenharmony_ci 15959, 16961, 17911, 18816, 19682, 20512, 21311, 30053a5a1b3Sopenharmony_ci 22082, 22827, 23549, 24250, 24931, 25594, 26241}; 30153a5a1b3Sopenharmony_ci ind = SHR32(xx,10); 30253a5a1b3Sopenharmony_ci if (ind<0) 30353a5a1b3Sopenharmony_ci return Q15_ONE; 30453a5a1b3Sopenharmony_ci if (ind>19) 30553a5a1b3Sopenharmony_ci return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT)))); 30653a5a1b3Sopenharmony_ci frac = SHL32(xx-SHL32(ind,10),5); 30753a5a1b3Sopenharmony_ci 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); 30853a5a1b3Sopenharmony_ci} 30953a5a1b3Sopenharmony_ci 31053a5a1b3Sopenharmony_cistatic inline spx_word16_t qcurve(spx_word16_t x) 31153a5a1b3Sopenharmony_ci{ 31253a5a1b3Sopenharmony_ci x = MAX16(x, 1); 31353a5a1b3Sopenharmony_ci return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x)))); 31453a5a1b3Sopenharmony_ci} 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_ci/* Compute the gain floor based on different floors for the background noise and residual echo */ 31753a5a1b3Sopenharmony_cistatic 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) 31853a5a1b3Sopenharmony_ci{ 31953a5a1b3Sopenharmony_ci int i; 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci if (noise_suppress > effective_echo_suppress) 32253a5a1b3Sopenharmony_ci { 32353a5a1b3Sopenharmony_ci spx_word16_t noise_gain, gain_ratio; 32453a5a1b3Sopenharmony_ci noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1))); 32553a5a1b3Sopenharmony_ci gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1))); 32653a5a1b3Sopenharmony_ci 32753a5a1b3Sopenharmony_ci /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ 32853a5a1b3Sopenharmony_ci for (i=0;i<len;i++) 32953a5a1b3Sopenharmony_ci gain_floor[i] = MULT16_16_Q15(noise_gain, 33053a5a1b3Sopenharmony_ci spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(PSHR32(noise[i],NOISE_SHIFT) + MULT16_32_Q15(gain_ratio,echo[i]), 33153a5a1b3Sopenharmony_ci (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15))); 33253a5a1b3Sopenharmony_ci } else { 33353a5a1b3Sopenharmony_ci spx_word16_t echo_gain, gain_ratio; 33453a5a1b3Sopenharmony_ci echo_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),effective_echo_suppress)),1))); 33553a5a1b3Sopenharmony_ci gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),noise_suppress-effective_echo_suppress)),1))); 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */ 33853a5a1b3Sopenharmony_ci for (i=0;i<len;i++) 33953a5a1b3Sopenharmony_ci gain_floor[i] = MULT16_16_Q15(echo_gain, 34053a5a1b3Sopenharmony_ci spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(MULT16_32_Q15(gain_ratio,PSHR32(noise[i],NOISE_SHIFT)) + echo[i], 34153a5a1b3Sopenharmony_ci (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15))); 34253a5a1b3Sopenharmony_ci } 34353a5a1b3Sopenharmony_ci} 34453a5a1b3Sopenharmony_ci 34553a5a1b3Sopenharmony_ci#else 34653a5a1b3Sopenharmony_ci/* This function approximates the gain function 34753a5a1b3Sopenharmony_ci y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) 34853a5a1b3Sopenharmony_ci which multiplied by xi/(1+xi) is the optimal gain 34953a5a1b3Sopenharmony_ci in the loudness domain ( sqrt[amplitude] ) 35053a5a1b3Sopenharmony_ci*/ 35153a5a1b3Sopenharmony_cistatic inline spx_word32_t hypergeom_gain(spx_word32_t xx) 35253a5a1b3Sopenharmony_ci{ 35353a5a1b3Sopenharmony_ci int ind; 35453a5a1b3Sopenharmony_ci float integer, frac; 35553a5a1b3Sopenharmony_ci float x; 35653a5a1b3Sopenharmony_ci static const float table[21] = { 35753a5a1b3Sopenharmony_ci 0.82157f, 1.02017f, 1.20461f, 1.37534f, 1.53363f, 1.68092f, 1.81865f, 35853a5a1b3Sopenharmony_ci 1.94811f, 2.07038f, 2.18638f, 2.29688f, 2.40255f, 2.50391f, 2.60144f, 35953a5a1b3Sopenharmony_ci 2.69551f, 2.78647f, 2.87458f, 2.96015f, 3.04333f, 3.12431f, 3.20326f}; 36053a5a1b3Sopenharmony_ci x = EXPIN_SCALING_1*xx; 36153a5a1b3Sopenharmony_ci integer = floor(2*x); 36253a5a1b3Sopenharmony_ci ind = (int)integer; 36353a5a1b3Sopenharmony_ci if (ind<0) 36453a5a1b3Sopenharmony_ci return FRAC_SCALING; 36553a5a1b3Sopenharmony_ci if (ind>19) 36653a5a1b3Sopenharmony_ci return FRAC_SCALING*(1+.1296/x); 36753a5a1b3Sopenharmony_ci frac = 2*x-integer; 36853a5a1b3Sopenharmony_ci return FRAC_SCALING*((1-frac)*table[ind] + frac*table[ind+1])/sqrt(x+.0001f); 36953a5a1b3Sopenharmony_ci} 37053a5a1b3Sopenharmony_ci 37153a5a1b3Sopenharmony_cistatic inline spx_word16_t qcurve(spx_word16_t x) 37253a5a1b3Sopenharmony_ci{ 37353a5a1b3Sopenharmony_ci return 1.f/(1.f+.15f/(SNR_SCALING_1*x)); 37453a5a1b3Sopenharmony_ci} 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_cistatic 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) 37753a5a1b3Sopenharmony_ci{ 37853a5a1b3Sopenharmony_ci int i; 37953a5a1b3Sopenharmony_ci float echo_floor; 38053a5a1b3Sopenharmony_ci float noise_floor; 38153a5a1b3Sopenharmony_ci 38253a5a1b3Sopenharmony_ci noise_floor = exp(.2302585f*noise_suppress); 38353a5a1b3Sopenharmony_ci echo_floor = exp(.2302585f*effective_echo_suppress); 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci /* Compute the gain floor based on different floors for the background noise and residual echo */ 38653a5a1b3Sopenharmony_ci for (i=0;i<len;i++) 38753a5a1b3Sopenharmony_ci 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]); 38853a5a1b3Sopenharmony_ci} 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_ci#endif 39153a5a1b3Sopenharmony_ciEXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) 39253a5a1b3Sopenharmony_ci{ 39353a5a1b3Sopenharmony_ci int i; 39453a5a1b3Sopenharmony_ci int N, N3, N4, M; 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci SpeexPreprocessState *st = (SpeexPreprocessState *)speex_alloc(sizeof(SpeexPreprocessState)); 39753a5a1b3Sopenharmony_ci st->frame_size = frame_size; 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci /* Round ps_size down to the nearest power of two */ 40053a5a1b3Sopenharmony_ci#if 0 40153a5a1b3Sopenharmony_ci i=1; 40253a5a1b3Sopenharmony_ci st->ps_size = st->frame_size; 40353a5a1b3Sopenharmony_ci while(1) 40453a5a1b3Sopenharmony_ci { 40553a5a1b3Sopenharmony_ci if (st->ps_size & ~i) 40653a5a1b3Sopenharmony_ci { 40753a5a1b3Sopenharmony_ci st->ps_size &= ~i; 40853a5a1b3Sopenharmony_ci i<<=1; 40953a5a1b3Sopenharmony_ci } else { 41053a5a1b3Sopenharmony_ci break; 41153a5a1b3Sopenharmony_ci } 41253a5a1b3Sopenharmony_ci } 41353a5a1b3Sopenharmony_ci 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci if (st->ps_size < 3*st->frame_size/4) 41653a5a1b3Sopenharmony_ci st->ps_size = st->ps_size * 3 / 2; 41753a5a1b3Sopenharmony_ci#else 41853a5a1b3Sopenharmony_ci st->ps_size = st->frame_size; 41953a5a1b3Sopenharmony_ci#endif 42053a5a1b3Sopenharmony_ci 42153a5a1b3Sopenharmony_ci N = st->ps_size; 42253a5a1b3Sopenharmony_ci N3 = 2*N - st->frame_size; 42353a5a1b3Sopenharmony_ci N4 = st->frame_size - N3; 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci st->sampling_rate = sampling_rate; 42653a5a1b3Sopenharmony_ci st->denoise_enabled = 1; 42753a5a1b3Sopenharmony_ci st->vad_enabled = 0; 42853a5a1b3Sopenharmony_ci st->dereverb_enabled = 0; 42953a5a1b3Sopenharmony_ci st->reverb_decay = 0; 43053a5a1b3Sopenharmony_ci st->reverb_level = 0; 43153a5a1b3Sopenharmony_ci st->noise_suppress = NOISE_SUPPRESS_DEFAULT; 43253a5a1b3Sopenharmony_ci st->echo_suppress = ECHO_SUPPRESS_DEFAULT; 43353a5a1b3Sopenharmony_ci st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT; 43453a5a1b3Sopenharmony_ci 43553a5a1b3Sopenharmony_ci st->speech_prob_start = SPEECH_PROB_START_DEFAULT; 43653a5a1b3Sopenharmony_ci st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci st->echo_state = NULL; 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci st->nbands = NB_BANDS; 44153a5a1b3Sopenharmony_ci M = st->nbands; 44253a5a1b3Sopenharmony_ci st->bank = filterbank_new(M, sampling_rate, N, 1); 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); 44553a5a1b3Sopenharmony_ci st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); 44653a5a1b3Sopenharmony_ci st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); 44753a5a1b3Sopenharmony_ci 44853a5a1b3Sopenharmony_ci st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 44953a5a1b3Sopenharmony_ci st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 45053a5a1b3Sopenharmony_ci st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 45153a5a1b3Sopenharmony_ci st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 45253a5a1b3Sopenharmony_ci st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 45353a5a1b3Sopenharmony_ci st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); 45453a5a1b3Sopenharmony_ci st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 45553a5a1b3Sopenharmony_ci st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 45653a5a1b3Sopenharmony_ci st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 45753a5a1b3Sopenharmony_ci st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 45853a5a1b3Sopenharmony_ci st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 45953a5a1b3Sopenharmony_ci st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); 46053a5a1b3Sopenharmony_ci 46153a5a1b3Sopenharmony_ci st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); 46253a5a1b3Sopenharmony_ci st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); 46353a5a1b3Sopenharmony_ci st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); 46453a5a1b3Sopenharmony_ci st->update_prob = (int*)speex_alloc(N*sizeof(int)); 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); 46753a5a1b3Sopenharmony_ci st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci conj_window(st->window, 2*N3); 47053a5a1b3Sopenharmony_ci for (i=2*N3;i<2*st->ps_size;i++) 47153a5a1b3Sopenharmony_ci st->window[i]=Q15_ONE; 47253a5a1b3Sopenharmony_ci 47353a5a1b3Sopenharmony_ci if (N4>0) 47453a5a1b3Sopenharmony_ci { 47553a5a1b3Sopenharmony_ci for (i=N3-1;i>=0;i--) 47653a5a1b3Sopenharmony_ci { 47753a5a1b3Sopenharmony_ci st->window[i+N3+N4]=st->window[i+N3]; 47853a5a1b3Sopenharmony_ci st->window[i+N3]=1; 47953a5a1b3Sopenharmony_ci } 48053a5a1b3Sopenharmony_ci } 48153a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 48253a5a1b3Sopenharmony_ci { 48353a5a1b3Sopenharmony_ci st->noise[i]=QCONST32(1.f,NOISE_SHIFT); 48453a5a1b3Sopenharmony_ci st->reverb_estimate[i]=0; 48553a5a1b3Sopenharmony_ci st->old_ps[i]=1; 48653a5a1b3Sopenharmony_ci st->gain[i]=Q15_ONE; 48753a5a1b3Sopenharmony_ci st->post[i]=SHL16(1, SNR_SHIFT); 48853a5a1b3Sopenharmony_ci st->prior[i]=SHL16(1, SNR_SHIFT); 48953a5a1b3Sopenharmony_ci } 49053a5a1b3Sopenharmony_ci 49153a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 49253a5a1b3Sopenharmony_ci st->update_prob[i] = 1; 49353a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 49453a5a1b3Sopenharmony_ci { 49553a5a1b3Sopenharmony_ci st->inbuf[i]=0; 49653a5a1b3Sopenharmony_ci st->outbuf[i]=0; 49753a5a1b3Sopenharmony_ci } 49853a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 49953a5a1b3Sopenharmony_ci st->agc_enabled = 0; 50053a5a1b3Sopenharmony_ci st->agc_level = 8000; 50153a5a1b3Sopenharmony_ci st->loudness_weight = (float*)speex_alloc(N*sizeof(float)); 50253a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 50353a5a1b3Sopenharmony_ci { 50453a5a1b3Sopenharmony_ci float ff=((float)i)*.5*sampling_rate/((float)N); 50553a5a1b3Sopenharmony_ci /*st->loudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/ 50653a5a1b3Sopenharmony_ci st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f); 50753a5a1b3Sopenharmony_ci if (st->loudness_weight[i]<.01f) 50853a5a1b3Sopenharmony_ci st->loudness_weight[i]=.01f; 50953a5a1b3Sopenharmony_ci st->loudness_weight[i] *= st->loudness_weight[i]; 51053a5a1b3Sopenharmony_ci } 51153a5a1b3Sopenharmony_ci /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ 51253a5a1b3Sopenharmony_ci st->loudness = 1e-15; 51353a5a1b3Sopenharmony_ci st->agc_gain = 1; 51453a5a1b3Sopenharmony_ci st->max_gain = 30; 51553a5a1b3Sopenharmony_ci st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); 51653a5a1b3Sopenharmony_ci st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); 51753a5a1b3Sopenharmony_ci st->prev_loudness = 1; 51853a5a1b3Sopenharmony_ci st->init_max = 1; 51953a5a1b3Sopenharmony_ci#endif 52053a5a1b3Sopenharmony_ci st->was_speech = 0; 52153a5a1b3Sopenharmony_ci 52253a5a1b3Sopenharmony_ci st->fft_lookup = spx_fft_init(2*N); 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci st->nb_adapt=0; 52553a5a1b3Sopenharmony_ci st->min_count=0; 52653a5a1b3Sopenharmony_ci return st; 52753a5a1b3Sopenharmony_ci} 52853a5a1b3Sopenharmony_ci 52953a5a1b3Sopenharmony_ciEXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st) 53053a5a1b3Sopenharmony_ci{ 53153a5a1b3Sopenharmony_ci speex_free(st->frame); 53253a5a1b3Sopenharmony_ci speex_free(st->ft); 53353a5a1b3Sopenharmony_ci speex_free(st->ps); 53453a5a1b3Sopenharmony_ci speex_free(st->gain2); 53553a5a1b3Sopenharmony_ci speex_free(st->gain_floor); 53653a5a1b3Sopenharmony_ci speex_free(st->window); 53753a5a1b3Sopenharmony_ci speex_free(st->noise); 53853a5a1b3Sopenharmony_ci speex_free(st->reverb_estimate); 53953a5a1b3Sopenharmony_ci speex_free(st->old_ps); 54053a5a1b3Sopenharmony_ci speex_free(st->gain); 54153a5a1b3Sopenharmony_ci speex_free(st->prior); 54253a5a1b3Sopenharmony_ci speex_free(st->post); 54353a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 54453a5a1b3Sopenharmony_ci speex_free(st->loudness_weight); 54553a5a1b3Sopenharmony_ci#endif 54653a5a1b3Sopenharmony_ci speex_free(st->echo_noise); 54753a5a1b3Sopenharmony_ci speex_free(st->residual_echo); 54853a5a1b3Sopenharmony_ci 54953a5a1b3Sopenharmony_ci speex_free(st->S); 55053a5a1b3Sopenharmony_ci speex_free(st->Smin); 55153a5a1b3Sopenharmony_ci speex_free(st->Stmp); 55253a5a1b3Sopenharmony_ci speex_free(st->update_prob); 55353a5a1b3Sopenharmony_ci speex_free(st->zeta); 55453a5a1b3Sopenharmony_ci 55553a5a1b3Sopenharmony_ci speex_free(st->inbuf); 55653a5a1b3Sopenharmony_ci speex_free(st->outbuf); 55753a5a1b3Sopenharmony_ci 55853a5a1b3Sopenharmony_ci spx_fft_destroy(st->fft_lookup); 55953a5a1b3Sopenharmony_ci filterbank_destroy(st->bank); 56053a5a1b3Sopenharmony_ci speex_free(st); 56153a5a1b3Sopenharmony_ci} 56253a5a1b3Sopenharmony_ci 56353a5a1b3Sopenharmony_ci/* FIXME: The AGC doesn't work yet with fixed-point*/ 56453a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 56553a5a1b3Sopenharmony_cistatic void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft) 56653a5a1b3Sopenharmony_ci{ 56753a5a1b3Sopenharmony_ci int i; 56853a5a1b3Sopenharmony_ci int N = st->ps_size; 56953a5a1b3Sopenharmony_ci float target_gain; 57053a5a1b3Sopenharmony_ci float loudness=1.f; 57153a5a1b3Sopenharmony_ci float rate; 57253a5a1b3Sopenharmony_ci 57353a5a1b3Sopenharmony_ci for (i=2;i<N;i++) 57453a5a1b3Sopenharmony_ci { 57553a5a1b3Sopenharmony_ci loudness += 2.f*N*st->ps[i]* st->loudness_weight[i]; 57653a5a1b3Sopenharmony_ci } 57753a5a1b3Sopenharmony_ci loudness=sqrt(loudness); 57853a5a1b3Sopenharmony_ci /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) && 57953a5a1b3Sopenharmony_ci loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ 58053a5a1b3Sopenharmony_ci if (Pframe>.3f) 58153a5a1b3Sopenharmony_ci { 58253a5a1b3Sopenharmony_ci /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ 58353a5a1b3Sopenharmony_ci rate = .03*Pframe*Pframe; 58453a5a1b3Sopenharmony_ci st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); 58553a5a1b3Sopenharmony_ci st->loudness_accum = (1-rate)*st->loudness_accum + rate; 58653a5a1b3Sopenharmony_ci if (st->init_max < st->max_gain && st->nb_adapt > 20) 58753a5a1b3Sopenharmony_ci st->init_max *= 1.f + .1f*Pframe*Pframe; 58853a5a1b3Sopenharmony_ci } 58953a5a1b3Sopenharmony_ci /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ 59053a5a1b3Sopenharmony_ci 59153a5a1b3Sopenharmony_ci target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); 59253a5a1b3Sopenharmony_ci 59353a5a1b3Sopenharmony_ci if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) 59453a5a1b3Sopenharmony_ci { 59553a5a1b3Sopenharmony_ci if (target_gain > st->max_increase_step*st->agc_gain) 59653a5a1b3Sopenharmony_ci target_gain = st->max_increase_step*st->agc_gain; 59753a5a1b3Sopenharmony_ci if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness) 59853a5a1b3Sopenharmony_ci target_gain = st->max_decrease_step*st->agc_gain; 59953a5a1b3Sopenharmony_ci if (target_gain > st->max_gain) 60053a5a1b3Sopenharmony_ci target_gain = st->max_gain; 60153a5a1b3Sopenharmony_ci if (target_gain > st->init_max) 60253a5a1b3Sopenharmony_ci target_gain = st->init_max; 60353a5a1b3Sopenharmony_ci 60453a5a1b3Sopenharmony_ci st->agc_gain = target_gain; 60553a5a1b3Sopenharmony_ci } 60653a5a1b3Sopenharmony_ci /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ 60753a5a1b3Sopenharmony_ci 60853a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 60953a5a1b3Sopenharmony_ci ft[i] *= st->agc_gain; 61053a5a1b3Sopenharmony_ci st->prev_loudness = loudness; 61153a5a1b3Sopenharmony_ci} 61253a5a1b3Sopenharmony_ci#endif 61353a5a1b3Sopenharmony_ci 61453a5a1b3Sopenharmony_cistatic void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) 61553a5a1b3Sopenharmony_ci{ 61653a5a1b3Sopenharmony_ci int i; 61753a5a1b3Sopenharmony_ci int N = st->ps_size; 61853a5a1b3Sopenharmony_ci int N3 = 2*N - st->frame_size; 61953a5a1b3Sopenharmony_ci int N4 = st->frame_size - N3; 62053a5a1b3Sopenharmony_ci spx_word32_t *ps=st->ps; 62153a5a1b3Sopenharmony_ci 62253a5a1b3Sopenharmony_ci /* 'Build' input frame */ 62353a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 62453a5a1b3Sopenharmony_ci st->frame[i]=st->inbuf[i]; 62553a5a1b3Sopenharmony_ci for (i=0;i<st->frame_size;i++) 62653a5a1b3Sopenharmony_ci st->frame[N3+i]=x[i]; 62753a5a1b3Sopenharmony_ci 62853a5a1b3Sopenharmony_ci /* Update inbuf */ 62953a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 63053a5a1b3Sopenharmony_ci st->inbuf[i]=x[N4+i]; 63153a5a1b3Sopenharmony_ci 63253a5a1b3Sopenharmony_ci /* Windowing */ 63353a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 63453a5a1b3Sopenharmony_ci st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); 63553a5a1b3Sopenharmony_ci 63653a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 63753a5a1b3Sopenharmony_ci { 63853a5a1b3Sopenharmony_ci spx_word16_t max_val=0; 63953a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 64053a5a1b3Sopenharmony_ci max_val = MAX16(max_val, ABS16(st->frame[i])); 64153a5a1b3Sopenharmony_ci st->frame_shift = 14-spx_ilog2(EXTEND32(max_val)); 64253a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 64353a5a1b3Sopenharmony_ci st->frame[i] = SHL16(st->frame[i], st->frame_shift); 64453a5a1b3Sopenharmony_ci } 64553a5a1b3Sopenharmony_ci#endif 64653a5a1b3Sopenharmony_ci 64753a5a1b3Sopenharmony_ci /* Perform FFT */ 64853a5a1b3Sopenharmony_ci spx_fft(st->fft_lookup, st->frame, st->ft); 64953a5a1b3Sopenharmony_ci 65053a5a1b3Sopenharmony_ci /* Power spectrum */ 65153a5a1b3Sopenharmony_ci ps[0]=MULT16_16(st->ft[0],st->ft[0]); 65253a5a1b3Sopenharmony_ci for (i=1;i<N;i++) 65353a5a1b3Sopenharmony_ci ps[i]=MULT16_16(st->ft[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]); 65453a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 65553a5a1b3Sopenharmony_ci st->ps[i] = PSHR32(st->ps[i], 2*st->frame_shift); 65653a5a1b3Sopenharmony_ci 65753a5a1b3Sopenharmony_ci filterbank_compute_bank32(st->bank, ps, ps+N); 65853a5a1b3Sopenharmony_ci} 65953a5a1b3Sopenharmony_ci 66053a5a1b3Sopenharmony_cistatic void update_noise_prob(SpeexPreprocessState *st) 66153a5a1b3Sopenharmony_ci{ 66253a5a1b3Sopenharmony_ci int i; 66353a5a1b3Sopenharmony_ci int min_range; 66453a5a1b3Sopenharmony_ci int N = st->ps_size; 66553a5a1b3Sopenharmony_ci 66653a5a1b3Sopenharmony_ci for (i=1;i<N-1;i++) 66753a5a1b3Sopenharmony_ci st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) 66853a5a1b3Sopenharmony_ci + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); 66953a5a1b3Sopenharmony_ci st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); 67053a5a1b3Sopenharmony_ci st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); 67153a5a1b3Sopenharmony_ci 67253a5a1b3Sopenharmony_ci if (st->nb_adapt==1) 67353a5a1b3Sopenharmony_ci { 67453a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 67553a5a1b3Sopenharmony_ci st->Smin[i] = st->Stmp[i] = 0; 67653a5a1b3Sopenharmony_ci } 67753a5a1b3Sopenharmony_ci 67853a5a1b3Sopenharmony_ci if (st->nb_adapt < 100) 67953a5a1b3Sopenharmony_ci min_range = 15; 68053a5a1b3Sopenharmony_ci else if (st->nb_adapt < 1000) 68153a5a1b3Sopenharmony_ci min_range = 50; 68253a5a1b3Sopenharmony_ci else if (st->nb_adapt < 10000) 68353a5a1b3Sopenharmony_ci min_range = 150; 68453a5a1b3Sopenharmony_ci else 68553a5a1b3Sopenharmony_ci min_range = 300; 68653a5a1b3Sopenharmony_ci if (st->min_count > min_range) 68753a5a1b3Sopenharmony_ci { 68853a5a1b3Sopenharmony_ci st->min_count = 0; 68953a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 69053a5a1b3Sopenharmony_ci { 69153a5a1b3Sopenharmony_ci st->Smin[i] = MIN32(st->Stmp[i], st->S[i]); 69253a5a1b3Sopenharmony_ci st->Stmp[i] = st->S[i]; 69353a5a1b3Sopenharmony_ci } 69453a5a1b3Sopenharmony_ci } else { 69553a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 69653a5a1b3Sopenharmony_ci { 69753a5a1b3Sopenharmony_ci st->Smin[i] = MIN32(st->Smin[i], st->S[i]); 69853a5a1b3Sopenharmony_ci st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); 69953a5a1b3Sopenharmony_ci } 70053a5a1b3Sopenharmony_ci } 70153a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 70253a5a1b3Sopenharmony_ci { 70353a5a1b3Sopenharmony_ci if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > st->Smin[i]) 70453a5a1b3Sopenharmony_ci st->update_prob[i] = 1; 70553a5a1b3Sopenharmony_ci else 70653a5a1b3Sopenharmony_ci st->update_prob[i] = 0; 70753a5a1b3Sopenharmony_ci /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/ 70853a5a1b3Sopenharmony_ci /*fprintf (stderr, "%f ", st->update_prob[i]);*/ 70953a5a1b3Sopenharmony_ci } 71053a5a1b3Sopenharmony_ci 71153a5a1b3Sopenharmony_ci} 71253a5a1b3Sopenharmony_ci 71353a5a1b3Sopenharmony_ci#define NOISE_OVERCOMPENS 1. 71453a5a1b3Sopenharmony_ci 71553a5a1b3Sopenharmony_civoid speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); 71653a5a1b3Sopenharmony_ci 71753a5a1b3Sopenharmony_ciEXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) 71853a5a1b3Sopenharmony_ci{ 71953a5a1b3Sopenharmony_ci return speex_preprocess_run(st, x); 72053a5a1b3Sopenharmony_ci} 72153a5a1b3Sopenharmony_ci 72253a5a1b3Sopenharmony_ciEXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) 72353a5a1b3Sopenharmony_ci{ 72453a5a1b3Sopenharmony_ci int i; 72553a5a1b3Sopenharmony_ci int M; 72653a5a1b3Sopenharmony_ci int N = st->ps_size; 72753a5a1b3Sopenharmony_ci int N3 = 2*N - st->frame_size; 72853a5a1b3Sopenharmony_ci int N4 = st->frame_size - N3; 72953a5a1b3Sopenharmony_ci spx_word32_t *ps=st->ps; 73053a5a1b3Sopenharmony_ci spx_word32_t Zframe; 73153a5a1b3Sopenharmony_ci spx_word16_t Pframe; 73253a5a1b3Sopenharmony_ci spx_word16_t beta, beta_1; 73353a5a1b3Sopenharmony_ci spx_word16_t effective_echo_suppress; 73453a5a1b3Sopenharmony_ci 73553a5a1b3Sopenharmony_ci st->nb_adapt++; 73653a5a1b3Sopenharmony_ci if (st->nb_adapt>20000) 73753a5a1b3Sopenharmony_ci st->nb_adapt = 20000; 73853a5a1b3Sopenharmony_ci st->min_count++; 73953a5a1b3Sopenharmony_ci 74053a5a1b3Sopenharmony_ci beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); 74153a5a1b3Sopenharmony_ci beta_1 = Q15_ONE-beta; 74253a5a1b3Sopenharmony_ci M = st->nbands; 74353a5a1b3Sopenharmony_ci /* Deal with residual echo if provided */ 74453a5a1b3Sopenharmony_ci if (st->echo_state) 74553a5a1b3Sopenharmony_ci { 74653a5a1b3Sopenharmony_ci speex_echo_get_residual(st->echo_state, st->residual_echo, N); 74753a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 74853a5a1b3Sopenharmony_ci /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */ 74953a5a1b3Sopenharmony_ci if (!(st->residual_echo[0] >=0 && st->residual_echo[0]<N*1e9f)) 75053a5a1b3Sopenharmony_ci { 75153a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 75253a5a1b3Sopenharmony_ci st->residual_echo[i] = 0; 75353a5a1b3Sopenharmony_ci } 75453a5a1b3Sopenharmony_ci#endif 75553a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 75653a5a1b3Sopenharmony_ci st->echo_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]); 75753a5a1b3Sopenharmony_ci filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N); 75853a5a1b3Sopenharmony_ci } else { 75953a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 76053a5a1b3Sopenharmony_ci st->echo_noise[i] = 0; 76153a5a1b3Sopenharmony_ci } 76253a5a1b3Sopenharmony_ci preprocess_analysis(st, x); 76353a5a1b3Sopenharmony_ci 76453a5a1b3Sopenharmony_ci update_noise_prob(st); 76553a5a1b3Sopenharmony_ci 76653a5a1b3Sopenharmony_ci /* Noise estimation always updated for the 10 first frames */ 76753a5a1b3Sopenharmony_ci /*if (st->nb_adapt<10) 76853a5a1b3Sopenharmony_ci { 76953a5a1b3Sopenharmony_ci for (i=1;i<N-1;i++) 77053a5a1b3Sopenharmony_ci st->update_prob[i] = 0; 77153a5a1b3Sopenharmony_ci } 77253a5a1b3Sopenharmony_ci */ 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci /* Update the noise estimate for the frequencies where it can be */ 77553a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 77653a5a1b3Sopenharmony_ci { 77753a5a1b3Sopenharmony_ci if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT)) 77853a5a1b3Sopenharmony_ci st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT))); 77953a5a1b3Sopenharmony_ci } 78053a5a1b3Sopenharmony_ci filterbank_compute_bank32(st->bank, st->noise, st->noise+N); 78153a5a1b3Sopenharmony_ci 78253a5a1b3Sopenharmony_ci /* Special case for first frame */ 78353a5a1b3Sopenharmony_ci if (st->nb_adapt==1) 78453a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 78553a5a1b3Sopenharmony_ci st->old_ps[i] = ps[i]; 78653a5a1b3Sopenharmony_ci 78753a5a1b3Sopenharmony_ci /* Compute a posteriori SNR */ 78853a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 78953a5a1b3Sopenharmony_ci { 79053a5a1b3Sopenharmony_ci spx_word16_t gamma; 79153a5a1b3Sopenharmony_ci 79253a5a1b3Sopenharmony_ci /* Total noise estimate including residual echo and reverberation */ 79353a5a1b3Sopenharmony_ci spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_ci /* A posteriori SNR = ps/noise - 1*/ 79653a5a1b3Sopenharmony_ci st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); 79753a5a1b3Sopenharmony_ci st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); 79853a5a1b3Sopenharmony_ci 79953a5a1b3Sopenharmony_ci /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ 80053a5a1b3Sopenharmony_ci 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)))); 80153a5a1b3Sopenharmony_ci 80253a5a1b3Sopenharmony_ci /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ 80353a5a1b3Sopenharmony_ci 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)); 80453a5a1b3Sopenharmony_ci st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); 80553a5a1b3Sopenharmony_ci } 80653a5a1b3Sopenharmony_ci 80753a5a1b3Sopenharmony_ci /*print_vec(st->post, N+M, "");*/ 80853a5a1b3Sopenharmony_ci 80953a5a1b3Sopenharmony_ci /* Recursive average of the a priori SNR. A bit smoothed for the psd components */ 81053a5a1b3Sopenharmony_ci st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15); 81153a5a1b3Sopenharmony_ci for (i=1;i<N-1;i++) 81253a5a1b3Sopenharmony_ci st->zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])), 81353a5a1b3Sopenharmony_ci MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15); 81453a5a1b3Sopenharmony_ci for (i=N-1;i<N+M;i++) 81553a5a1b3Sopenharmony_ci st->zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15); 81653a5a1b3Sopenharmony_ci 81753a5a1b3Sopenharmony_ci /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */ 81853a5a1b3Sopenharmony_ci Zframe = 0; 81953a5a1b3Sopenharmony_ci for (i=N;i<N+M;i++) 82053a5a1b3Sopenharmony_ci Zframe = ADD32(Zframe, EXTEND32(st->zeta[i])); 82153a5a1b3Sopenharmony_ci Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); 82253a5a1b3Sopenharmony_ci 82353a5a1b3Sopenharmony_ci effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); 82453a5a1b3Sopenharmony_ci 82553a5a1b3Sopenharmony_ci compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); 82653a5a1b3Sopenharmony_ci 82753a5a1b3Sopenharmony_ci /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) 82853a5a1b3Sopenharmony_ci Technically this is actually wrong because the EM gaim assumes a slightly different probability 82953a5a1b3Sopenharmony_ci distribution */ 83053a5a1b3Sopenharmony_ci for (i=N;i<N+M;i++) 83153a5a1b3Sopenharmony_ci { 83253a5a1b3Sopenharmony_ci /* See EM and Cohen papers*/ 83353a5a1b3Sopenharmony_ci spx_word32_t theta; 83453a5a1b3Sopenharmony_ci /* Gain from hypergeometric function */ 83553a5a1b3Sopenharmony_ci spx_word32_t MM; 83653a5a1b3Sopenharmony_ci /* Weiner filter gain */ 83753a5a1b3Sopenharmony_ci spx_word16_t prior_ratio; 83853a5a1b3Sopenharmony_ci /* a priority probability of speech presence based on Bark sub-band alone */ 83953a5a1b3Sopenharmony_ci spx_word16_t P1; 84053a5a1b3Sopenharmony_ci /* Speech absence a priori probability (considering sub-band and frame) */ 84153a5a1b3Sopenharmony_ci spx_word16_t q; 84253a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 84353a5a1b3Sopenharmony_ci spx_word16_t tmp; 84453a5a1b3Sopenharmony_ci#endif 84553a5a1b3Sopenharmony_ci 84653a5a1b3Sopenharmony_ci prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); 84753a5a1b3Sopenharmony_ci theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci MM = hypergeom_gain(theta); 85053a5a1b3Sopenharmony_ci /* Gain with bound */ 85153a5a1b3Sopenharmony_ci st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); 85253a5a1b3Sopenharmony_ci /* Save old Bark power spectrum */ 85353a5a1b3Sopenharmony_ci 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]); 85453a5a1b3Sopenharmony_ci 85553a5a1b3Sopenharmony_ci P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i])); 85653a5a1b3Sopenharmony_ci q = Q15_ONE-MULT16_16_Q15(Pframe,P1); 85753a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 85853a5a1b3Sopenharmony_ci theta = MIN32(theta, EXTEND32(32767)); 85953a5a1b3Sopenharmony_ci/*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1)))); 86053a5a1b3Sopenharmony_ci tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/ 86153a5a1b3Sopenharmony_ci/*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8)); 86253a5a1b3Sopenharmony_ci st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp)); 86353a5a1b3Sopenharmony_ci#else 86453a5a1b3Sopenharmony_ci st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta)); 86553a5a1b3Sopenharmony_ci#endif 86653a5a1b3Sopenharmony_ci } 86753a5a1b3Sopenharmony_ci /* Convert the EM gains and speech prob to linear frequency */ 86853a5a1b3Sopenharmony_ci filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); 86953a5a1b3Sopenharmony_ci filterbank_compute_psd16(st->bank,st->gain+N, st->gain); 87053a5a1b3Sopenharmony_ci 87153a5a1b3Sopenharmony_ci /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ 87253a5a1b3Sopenharmony_ci if (1) 87353a5a1b3Sopenharmony_ci { 87453a5a1b3Sopenharmony_ci filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); 87553a5a1b3Sopenharmony_ci 87653a5a1b3Sopenharmony_ci /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ 87753a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 87853a5a1b3Sopenharmony_ci { 87953a5a1b3Sopenharmony_ci spx_word32_t MM; 88053a5a1b3Sopenharmony_ci spx_word32_t theta; 88153a5a1b3Sopenharmony_ci spx_word16_t prior_ratio; 88253a5a1b3Sopenharmony_ci spx_word16_t tmp; 88353a5a1b3Sopenharmony_ci spx_word16_t p; 88453a5a1b3Sopenharmony_ci spx_word16_t g; 88553a5a1b3Sopenharmony_ci 88653a5a1b3Sopenharmony_ci /* Wiener filter gain */ 88753a5a1b3Sopenharmony_ci prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); 88853a5a1b3Sopenharmony_ci theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); 88953a5a1b3Sopenharmony_ci 89053a5a1b3Sopenharmony_ci /* Optimal estimator for loudness domain */ 89153a5a1b3Sopenharmony_ci MM = hypergeom_gain(theta); 89253a5a1b3Sopenharmony_ci /* EM gain with bound */ 89353a5a1b3Sopenharmony_ci g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); 89453a5a1b3Sopenharmony_ci /* Interpolated speech probability of presence */ 89553a5a1b3Sopenharmony_ci p = st->gain2[i]; 89653a5a1b3Sopenharmony_ci 89753a5a1b3Sopenharmony_ci /* Constrain the gain to be close to the Bark scale gain */ 89853a5a1b3Sopenharmony_ci if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) 89953a5a1b3Sopenharmony_ci g = MULT16_16(3,st->gain[i]); 90053a5a1b3Sopenharmony_ci st->gain[i] = g; 90153a5a1b3Sopenharmony_ci 90253a5a1b3Sopenharmony_ci /* Save old power spectrum */ 90353a5a1b3Sopenharmony_ci 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]); 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci /* Apply gain floor */ 90653a5a1b3Sopenharmony_ci if (st->gain[i] < st->gain_floor[i]) 90753a5a1b3Sopenharmony_ci st->gain[i] = st->gain_floor[i]; 90853a5a1b3Sopenharmony_ci 90953a5a1b3Sopenharmony_ci /* Exponential decay model for reverberation (unused) */ 91053a5a1b3Sopenharmony_ci /*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];*/ 91153a5a1b3Sopenharmony_ci 91253a5a1b3Sopenharmony_ci /* Take into account speech probability of presence (loudness domain MMSE estimator) */ 91353a5a1b3Sopenharmony_ci /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ 91453a5a1b3Sopenharmony_ci 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))); 91553a5a1b3Sopenharmony_ci st->gain2[i]=SQR16_Q15(tmp); 91653a5a1b3Sopenharmony_ci 91753a5a1b3Sopenharmony_ci /* Use this if you want a log-domain MMSE estimator instead */ 91853a5a1b3Sopenharmony_ci /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/ 91953a5a1b3Sopenharmony_ci } 92053a5a1b3Sopenharmony_ci } else { 92153a5a1b3Sopenharmony_ci for (i=N;i<N+M;i++) 92253a5a1b3Sopenharmony_ci { 92353a5a1b3Sopenharmony_ci spx_word16_t tmp; 92453a5a1b3Sopenharmony_ci spx_word16_t p = st->gain2[i]; 92553a5a1b3Sopenharmony_ci st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); 92653a5a1b3Sopenharmony_ci 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))); 92753a5a1b3Sopenharmony_ci st->gain2[i]=SQR16_Q15(tmp); 92853a5a1b3Sopenharmony_ci } 92953a5a1b3Sopenharmony_ci filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); 93053a5a1b3Sopenharmony_ci } 93153a5a1b3Sopenharmony_ci 93253a5a1b3Sopenharmony_ci /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ 93353a5a1b3Sopenharmony_ci if (!st->denoise_enabled) 93453a5a1b3Sopenharmony_ci { 93553a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 93653a5a1b3Sopenharmony_ci st->gain2[i]=Q15_ONE; 93753a5a1b3Sopenharmony_ci } 93853a5a1b3Sopenharmony_ci 93953a5a1b3Sopenharmony_ci /* Apply computed gain */ 94053a5a1b3Sopenharmony_ci for (i=1;i<N;i++) 94153a5a1b3Sopenharmony_ci { 94253a5a1b3Sopenharmony_ci st->ft[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]); 94353a5a1b3Sopenharmony_ci st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]); 94453a5a1b3Sopenharmony_ci } 94553a5a1b3Sopenharmony_ci st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); 94653a5a1b3Sopenharmony_ci st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); 94753a5a1b3Sopenharmony_ci 94853a5a1b3Sopenharmony_ci /*FIXME: This *will* not work for fixed-point */ 94953a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 95053a5a1b3Sopenharmony_ci if (st->agc_enabled) 95153a5a1b3Sopenharmony_ci speex_compute_agc(st, Pframe, st->ft); 95253a5a1b3Sopenharmony_ci#endif 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci /* Inverse FFT with 1/N scaling */ 95553a5a1b3Sopenharmony_ci spx_ifft(st->fft_lookup, st->ft, st->frame); 95653a5a1b3Sopenharmony_ci /* Scale back to original (lower) amplitude */ 95753a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 95853a5a1b3Sopenharmony_ci st->frame[i] = PSHR16(st->frame[i], st->frame_shift); 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci /*FIXME: This *will* not work for fixed-point */ 96153a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 96253a5a1b3Sopenharmony_ci if (st->agc_enabled) 96353a5a1b3Sopenharmony_ci { 96453a5a1b3Sopenharmony_ci float max_sample=0; 96553a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 96653a5a1b3Sopenharmony_ci if (fabs(st->frame[i])>max_sample) 96753a5a1b3Sopenharmony_ci max_sample = fabs(st->frame[i]); 96853a5a1b3Sopenharmony_ci if (max_sample>28000.f) 96953a5a1b3Sopenharmony_ci { 97053a5a1b3Sopenharmony_ci float damp = 28000.f/max_sample; 97153a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 97253a5a1b3Sopenharmony_ci st->frame[i] *= damp; 97353a5a1b3Sopenharmony_ci } 97453a5a1b3Sopenharmony_ci } 97553a5a1b3Sopenharmony_ci#endif 97653a5a1b3Sopenharmony_ci 97753a5a1b3Sopenharmony_ci /* Synthesis window (for WOLA) */ 97853a5a1b3Sopenharmony_ci for (i=0;i<2*N;i++) 97953a5a1b3Sopenharmony_ci st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); 98053a5a1b3Sopenharmony_ci 98153a5a1b3Sopenharmony_ci /* Perform overlap and add */ 98253a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 98353a5a1b3Sopenharmony_ci x[i] = WORD2INT(ADD32(EXTEND32(st->outbuf[i]), EXTEND32(st->frame[i]))); 98453a5a1b3Sopenharmony_ci for (i=0;i<N4;i++) 98553a5a1b3Sopenharmony_ci x[N3+i] = st->frame[N3+i]; 98653a5a1b3Sopenharmony_ci 98753a5a1b3Sopenharmony_ci /* Update outbuf */ 98853a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 98953a5a1b3Sopenharmony_ci st->outbuf[i] = st->frame[st->frame_size+i]; 99053a5a1b3Sopenharmony_ci 99153a5a1b3Sopenharmony_ci /* FIXME: This VAD is a kludge */ 99253a5a1b3Sopenharmony_ci st->speech_prob = Pframe; 99353a5a1b3Sopenharmony_ci if (st->vad_enabled) 99453a5a1b3Sopenharmony_ci { 99553a5a1b3Sopenharmony_ci if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue)) 99653a5a1b3Sopenharmony_ci { 99753a5a1b3Sopenharmony_ci st->was_speech=1; 99853a5a1b3Sopenharmony_ci return 1; 99953a5a1b3Sopenharmony_ci } else 100053a5a1b3Sopenharmony_ci { 100153a5a1b3Sopenharmony_ci st->was_speech=0; 100253a5a1b3Sopenharmony_ci return 0; 100353a5a1b3Sopenharmony_ci } 100453a5a1b3Sopenharmony_ci } else { 100553a5a1b3Sopenharmony_ci return 1; 100653a5a1b3Sopenharmony_ci } 100753a5a1b3Sopenharmony_ci} 100853a5a1b3Sopenharmony_ci 100953a5a1b3Sopenharmony_ciEXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) 101053a5a1b3Sopenharmony_ci{ 101153a5a1b3Sopenharmony_ci int i; 101253a5a1b3Sopenharmony_ci int N = st->ps_size; 101353a5a1b3Sopenharmony_ci int N3 = 2*N - st->frame_size; 101453a5a1b3Sopenharmony_ci int M; 101553a5a1b3Sopenharmony_ci spx_word32_t *ps=st->ps; 101653a5a1b3Sopenharmony_ci 101753a5a1b3Sopenharmony_ci M = st->nbands; 101853a5a1b3Sopenharmony_ci st->min_count++; 101953a5a1b3Sopenharmony_ci 102053a5a1b3Sopenharmony_ci preprocess_analysis(st, x); 102153a5a1b3Sopenharmony_ci 102253a5a1b3Sopenharmony_ci update_noise_prob(st); 102353a5a1b3Sopenharmony_ci 102453a5a1b3Sopenharmony_ci for (i=1;i<N-1;i++) 102553a5a1b3Sopenharmony_ci { 102653a5a1b3Sopenharmony_ci if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) 102753a5a1b3Sopenharmony_ci { 102853a5a1b3Sopenharmony_ci st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT)); 102953a5a1b3Sopenharmony_ci } 103053a5a1b3Sopenharmony_ci } 103153a5a1b3Sopenharmony_ci 103253a5a1b3Sopenharmony_ci for (i=0;i<N3;i++) 103353a5a1b3Sopenharmony_ci st->outbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]); 103453a5a1b3Sopenharmony_ci 103553a5a1b3Sopenharmony_ci /* Save old power spectrum */ 103653a5a1b3Sopenharmony_ci for (i=0;i<N+M;i++) 103753a5a1b3Sopenharmony_ci st->old_ps[i] = ps[i]; 103853a5a1b3Sopenharmony_ci 103953a5a1b3Sopenharmony_ci for (i=0;i<N;i++) 104053a5a1b3Sopenharmony_ci st->reverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]); 104153a5a1b3Sopenharmony_ci} 104253a5a1b3Sopenharmony_ci 104353a5a1b3Sopenharmony_ci 104453a5a1b3Sopenharmony_ciEXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) 104553a5a1b3Sopenharmony_ci{ 104653a5a1b3Sopenharmony_ci int i; 104753a5a1b3Sopenharmony_ci SpeexPreprocessState *st; 104853a5a1b3Sopenharmony_ci st=(SpeexPreprocessState*)state; 104953a5a1b3Sopenharmony_ci switch(request) 105053a5a1b3Sopenharmony_ci { 105153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_DENOISE: 105253a5a1b3Sopenharmony_ci st->denoise_enabled = (*(spx_int32_t*)ptr); 105353a5a1b3Sopenharmony_ci break; 105453a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_DENOISE: 105553a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->denoise_enabled; 105653a5a1b3Sopenharmony_ci break; 105753a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 105853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC: 105953a5a1b3Sopenharmony_ci st->agc_enabled = (*(spx_int32_t*)ptr); 106053a5a1b3Sopenharmony_ci break; 106153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC: 106253a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->agc_enabled; 106353a5a1b3Sopenharmony_ci break; 106453a5a1b3Sopenharmony_ci#ifndef DISABLE_FLOAT_API 106553a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC_LEVEL: 106653a5a1b3Sopenharmony_ci st->agc_level = (*(float*)ptr); 106753a5a1b3Sopenharmony_ci if (st->agc_level<1) 106853a5a1b3Sopenharmony_ci st->agc_level=1; 106953a5a1b3Sopenharmony_ci if (st->agc_level>32768) 107053a5a1b3Sopenharmony_ci st->agc_level=32768; 107153a5a1b3Sopenharmony_ci break; 107253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_LEVEL: 107353a5a1b3Sopenharmony_ci (*(float*)ptr) = st->agc_level; 107453a5a1b3Sopenharmony_ci break; 107553a5a1b3Sopenharmony_ci#endif /* #ifndef DISABLE_FLOAT_API */ 107653a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC_INCREMENT: 107753a5a1b3Sopenharmony_ci st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); 107853a5a1b3Sopenharmony_ci break; 107953a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_INCREMENT: 108053a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size); 108153a5a1b3Sopenharmony_ci break; 108253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC_DECREMENT: 108353a5a1b3Sopenharmony_ci st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate); 108453a5a1b3Sopenharmony_ci break; 108553a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_DECREMENT: 108653a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size); 108753a5a1b3Sopenharmony_ci break; 108853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN: 108953a5a1b3Sopenharmony_ci st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr)); 109053a5a1b3Sopenharmony_ci break; 109153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN: 109253a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain)); 109353a5a1b3Sopenharmony_ci break; 109453a5a1b3Sopenharmony_ci#endif 109553a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_VAD: 109653a5a1b3Sopenharmony_ci speex_warning("The VAD has been replaced by a hack pending a complete rewrite"); 109753a5a1b3Sopenharmony_ci st->vad_enabled = (*(spx_int32_t*)ptr); 109853a5a1b3Sopenharmony_ci break; 109953a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_VAD: 110053a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->vad_enabled; 110153a5a1b3Sopenharmony_ci break; 110253a5a1b3Sopenharmony_ci 110353a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_DEREVERB: 110453a5a1b3Sopenharmony_ci st->dereverb_enabled = (*(spx_int32_t*)ptr); 110553a5a1b3Sopenharmony_ci for (i=0;i<st->ps_size;i++) 110653a5a1b3Sopenharmony_ci st->reverb_estimate[i]=0; 110753a5a1b3Sopenharmony_ci break; 110853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_DEREVERB: 110953a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->dereverb_enabled; 111053a5a1b3Sopenharmony_ci break; 111153a5a1b3Sopenharmony_ci 111253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL: 111353a5a1b3Sopenharmony_ci /* FIXME: Re-enable when de-reverberation is actually enabled again */ 111453a5a1b3Sopenharmony_ci /*st->reverb_level = (*(float*)ptr);*/ 111553a5a1b3Sopenharmony_ci break; 111653a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_DEREVERB_LEVEL: 111753a5a1b3Sopenharmony_ci /* FIXME: Re-enable when de-reverberation is actually enabled again */ 111853a5a1b3Sopenharmony_ci /*(*(float*)ptr) = st->reverb_level;*/ 111953a5a1b3Sopenharmony_ci break; 112053a5a1b3Sopenharmony_ci 112153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: 112253a5a1b3Sopenharmony_ci /* FIXME: Re-enable when de-reverberation is actually enabled again */ 112353a5a1b3Sopenharmony_ci /*st->reverb_decay = (*(float*)ptr);*/ 112453a5a1b3Sopenharmony_ci break; 112553a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_DEREVERB_DECAY: 112653a5a1b3Sopenharmony_ci /* FIXME: Re-enable when de-reverberation is actually enabled again */ 112753a5a1b3Sopenharmony_ci /*(*(float*)ptr) = st->reverb_decay;*/ 112853a5a1b3Sopenharmony_ci break; 112953a5a1b3Sopenharmony_ci 113053a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_PROB_START: 113153a5a1b3Sopenharmony_ci *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); 113253a5a1b3Sopenharmony_ci st->speech_prob_start = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); 113353a5a1b3Sopenharmony_ci break; 113453a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_PROB_START: 113553a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100); 113653a5a1b3Sopenharmony_ci break; 113753a5a1b3Sopenharmony_ci 113853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_PROB_CONTINUE: 113953a5a1b3Sopenharmony_ci *(spx_int32_t*)ptr = MIN32(100,MAX32(0, *(spx_int32_t*)ptr)); 114053a5a1b3Sopenharmony_ci st->speech_prob_continue = DIV32_16(MULT16_16(Q15ONE,*(spx_int32_t*)ptr), 100); 114153a5a1b3Sopenharmony_ci break; 114253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_PROB_CONTINUE: 114353a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100); 114453a5a1b3Sopenharmony_ci break; 114553a5a1b3Sopenharmony_ci 114653a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS: 114753a5a1b3Sopenharmony_ci st->noise_suppress = -ABS(*(spx_int32_t*)ptr); 114853a5a1b3Sopenharmony_ci break; 114953a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS: 115053a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->noise_suppress; 115153a5a1b3Sopenharmony_ci break; 115253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS: 115353a5a1b3Sopenharmony_ci st->echo_suppress = -ABS(*(spx_int32_t*)ptr); 115453a5a1b3Sopenharmony_ci break; 115553a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS: 115653a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->echo_suppress; 115753a5a1b3Sopenharmony_ci break; 115853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE: 115953a5a1b3Sopenharmony_ci st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr); 116053a5a1b3Sopenharmony_ci break; 116153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE: 116253a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->echo_suppress_active; 116353a5a1b3Sopenharmony_ci break; 116453a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_ECHO_STATE: 116553a5a1b3Sopenharmony_ci st->echo_state = (SpeexEchoState*)ptr; 116653a5a1b3Sopenharmony_ci break; 116753a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_ECHO_STATE: 116853a5a1b3Sopenharmony_ci (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state; 116953a5a1b3Sopenharmony_ci break; 117053a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 117153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: 117253a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); 117353a5a1b3Sopenharmony_ci break; 117453a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_GAIN: 117553a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain)); 117653a5a1b3Sopenharmony_ci break; 117753a5a1b3Sopenharmony_ci#endif 117853a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_PSD_SIZE: 117953a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE: 118053a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->ps_size; 118153a5a1b3Sopenharmony_ci break; 118253a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_PSD: 118353a5a1b3Sopenharmony_ci for(i=0;i<st->ps_size;i++) 118453a5a1b3Sopenharmony_ci ((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i]; 118553a5a1b3Sopenharmony_ci break; 118653a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_NOISE_PSD: 118753a5a1b3Sopenharmony_ci for(i=0;i<st->ps_size;i++) 118853a5a1b3Sopenharmony_ci ((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT); 118953a5a1b3Sopenharmony_ci break; 119053a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_PROB: 119153a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100); 119253a5a1b3Sopenharmony_ci break; 119353a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 119453a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_SET_AGC_TARGET: 119553a5a1b3Sopenharmony_ci st->agc_level = (*(spx_int32_t*)ptr); 119653a5a1b3Sopenharmony_ci if (st->agc_level<1) 119753a5a1b3Sopenharmony_ci st->agc_level=1; 119853a5a1b3Sopenharmony_ci if (st->agc_level>32768) 119953a5a1b3Sopenharmony_ci st->agc_level=32768; 120053a5a1b3Sopenharmony_ci break; 120153a5a1b3Sopenharmony_ci case SPEEX_PREPROCESS_GET_AGC_TARGET: 120253a5a1b3Sopenharmony_ci (*(spx_int32_t*)ptr) = st->agc_level; 120353a5a1b3Sopenharmony_ci break; 120453a5a1b3Sopenharmony_ci#endif 120553a5a1b3Sopenharmony_ci default: 120653a5a1b3Sopenharmony_ci speex_warning_int("Unknown speex_preprocess_ctl request: ", request); 120753a5a1b3Sopenharmony_ci return -1; 120853a5a1b3Sopenharmony_ci } 120953a5a1b3Sopenharmony_ci return 0; 121053a5a1b3Sopenharmony_ci} 121153a5a1b3Sopenharmony_ci 121253a5a1b3Sopenharmony_ci#ifdef FIXED_DEBUG 121353a5a1b3Sopenharmony_cilong long spx_mips=0; 121453a5a1b3Sopenharmony_ci#endif 121553a5a1b3Sopenharmony_ci 1216