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