Some minor (non-bitstream-affecting) changes to help us have better test vectors
[opus.git] / silk / PLC.c
1 /***********************************************************************
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, (subject to the limitations in the disclaimer below)
5 are permitted provided that the following conditions are met:
6 - Redistributions of source code must retain the above copyright notice,
7 this list of conditions and the following disclaimer.
8 - Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 - Neither the name of Skype Limited, nor the names of specific
12 contributors, may be used to endorse or promote products derived from
13 this software without specific prior written permission.
14 NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
15 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
16 CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
17 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 ***********************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "main.h"
33 #include "PLC.h"
34
35 #define NB_ATT 2
36 static const opus_int16 HARM_ATT_Q15[NB_ATT]              = { 32440, 31130 }; /* 0.99, 0.95 */
37 static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT]  = { 31130, 26214 }; /* 0.95, 0.8 */
38 static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
39
40 static inline void silk_PLC_update(
41     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
42     silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
43 );
44
45 static inline void silk_PLC_conceal(
46     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
47     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
48     opus_int16                          signal[]            /* O LPC residual signal    */
49 );
50
51
52 void silk_PLC_Reset(
53     silk_decoder_state                  *psDec              /* I/O Decoder state        */
54 )
55 {
56     psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
57     psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
58     psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
59     psDec->sPLC.subfr_length = 20;
60     psDec->sPLC.nb_subfr = 2;
61 }
62
63 void silk_PLC(
64     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
65     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
66     opus_int16                          frame[],            /* I/O  signal              */
67     opus_int                            lost                /* I Loss flag              */
68 )
69 {
70     /* PLC control function */
71     if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
72         silk_PLC_Reset( psDec );
73         psDec->sPLC.fs_kHz = psDec->fs_kHz;
74     }
75
76     if( lost ) {
77         /****************************/
78         /* Generate Signal          */
79         /****************************/
80         silk_PLC_conceal( psDec, psDecCtrl, frame );
81
82         psDec->lossCnt++;
83     } else {
84         /****************************/
85         /* Update state             */
86         /****************************/
87         silk_PLC_update( psDec, psDecCtrl );
88     }
89 }
90
91 /**************************************************/
92 /* Update state of PLC                            */
93 /**************************************************/
94 static inline void silk_PLC_update(
95     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
96     silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
97 )
98 {
99     opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
100     opus_int   i, j;
101     silk_PLC_struct *psPLC;
102
103     psPLC = &psDec->sPLC;
104
105     /* Update parameters used in case of packet loss */
106     psDec->prevSignalType = psDec->indices.signalType;
107     LTP_Gain_Q14 = 0;
108     if( psDec->indices.signalType == TYPE_VOICED ) {
109         /* Find the parameters for the last subframe which contains a pitch pulse */
110         for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
111             if( j == psDec->nb_subfr ) {
112                 break;
113             }
114             temp_LTP_Gain_Q14 = 0;
115             for( i = 0; i < LTP_ORDER; i++ ) {
116                 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
117             }
118             if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
119                 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
120                 silk_memcpy( psPLC->LTPCoef_Q14,
121                     &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
122                     LTP_ORDER * sizeof( opus_int16 ) );
123
124                 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
125             }
126         }
127
128         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
129         psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
130
131         /* Limit LT coefs */
132         if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
133             opus_int   scale_Q10;
134             opus_int32 tmp;
135
136             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
137             scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
138             for( i = 0; i < LTP_ORDER; i++ ) {
139                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
140             }
141         } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
142             opus_int   scale_Q14;
143             opus_int32 tmp;
144
145             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
146             scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
147             for( i = 0; i < LTP_ORDER; i++ ) {
148                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
149             }
150         }
151     } else {
152         psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
153         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
154     }
155
156     /* Save LPC coeficients */
157     silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
158     psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
159
160     /* Save last two gains */
161     silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
162
163     psPLC->subfr_length = psDec->subfr_length;
164     psPLC->nb_subfr = psDec->nb_subfr;
165 }
166
167 static inline void silk_PLC_conceal(
168     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
169     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
170     opus_int16                          frame[]             /* O LPC residual signal    */
171 )
172 {
173     opus_int   i, j, k;
174     opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
175     opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q16, inv_gain_Q30;
176     opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
177     opus_int32 LPC_exc_Q14, LPC_pred_Q10, LTP_pred_Q12;
178     opus_int16 rand_scale_Q14;
179     opus_int16 *B_Q14, *exc_buf_ptr;
180     opus_int32 *sLPC_Q14_ptr;
181     opus_int16 exc_buf[ 2 * MAX_SUB_FRAME_LENGTH ];
182     opus_int16 A_Q12[ MAX_LPC_ORDER ];
183     opus_int16 sLTP[ MAX_FRAME_LENGTH ];
184     opus_int32 sLTP_Q14[ 2 * MAX_FRAME_LENGTH ];
185     silk_PLC_struct *psPLC = &psDec->sPLC;
186
187     if (psDec->first_frame_after_reset)
188        silk_memset(psPLC->prevLPC_Q12, 0, MAX_LPC_ORDER*sizeof(psPLC->prevLPC_Q12[ 0 ]));
189
190     /* Find random noise component */
191     /* Scale previous excitation signal */
192     exc_buf_ptr = exc_buf;
193     for( k = 0; k < 2; k++ ) {
194         for( i = 0; i < psPLC->subfr_length; i++ ) {
195             exc_buf_ptr[ i ] = ( opus_int16 )silk_RSHIFT(
196                 silk_SMULWW( psDec->exc_Q10[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 );
197         }
198         exc_buf_ptr += psPLC->subfr_length;
199     }
200     /* Find the subframe with lowest energy of the last two and use that as random noise generator */
201     silk_sum_sqr_shift( &energy1, &shift1, exc_buf,                         psPLC->subfr_length );
202     silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length );
203
204     if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
205         /* First sub-frame has lowest energy */
206         rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
207     } else {
208         /* Second sub-frame has lowest energy */
209         rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
210     }
211
212     /* Setup Gain to random noise component */
213     B_Q14          = psPLC->LTPCoef_Q14;
214     rand_scale_Q14 = psPLC->randScale_Q14;
215
216     /* Setup attenuation gains */
217     harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
218     if( psDec->prevSignalType == TYPE_VOICED ) {
219         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
220     } else {
221         rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
222     }
223
224     /* LPC concealment. Apply BWE to previous LPC */
225     silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
226
227     /* Preload LPC coeficients to array on stack. Gives small performance gain */
228     silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
229
230     /* First Lost frame */
231     if( psDec->lossCnt == 0 ) {
232         rand_scale_Q14 = 1 << 14;
233
234         /* Reduce random noise Gain for voiced frames */
235         if( psDec->prevSignalType == TYPE_VOICED ) {
236             for( i = 0; i < LTP_ORDER; i++ ) {
237                 rand_scale_Q14 -= B_Q14[ i ];
238             }
239             rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
240             rand_scale_Q14 = ( opus_int16 )silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
241         } else {
242             /* Reduce random noise for unvoiced frames with high LPC gain */
243             opus_int32 invGain_Q30, down_scale_Q30;
244
245             silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order );
246
247             down_scale_Q30 = silk_min_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
248             down_scale_Q30 = silk_max_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
249             down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
250
251             rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
252         }
253     }
254
255     rand_seed    = psPLC->rand_seed;
256     lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
257     sLTP_buf_idx = psDec->ltp_mem_length;
258
259     /* Rewhiten LTP state */
260     idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
261     silk_assert( idx > 0 );
262     silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order );
263     /* Scale LTP state */
264     inv_gain_Q16 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 32 );
265     inv_gain_Q16 = silk_min( inv_gain_Q16, silk_int16_MAX );
266     inv_gain_Q30 = silk_LSHIFT( inv_gain_Q16, 14 );
267     for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
268         sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
269     }
270
271     /***************************/
272     /* LTP synthesis filtering */
273     /***************************/
274     for( k = 0; k < psDec->nb_subfr; k++ ) {
275         /* Setup pointer */
276         pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
277         for( i = 0; i < psDec->subfr_length; i++ ) {
278             /* Unrolled loop */
279             LTP_pred_Q12 = silk_SMULWB(               pred_lag_ptr[  0 ], B_Q14[ 0 ] );
280             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
281             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
282             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
283             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
284             pred_lag_ptr++;
285
286             /* Generate LPC excitation */
287             rand_seed = silk_RAND( rand_seed );
288             idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
289             LPC_exc_Q14 = silk_LSHIFT32( silk_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 6 ); /* Random noise part */
290             LPC_exc_Q14 = silk_ADD32( LPC_exc_Q14, silk_LSHIFT32( LTP_pred_Q12, 2 ) );        /* Harmonic part */
291             sLTP_Q14[ sLTP_buf_idx ] = LPC_exc_Q14;
292             sLTP_buf_idx++;
293         }
294
295         /* Gradually reduce LTP gain */
296         for( j = 0; j < LTP_ORDER; j++ ) {
297             B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
298         }
299         /* Gradually reduce excitation gain */
300         rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
301
302         /* Slowly increase pitch lag */
303         psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
304         psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
305         lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
306     }
307
308     /***************************/
309     /* LPC synthesis filtering */
310     /***************************/
311     sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
312
313     /* Copy LPC state */
314     silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
315
316     silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
317     for( i = 0; i < psDec->frame_length; i++ ) {
318         /* partly unrolled */
319         LPC_pred_Q10 = silk_SMULWB(               sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
320         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
321         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
322         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
323         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
324         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
325         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
326         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
327         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
328         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
329         for( j = 10; j < psDec->LPC_order; j++ ) {
330             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
331         }
332
333         /* Add prediction to LPC excitation */
334         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
335
336         /* Scale with Gain */
337         frame[ i ] = ( opus_int16 )silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], psPLC->prevGain_Q16[ 1 ] ), 14 ) );
338     }
339
340     /* Save LPC state */
341     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
342
343     /**************************************/
344     /* Update states                      */
345     /**************************************/
346     psPLC->rand_seed     = rand_seed;
347     psPLC->randScale_Q14 = rand_scale_Q14;
348     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
349         psDecCtrl->pitchL[ i ] = lag;
350     }
351 }
352
353 /* Glues concealed frames with new good recieved frames */
354 void silk_PLC_glue_frames(
355     silk_decoder_state                  *psDec,             /* I/O decoder state        */
356     opus_int16                          frame[],            /* I/O signal               */
357     opus_int                            length              /* I length of signal       */
358 )
359 {
360     opus_int   i, energy_shift;
361     opus_int32 energy;
362     silk_PLC_struct *psPLC;
363     psPLC = &psDec->sPLC;
364
365     if( psDec->lossCnt ) {
366         /* Calculate energy in concealed residual */
367         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
368
369         psPLC->last_frame_lost = 1;
370     } else {
371         if( psDec->sPLC.last_frame_lost ) {
372             /* Calculate residual in decoded signal if last frame was lost */
373             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
374
375             /* Normalize energies */
376             if( energy_shift > psPLC->conc_energy_shift ) {
377                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
378             } else if( energy_shift < psPLC->conc_energy_shift ) {
379                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
380             }
381
382             /* Fade in the energy difference */
383             if( energy > psPLC->conc_energy ) {
384                 opus_int32 frac_Q24, LZ;
385                 opus_int32 gain_Q16, slope_Q16;
386
387                 LZ = silk_CLZ32( psPLC->conc_energy );
388                 LZ = LZ - 1;
389                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
390                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
391
392                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
393
394                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
395                 slope_Q16 = silk_DIV32_16( ( 1 << 16 ) - gain_Q16, length );
396                 /* Make slope 4x steeper to avoid missing onsets after DTX */
397                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
398
399                 for( i = 0; i < length; i++ ) {
400                     frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
401                     gain_Q16 += slope_Q16;
402                     if( gain_Q16 > 1 << 16 ) {
403                         break;
404                     }
405                 }
406             }
407         }
408         psPLC->last_frame_lost = 0;
409     }
410 }