2d140b24da55ebd8fc4ed84be0b717e6c309d5ca
[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_Q30;
176     opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
177     opus_int32 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, sizeof( psPLC->prevLPC_Q12 ) );
189     }
190
191     /* Find random noise component */
192     /* Scale previous excitation signal */
193     exc_buf_ptr = exc_buf;
194     for( k = 0; k < 2; k++ ) {
195         for( i = 0; i < psPLC->subfr_length; i++ ) {
196             exc_buf_ptr[ i ] = (opus_int16)silk_RSHIFT(
197                 silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], psPLC->prevGain_Q16[ k ] ), 14 );
198         }
199         exc_buf_ptr += psPLC->subfr_length;
200     }
201     /* Find the subframe with lowest energy of the last two and use that as random noise generator */
202     silk_sum_sqr_shift( &energy1, &shift1, exc_buf,                         psPLC->subfr_length );
203     silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length );
204
205     if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
206         /* First sub-frame has lowest energy */
207         rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
208     } else {
209         /* Second sub-frame has lowest energy */
210         rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
211     }
212
213     /* Set up Gain to random noise component */
214     B_Q14          = psPLC->LTPCoef_Q14;
215     rand_scale_Q14 = psPLC->randScale_Q14;
216
217     /* Set up attenuation gains */
218     harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
219     if( psDec->prevSignalType == TYPE_VOICED ) {
220         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
221     } else {
222         rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
223     }
224
225     /* LPC concealment. Apply BWE to previous LPC */
226     silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
227
228     /* Preload LPC coeficients to array on stack. Gives small performance gain */
229     silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
230
231     /* First Lost frame */
232     if( psDec->lossCnt == 0 ) {
233         rand_scale_Q14 = 1 << 14;
234
235         /* Reduce random noise Gain for voiced frames */
236         if( psDec->prevSignalType == TYPE_VOICED ) {
237             for( i = 0; i < LTP_ORDER; i++ ) {
238                 rand_scale_Q14 -= B_Q14[ i ];
239             }
240             rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
241             rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
242         } else {
243             /* Reduce random noise for unvoiced frames with high LPC gain */
244             opus_int32 invGain_Q30, down_scale_Q30;
245
246             invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
247
248             down_scale_Q30 = silk_min_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
249             down_scale_Q30 = silk_max_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
250             down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
251
252             rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
253         }
254     }
255
256     rand_seed    = psPLC->rand_seed;
257     lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
258     sLTP_buf_idx = psDec->ltp_mem_length;
259
260     /* Rewhiten LTP state */
261     idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
262     silk_assert( idx > 0 );
263     silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order );
264     /* Scale LTP state */
265     inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
266     inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
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         /* Set up 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             /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
280             LTP_pred_Q12 = 2;
281             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
282             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
283             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
284             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
285             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
286             pred_lag_ptr++;
287
288             /* Generate LPC excitation */
289             rand_seed = silk_RAND( rand_seed );
290             idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
291             sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
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         /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
320         LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
321         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
322         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
323         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
324         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
325         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
326         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
327         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
328         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
329         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
330         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
331         for( j = 10; j < psDec->LPC_order; j++ ) {
332             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
333         }
334
335         /* Add prediction to LPC excitation */
336         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
337
338         /* Scale with Gain */
339         frame[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], psPLC->prevGain_Q16[ 1 ] ), 14 ) );
340     }
341
342     /* Save LPC state */
343     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
344
345     /**************************************/
346     /* Update states                      */
347     /**************************************/
348     psPLC->rand_seed     = rand_seed;
349     psPLC->randScale_Q14 = rand_scale_Q14;
350     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
351         psDecCtrl->pitchL[ i ] = lag;
352     }
353 }
354
355 /* Glues concealed frames with new good recieved frames */
356 void silk_PLC_glue_frames(
357     silk_decoder_state                  *psDec,             /* I/O decoder state        */
358     opus_int16                          frame[],            /* I/O signal               */
359     opus_int                            length              /* I length of signal       */
360 )
361 {
362     opus_int   i, energy_shift;
363     opus_int32 energy;
364     silk_PLC_struct *psPLC;
365     psPLC = &psDec->sPLC;
366
367     if( psDec->lossCnt ) {
368         /* Calculate energy in concealed residual */
369         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
370
371         psPLC->last_frame_lost = 1;
372     } else {
373         if( psDec->sPLC.last_frame_lost ) {
374             /* Calculate residual in decoded signal if last frame was lost */
375             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
376
377             /* Normalize energies */
378             if( energy_shift > psPLC->conc_energy_shift ) {
379                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
380             } else if( energy_shift < psPLC->conc_energy_shift ) {
381                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
382             }
383
384             /* Fade in the energy difference */
385             if( energy > psPLC->conc_energy ) {
386                 opus_int32 frac_Q24, LZ;
387                 opus_int32 gain_Q16, slope_Q16;
388
389                 LZ = silk_CLZ32( psPLC->conc_energy );
390                 LZ = LZ - 1;
391                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
392                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
393
394                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
395
396                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
397                 slope_Q16 = silk_DIV32_16( ( 1 << 16 ) - gain_Q16, length );
398                 /* Make slope 4x steeper to avoid missing onsets after DTX */
399                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
400
401                 for( i = 0; i < length; i++ ) {
402                     frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
403                     gain_Q16 += slope_Q16;
404                     if( gain_Q16 > 1 << 16 ) {
405                         break;
406                     }
407                 }
408             }
409         }
410         psPLC->last_frame_lost = 0;
411     }
412 }