xref: /aosp_15_r20/external/libopus/silk/VAD.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1*a58d3d2aSXin Li /***********************************************************************
2*a58d3d2aSXin Li Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3*a58d3d2aSXin Li Redistribution and use in source and binary forms, with or without
4*a58d3d2aSXin Li modification, are permitted provided that the following conditions
5*a58d3d2aSXin Li are met:
6*a58d3d2aSXin Li - Redistributions of source code must retain the above copyright notice,
7*a58d3d2aSXin Li this list of conditions and the following disclaimer.
8*a58d3d2aSXin Li - Redistributions in binary form must reproduce the above copyright
9*a58d3d2aSXin Li notice, this list of conditions and the following disclaimer in the
10*a58d3d2aSXin Li documentation and/or other materials provided with the distribution.
11*a58d3d2aSXin Li - Neither the name of Internet Society, IETF or IETF Trust, nor the
12*a58d3d2aSXin Li names of specific contributors, may be used to endorse or promote
13*a58d3d2aSXin Li products derived from this software without specific prior written
14*a58d3d2aSXin Li permission.
15*a58d3d2aSXin Li THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16*a58d3d2aSXin Li AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*a58d3d2aSXin Li IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*a58d3d2aSXin Li ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19*a58d3d2aSXin Li LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20*a58d3d2aSXin Li CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21*a58d3d2aSXin Li SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22*a58d3d2aSXin Li INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*a58d3d2aSXin Li CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24*a58d3d2aSXin Li ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25*a58d3d2aSXin Li POSSIBILITY OF SUCH DAMAGE.
26*a58d3d2aSXin Li ***********************************************************************/
27*a58d3d2aSXin Li 
28*a58d3d2aSXin Li #ifdef HAVE_CONFIG_H
29*a58d3d2aSXin Li #include "config.h"
30*a58d3d2aSXin Li #endif
31*a58d3d2aSXin Li 
32*a58d3d2aSXin Li #include "main.h"
33*a58d3d2aSXin Li #include "stack_alloc.h"
34*a58d3d2aSXin Li 
35*a58d3d2aSXin Li /* Silk VAD noise level estimation */
36*a58d3d2aSXin Li # if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
37*a58d3d2aSXin Li static OPUS_INLINE void silk_VAD_GetNoiseLevels(
38*a58d3d2aSXin Li     const opus_int32             pX[ VAD_N_BANDS ], /* I    subband energies                            */
39*a58d3d2aSXin Li     silk_VAD_state              *psSilk_VAD         /* I/O  Pointer to Silk VAD state                   */
40*a58d3d2aSXin Li );
41*a58d3d2aSXin Li #endif
42*a58d3d2aSXin Li 
43*a58d3d2aSXin Li /**********************************/
44*a58d3d2aSXin Li /* Initialization of the Silk VAD */
45*a58d3d2aSXin Li /**********************************/
silk_VAD_Init(silk_VAD_state * psSilk_VAD)46*a58d3d2aSXin Li opus_int silk_VAD_Init(                                         /* O    Return value, 0 if success                  */
47*a58d3d2aSXin Li     silk_VAD_state              *psSilk_VAD                     /* I/O  Pointer to Silk VAD state                   */
48*a58d3d2aSXin Li )
49*a58d3d2aSXin Li {
50*a58d3d2aSXin Li     opus_int b, ret = 0;
51*a58d3d2aSXin Li 
52*a58d3d2aSXin Li     /* reset state memory */
53*a58d3d2aSXin Li     silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
54*a58d3d2aSXin Li 
55*a58d3d2aSXin Li     /* init noise levels */
56*a58d3d2aSXin Li     /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
57*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
58*a58d3d2aSXin Li         psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
59*a58d3d2aSXin Li     }
60*a58d3d2aSXin Li 
61*a58d3d2aSXin Li     /* Initialize state */
62*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
63*a58d3d2aSXin Li         psSilk_VAD->NL[ b ]     = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
64*a58d3d2aSXin Li         psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
65*a58d3d2aSXin Li     }
66*a58d3d2aSXin Li     psSilk_VAD->counter = 15;
67*a58d3d2aSXin Li 
68*a58d3d2aSXin Li     /* init smoothed energy-to-noise ratio*/
69*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
70*a58d3d2aSXin Li         psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256;       /* 100 * 256 --> 20 dB SNR */
71*a58d3d2aSXin Li     }
72*a58d3d2aSXin Li 
73*a58d3d2aSXin Li     return( ret );
74*a58d3d2aSXin Li }
75*a58d3d2aSXin Li 
76*a58d3d2aSXin Li /* Weighting factors for tilt measure */
77*a58d3d2aSXin Li static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
78*a58d3d2aSXin Li 
79*a58d3d2aSXin Li /***************************************/
80*a58d3d2aSXin Li /* Get the speech activity level in Q8 */
81*a58d3d2aSXin Li /***************************************/
silk_VAD_GetSA_Q8_c(silk_encoder_state * psEncC,const opus_int16 pIn[])82*a58d3d2aSXin Li opus_int silk_VAD_GetSA_Q8_c(                                   /* O    Return value, 0 if success                  */
83*a58d3d2aSXin Li     silk_encoder_state          *psEncC,                        /* I/O  Encoder state                               */
84*a58d3d2aSXin Li     const opus_int16            pIn[]                           /* I    PCM input                                   */
85*a58d3d2aSXin Li )
86*a58d3d2aSXin Li {
87*a58d3d2aSXin Li     opus_int   SA_Q15, pSNR_dB_Q7, input_tilt;
88*a58d3d2aSXin Li     opus_int   decimated_framelength1, decimated_framelength2;
89*a58d3d2aSXin Li     opus_int   decimated_framelength;
90*a58d3d2aSXin Li     opus_int   dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
91*a58d3d2aSXin Li     opus_int32 sumSquared, smooth_coef_Q16;
92*a58d3d2aSXin Li     opus_int16 HPstateTmp;
93*a58d3d2aSXin Li     VARDECL( opus_int16, X );
94*a58d3d2aSXin Li     opus_int32 Xnrg[ VAD_N_BANDS ];
95*a58d3d2aSXin Li     opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
96*a58d3d2aSXin Li     opus_int32 speech_nrg, x_tmp;
97*a58d3d2aSXin Li     opus_int   X_offset[ VAD_N_BANDS ];
98*a58d3d2aSXin Li     opus_int   ret = 0;
99*a58d3d2aSXin Li     silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
100*a58d3d2aSXin Li     SAVE_STACK;
101*a58d3d2aSXin Li 
102*a58d3d2aSXin Li     /* Safety checks */
103*a58d3d2aSXin Li     silk_assert( VAD_N_BANDS == 4 );
104*a58d3d2aSXin Li     celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
105*a58d3d2aSXin Li     celt_assert( psEncC->frame_length <= 512 );
106*a58d3d2aSXin Li     celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
107*a58d3d2aSXin Li 
108*a58d3d2aSXin Li     /***********************/
109*a58d3d2aSXin Li     /* Filter and Decimate */
110*a58d3d2aSXin Li     /***********************/
111*a58d3d2aSXin Li     decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
112*a58d3d2aSXin Li     decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
113*a58d3d2aSXin Li     decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
114*a58d3d2aSXin Li     /* Decimate into 4 bands:
115*a58d3d2aSXin Li        0       L      3L       L              3L                             5L
116*a58d3d2aSXin Li                -      --       -              --                             --
117*a58d3d2aSXin Li                8       8       2               4                              4
118*a58d3d2aSXin Li 
119*a58d3d2aSXin Li        [0-1 kHz| temp. |1-2 kHz|    2-4 kHz    |            4-8 kHz           |
120*a58d3d2aSXin Li 
121*a58d3d2aSXin Li        They're arranged to allow the minimal ( frame_length / 4 ) extra
122*a58d3d2aSXin Li        scratch space during the downsampling process */
123*a58d3d2aSXin Li     X_offset[ 0 ] = 0;
124*a58d3d2aSXin Li     X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
125*a58d3d2aSXin Li     X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
126*a58d3d2aSXin Li     X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
127*a58d3d2aSXin Li     ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
128*a58d3d2aSXin Li 
129*a58d3d2aSXin Li     /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
130*a58d3d2aSXin Li     silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[  0 ],
131*a58d3d2aSXin Li         X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
132*a58d3d2aSXin Li 
133*a58d3d2aSXin Li     /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
134*a58d3d2aSXin Li     silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
135*a58d3d2aSXin Li         X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
136*a58d3d2aSXin Li 
137*a58d3d2aSXin Li     /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
138*a58d3d2aSXin Li     silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
139*a58d3d2aSXin Li         X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
140*a58d3d2aSXin Li 
141*a58d3d2aSXin Li     /*********************************************/
142*a58d3d2aSXin Li     /* HP filter on lowest band (differentiator) */
143*a58d3d2aSXin Li     /*********************************************/
144*a58d3d2aSXin Li     X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
145*a58d3d2aSXin Li     HPstateTmp = X[ decimated_framelength - 1 ];
146*a58d3d2aSXin Li     for( i = decimated_framelength - 1; i > 0; i-- ) {
147*a58d3d2aSXin Li         X[ i - 1 ]  = silk_RSHIFT( X[ i - 1 ], 1 );
148*a58d3d2aSXin Li         X[ i ]     -= X[ i - 1 ];
149*a58d3d2aSXin Li     }
150*a58d3d2aSXin Li     X[ 0 ] -= psSilk_VAD->HPstate;
151*a58d3d2aSXin Li     psSilk_VAD->HPstate = HPstateTmp;
152*a58d3d2aSXin Li 
153*a58d3d2aSXin Li     /*************************************/
154*a58d3d2aSXin Li     /* Calculate the energy in each band */
155*a58d3d2aSXin Li     /*************************************/
156*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
157*a58d3d2aSXin Li         /* Find the decimated framelength in the non-uniformly divided bands */
158*a58d3d2aSXin Li         decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
159*a58d3d2aSXin Li 
160*a58d3d2aSXin Li         /* Split length into subframe lengths */
161*a58d3d2aSXin Li         dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
162*a58d3d2aSXin Li         dec_subframe_offset = 0;
163*a58d3d2aSXin Li 
164*a58d3d2aSXin Li         /* Compute energy per sub-frame */
165*a58d3d2aSXin Li         /* initialize with summed energy of last subframe */
166*a58d3d2aSXin Li         Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
167*a58d3d2aSXin Li         for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
168*a58d3d2aSXin Li             sumSquared = 0;
169*a58d3d2aSXin Li             for( i = 0; i < dec_subframe_length; i++ ) {
170*a58d3d2aSXin Li                 /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2.            */
171*a58d3d2aSXin Li                 /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128)  */
172*a58d3d2aSXin Li                 x_tmp = silk_RSHIFT(
173*a58d3d2aSXin Li                     X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
174*a58d3d2aSXin Li                 sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
175*a58d3d2aSXin Li 
176*a58d3d2aSXin Li                 /* Safety check */
177*a58d3d2aSXin Li                 silk_assert( sumSquared >= 0 );
178*a58d3d2aSXin Li             }
179*a58d3d2aSXin Li 
180*a58d3d2aSXin Li             /* Add/saturate summed energy of current subframe */
181*a58d3d2aSXin Li             if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
182*a58d3d2aSXin Li                 Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
183*a58d3d2aSXin Li             } else {
184*a58d3d2aSXin Li                 /* Look-ahead subframe */
185*a58d3d2aSXin Li                 Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
186*a58d3d2aSXin Li             }
187*a58d3d2aSXin Li 
188*a58d3d2aSXin Li             dec_subframe_offset += dec_subframe_length;
189*a58d3d2aSXin Li         }
190*a58d3d2aSXin Li         psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
191*a58d3d2aSXin Li     }
192*a58d3d2aSXin Li 
193*a58d3d2aSXin Li     /********************/
194*a58d3d2aSXin Li     /* Noise estimation */
195*a58d3d2aSXin Li     /********************/
196*a58d3d2aSXin Li     silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
197*a58d3d2aSXin Li 
198*a58d3d2aSXin Li     /***********************************************/
199*a58d3d2aSXin Li     /* Signal-plus-noise to noise ratio estimation */
200*a58d3d2aSXin Li     /***********************************************/
201*a58d3d2aSXin Li     sumSquared = 0;
202*a58d3d2aSXin Li     input_tilt = 0;
203*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
204*a58d3d2aSXin Li         speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
205*a58d3d2aSXin Li         if( speech_nrg > 0 ) {
206*a58d3d2aSXin Li             /* Divide, with sufficient resolution */
207*a58d3d2aSXin Li             if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
208*a58d3d2aSXin Li                 NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
209*a58d3d2aSXin Li             } else {
210*a58d3d2aSXin Li                 NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
211*a58d3d2aSXin Li             }
212*a58d3d2aSXin Li 
213*a58d3d2aSXin Li             /* Convert to log domain */
214*a58d3d2aSXin Li             SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
215*a58d3d2aSXin Li 
216*a58d3d2aSXin Li             /* Sum-of-squares */
217*a58d3d2aSXin Li             sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 );          /* Q14 */
218*a58d3d2aSXin Li 
219*a58d3d2aSXin Li             /* Tilt measure */
220*a58d3d2aSXin Li             if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
221*a58d3d2aSXin Li                 /* Scale down SNR value for small subband speech energies */
222*a58d3d2aSXin Li                 SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
223*a58d3d2aSXin Li             }
224*a58d3d2aSXin Li             input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
225*a58d3d2aSXin Li         } else {
226*a58d3d2aSXin Li             NrgToNoiseRatio_Q8[ b ] = 256;
227*a58d3d2aSXin Li         }
228*a58d3d2aSXin Li     }
229*a58d3d2aSXin Li 
230*a58d3d2aSXin Li     /* Mean-of-squares */
231*a58d3d2aSXin Li     sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
232*a58d3d2aSXin Li 
233*a58d3d2aSXin Li     /* Root-mean-square approximation, scale to dBs, and write to output pointer */
234*a58d3d2aSXin Li     pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
235*a58d3d2aSXin Li 
236*a58d3d2aSXin Li     /*********************************/
237*a58d3d2aSXin Li     /* Speech Probability Estimation */
238*a58d3d2aSXin Li     /*********************************/
239*a58d3d2aSXin Li     SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
240*a58d3d2aSXin Li 
241*a58d3d2aSXin Li     /**************************/
242*a58d3d2aSXin Li     /* Frequency Tilt Measure */
243*a58d3d2aSXin Li     /**************************/
244*a58d3d2aSXin Li     psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
245*a58d3d2aSXin Li 
246*a58d3d2aSXin Li     /**************************************************/
247*a58d3d2aSXin Li     /* Scale the sigmoid output based on power levels */
248*a58d3d2aSXin Li     /**************************************************/
249*a58d3d2aSXin Li     speech_nrg = 0;
250*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
251*a58d3d2aSXin Li         /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
252*a58d3d2aSXin Li         speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
253*a58d3d2aSXin Li     }
254*a58d3d2aSXin Li 
255*a58d3d2aSXin Li     if( psEncC->frame_length == 20 * psEncC->fs_kHz ) {
256*a58d3d2aSXin Li         speech_nrg = silk_RSHIFT32( speech_nrg, 1 );
257*a58d3d2aSXin Li     }
258*a58d3d2aSXin Li     /* Power scaling */
259*a58d3d2aSXin Li     if( speech_nrg <= 0 ) {
260*a58d3d2aSXin Li         SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
261*a58d3d2aSXin Li     } else if( speech_nrg < 16384 ) {
262*a58d3d2aSXin Li         speech_nrg = silk_LSHIFT32( speech_nrg, 16 );
263*a58d3d2aSXin Li 
264*a58d3d2aSXin Li         /* square-root */
265*a58d3d2aSXin Li         speech_nrg = silk_SQRT_APPROX( speech_nrg );
266*a58d3d2aSXin Li         SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
267*a58d3d2aSXin Li     }
268*a58d3d2aSXin Li 
269*a58d3d2aSXin Li     /* Copy the resulting speech activity in Q8 */
270*a58d3d2aSXin Li     psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
271*a58d3d2aSXin Li 
272*a58d3d2aSXin Li     /***********************************/
273*a58d3d2aSXin Li     /* Energy Level and SNR estimation */
274*a58d3d2aSXin Li     /***********************************/
275*a58d3d2aSXin Li     /* Smoothing coefficient */
276*a58d3d2aSXin Li     smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
277*a58d3d2aSXin Li 
278*a58d3d2aSXin Li     if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
279*a58d3d2aSXin Li         smooth_coef_Q16 >>= 1;
280*a58d3d2aSXin Li     }
281*a58d3d2aSXin Li 
282*a58d3d2aSXin Li     for( b = 0; b < VAD_N_BANDS; b++ ) {
283*a58d3d2aSXin Li         /* compute smoothed energy-to-noise ratio per band */
284*a58d3d2aSXin Li         psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
285*a58d3d2aSXin Li             NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
286*a58d3d2aSXin Li 
287*a58d3d2aSXin Li         /* signal to noise ratio in dB per band */
288*a58d3d2aSXin Li         SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
289*a58d3d2aSXin Li         /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
290*a58d3d2aSXin Li         psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
291*a58d3d2aSXin Li     }
292*a58d3d2aSXin Li 
293*a58d3d2aSXin Li     RESTORE_STACK;
294*a58d3d2aSXin Li     return( ret );
295*a58d3d2aSXin Li }
296*a58d3d2aSXin Li 
297*a58d3d2aSXin Li /**************************/
298*a58d3d2aSXin Li /* Noise level estimation */
299*a58d3d2aSXin Li /**************************/
300*a58d3d2aSXin Li # if  !defined(OPUS_X86_MAY_HAVE_SSE4_1)
301*a58d3d2aSXin Li static OPUS_INLINE
302*a58d3d2aSXin Li #endif
silk_VAD_GetNoiseLevels(const opus_int32 pX[VAD_N_BANDS],silk_VAD_state * psSilk_VAD)303*a58d3d2aSXin Li void silk_VAD_GetNoiseLevels(
304*a58d3d2aSXin Li     const opus_int32            pX[ VAD_N_BANDS ],  /* I    subband energies                            */
305*a58d3d2aSXin Li     silk_VAD_state              *psSilk_VAD         /* I/O  Pointer to Silk VAD state                   */
306*a58d3d2aSXin Li )
307*a58d3d2aSXin Li {
308*a58d3d2aSXin Li     opus_int   k;
309*a58d3d2aSXin Li     opus_int32 nl, nrg, inv_nrg;
310*a58d3d2aSXin Li     opus_int   coef, min_coef;
311*a58d3d2aSXin Li 
312*a58d3d2aSXin Li     /* Initially faster smoothing */
313*a58d3d2aSXin Li     if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
314*a58d3d2aSXin Li         min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
315*a58d3d2aSXin Li         /* Increment frame counter */
316*a58d3d2aSXin Li         psSilk_VAD->counter++;
317*a58d3d2aSXin Li     } else {
318*a58d3d2aSXin Li         min_coef = 0;
319*a58d3d2aSXin Li     }
320*a58d3d2aSXin Li 
321*a58d3d2aSXin Li     for( k = 0; k < VAD_N_BANDS; k++ ) {
322*a58d3d2aSXin Li         /* Get old noise level estimate for current band */
323*a58d3d2aSXin Li         nl = psSilk_VAD->NL[ k ];
324*a58d3d2aSXin Li         silk_assert( nl >= 0 );
325*a58d3d2aSXin Li 
326*a58d3d2aSXin Li         /* Add bias */
327*a58d3d2aSXin Li         nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
328*a58d3d2aSXin Li         silk_assert( nrg > 0 );
329*a58d3d2aSXin Li 
330*a58d3d2aSXin Li         /* Invert energies */
331*a58d3d2aSXin Li         inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
332*a58d3d2aSXin Li         silk_assert( inv_nrg >= 0 );
333*a58d3d2aSXin Li 
334*a58d3d2aSXin Li         /* Less update when subband energy is high */
335*a58d3d2aSXin Li         if( nrg > silk_LSHIFT( nl, 3 ) ) {
336*a58d3d2aSXin Li             coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
337*a58d3d2aSXin Li         } else if( nrg < nl ) {
338*a58d3d2aSXin Li             coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
339*a58d3d2aSXin Li         } else {
340*a58d3d2aSXin Li             coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
341*a58d3d2aSXin Li         }
342*a58d3d2aSXin Li 
343*a58d3d2aSXin Li         /* Initially faster smoothing */
344*a58d3d2aSXin Li         coef = silk_max_int( coef, min_coef );
345*a58d3d2aSXin Li 
346*a58d3d2aSXin Li         /* Smooth inverse energies */
347*a58d3d2aSXin Li         psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
348*a58d3d2aSXin Li         silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
349*a58d3d2aSXin Li 
350*a58d3d2aSXin Li         /* Compute noise level by inverting again */
351*a58d3d2aSXin Li         nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
352*a58d3d2aSXin Li         silk_assert( nl >= 0 );
353*a58d3d2aSXin Li 
354*a58d3d2aSXin Li         /* Limit noise levels (guarantee 7 bits of head room) */
355*a58d3d2aSXin Li         nl = silk_min( nl, 0x00FFFFFF );
356*a58d3d2aSXin Li 
357*a58d3d2aSXin Li         /* Store as part of state */
358*a58d3d2aSXin Li         psSilk_VAD->NL[ k ] = nl;
359*a58d3d2aSXin Li     }
360*a58d3d2aSXin Li }
361