Optimization of the CBR loop
[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_RSHIFT( psDec->frame_length, 1 );
57 }
58
59 void silk_PLC(
60     silk_decoder_state          *psDec,             /* I Decoder state          */
61     silk_decoder_control        *psDecCtrl,         /* I Decoder control        */
62     opus_int16                   frame[],            /* O Concealed signal       */
63     opus_int                     lost                /* I Loss flag              */
64 )
65 {
66     /* PLC control function */
67     if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
68         silk_PLC_Reset( psDec );
69         psDec->sPLC.fs_kHz = psDec->fs_kHz;
70     }
71
72     if( lost ) {
73         /****************************/
74         /* Generate Signal          */
75         /****************************/
76         silk_PLC_conceal( psDec, psDecCtrl, frame );
77
78         psDec->lossCnt++;
79     } else {
80         /****************************/
81         /* Update state             */
82         /****************************/
83         silk_PLC_update( psDec, psDecCtrl );
84     }
85 }
86
87 /**************************************************/
88 /* Update state of PLC                            */
89 /**************************************************/
90 static inline void silk_PLC_update(
91     silk_decoder_state          *psDec,             /* (I/O) Decoder state          */
92     silk_decoder_control        *psDecCtrl          /* (I/O) Decoder control        */
93 )
94 {
95     opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
96     opus_int   i, j;
97     silk_PLC_struct *psPLC;
98
99     psPLC = &psDec->sPLC;
100
101     /* Update parameters used in case of packet loss */
102     psDec->prevSignalType = psDec->indices.signalType;
103     LTP_Gain_Q14 = 0;
104     if( psDec->indices.signalType == TYPE_VOICED ) {
105         /* Find the parameters for the last subframe which contains a pitch pulse */
106         for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
107             if( j == psDec->nb_subfr ){
108                 break;
109             }
110             temp_LTP_Gain_Q14 = 0;
111             for( i = 0; i < LTP_ORDER; i++ ) {
112                 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
113             }
114             if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
115                 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
116                 silk_memcpy( psPLC->LTPCoef_Q14,
117                     &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
118                     LTP_ORDER * sizeof( opus_int16 ) );
119
120                 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
121             }
122         }
123
124 #if USE_SINGLE_TAP
125         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
126         psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
127 #endif
128
129         /* Limit LT coefs */
130         if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
131             opus_int   scale_Q10;
132             opus_int32 tmp;
133
134             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
135             scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
136             for( i = 0; i < LTP_ORDER; i++ ) {
137                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
138             }
139         } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
140             opus_int   scale_Q14;
141             opus_int32 tmp;
142
143             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
144             scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
145             for( i = 0; i < LTP_ORDER; i++ ) {
146                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
147             }
148         }
149     } else {
150         psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
151         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
152     }
153
154     /* Save LPC coeficients */
155     silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
156     psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
157
158     /* Save Gains */
159     silk_memcpy( psPLC->prevGain_Q16, psDecCtrl->Gains_Q16, psDec->nb_subfr * sizeof( opus_int32 ) );
160 }
161
162 static inline void silk_PLC_conceal(
163     silk_decoder_state          *psDec,             /* I/O Decoder state */
164     silk_decoder_control        *psDecCtrl,         /* I/O Decoder control */
165     opus_int16                   frame[]            /* O concealed signal */
166 )
167 {
168     opus_int   i, j, k;
169     opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
170     opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q16, inv_gain_Q30;
171     opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
172     opus_int32 LPC_exc_Q14, LPC_pred_Q10, LTP_pred_Q12;
173     opus_int16 rand_scale_Q14;
174     opus_int16 *B_Q14, *exc_buf_ptr;
175     opus_int32 *sLPC_Q14_ptr;
176     opus_int16 exc_buf[ 2 * MAX_SUB_FRAME_LENGTH ];
177     opus_int16 A_Q12[ MAX_LPC_ORDER ];
178     opus_int16 sLTP[ MAX_FRAME_LENGTH ];
179     opus_int32 sLTP_Q14[ 2 * MAX_FRAME_LENGTH ];
180     silk_PLC_struct *psPLC = &psDec->sPLC;
181
182     /* Find random noise component */
183     /* Scale previous excitation signal */
184     exc_buf_ptr = exc_buf;
185     for( k = psDec->nb_subfr - 2; k < psDec->nb_subfr; k++ ) {
186         for( i = 0; i < psDec->subfr_length; i++ ) {
187             exc_buf_ptr[ i ] = ( opus_int16 )silk_RSHIFT(
188                 silk_SMULWW( psDec->exc_Q10[ i + k * psDec->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 );
189         }
190         exc_buf_ptr += psDec->subfr_length;
191     }
192     /* Find the subframe with lowest energy of the last two and use that as random noise generator */
193     silk_sum_sqr_shift( &energy1, &shift1, exc_buf,                         psDec->subfr_length );
194     silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psDec->subfr_length ], psDec->subfr_length );
195
196     if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
197         /* First sub-frame has lowest energy */
198         rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, psDec->frame_length - psDec->subfr_length - RAND_BUF_SIZE ) ];
199     } else {
200         /* Second sub-frame has lowest energy */
201         rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, psDec->frame_length - RAND_BUF_SIZE ) ];
202     }
203
204     /* Setup Gain to random noise component */
205     B_Q14          = psPLC->LTPCoef_Q14;
206     rand_scale_Q14 = psPLC->randScale_Q14;
207
208     /* Setup attenuation gains */
209     harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
210     if( psDec->prevSignalType == TYPE_VOICED ) {
211         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
212     } else {
213         rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
214     }
215
216     /* LPC concealment. Apply BWE to previous LPC */
217     silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
218
219     /* Preload LPC coeficients to array on stack. Gives small performance gain */
220     silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
221
222     /* First Lost frame */
223     if( psDec->lossCnt == 0 ) {
224         rand_scale_Q14 = 1 << 14;
225
226         /* Reduce random noise Gain for voiced frames */
227         if( psDec->prevSignalType == TYPE_VOICED ) {
228             for( i = 0; i < LTP_ORDER; i++ ) {
229                 rand_scale_Q14 -= B_Q14[ i ];
230             }
231             rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
232             rand_scale_Q14 = ( opus_int16 )silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
233         } else {
234             /* Reduce random noise for unvoiced frames with high LPC gain */
235             opus_int32 invGain_Q30, down_scale_Q30;
236
237             silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order );
238
239             down_scale_Q30 = silk_min_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
240             down_scale_Q30 = silk_max_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
241             down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
242
243             rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
244         }
245     }
246
247     rand_seed    = psPLC->rand_seed;
248     lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
249     sLTP_buf_idx = psDec->ltp_mem_length;
250
251     /* Rewhiten LTP state */
252     idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
253     silk_assert( idx > 0 );
254     silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order );
255     /* Scale LTP state */
256     inv_gain_Q16 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ psDec->nb_subfr - 1 ], 32 );
257     inv_gain_Q16 = silk_min( inv_gain_Q16, silk_int16_MAX );
258     inv_gain_Q30 = silk_LSHIFT( inv_gain_Q16, 14 );
259     for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
260         sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
261     }
262
263     /***************************/
264     /* LTP synthesis filtering */
265     /***************************/
266     for( k = 0; k < psDec->nb_subfr; k++ ) {
267         /* Setup pointer */
268         pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
269         for( i = 0; i < psDec->subfr_length; i++ ) {
270             /* Unrolled loop */
271             LTP_pred_Q12 = silk_SMULWB(               pred_lag_ptr[  0 ], B_Q14[ 0 ] );
272             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
273             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
274             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
275             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
276             pred_lag_ptr++;
277
278             /* Generate LPC excitation */
279             rand_seed = silk_RAND( rand_seed );
280             idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
281             LPC_exc_Q14 = silk_LSHIFT32( silk_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 6 ); /* Random noise part */
282             LPC_exc_Q14 = silk_ADD32( LPC_exc_Q14, silk_LSHIFT32( LTP_pred_Q12, 2 ) );        /* Harmonic part */
283             sLTP_Q14[ sLTP_buf_idx ] = LPC_exc_Q14;
284             sLTP_buf_idx++;
285         }
286
287         /* Gradually reduce LTP gain */
288         for( j = 0; j < LTP_ORDER; j++ ) {
289             B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
290         }
291         /* Gradually reduce excitation gain */
292         rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
293
294         /* Slowly increase pitch lag */
295         psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
296         psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
297         lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
298     }
299
300     /***************************/
301     /* LPC synthesis filtering */
302     /***************************/
303     sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
304
305     /* Copy LPC state */
306     silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
307
308     silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
309     for( i = 0; i < psDec->frame_length; i++ ) {
310         /* partly unrolled */
311         LPC_pred_Q10 = silk_SMULWB(               sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
312         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
313         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
314         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
315         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
316         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
317         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
318         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
319         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
320         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
321         for( j = 10; j < psDec->LPC_order; j++ ) {
322             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
323         }
324
325         /* Add prediction to LPC excitation */
326         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
327
328         /* Scale with Gain */
329         frame[ i ] = ( opus_int16 )silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], psPLC->prevGain_Q16[ psDec->nb_subfr - 1 ] ), 14 ) );
330     }
331
332     /* Save LPC state */
333     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
334
335     /**************************************/
336     /* Update states                      */
337     /**************************************/
338     psPLC->rand_seed     = rand_seed;
339     psPLC->randScale_Q14 = rand_scale_Q14;
340     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
341         psDecCtrl->pitchL[ i ] = lag;
342     }
343 }
344
345 /* Glues concealed frames with new good recieved frames             */
346 void silk_PLC_glue_frames(
347     silk_decoder_state          *psDec,             /* I/O decoder state    */
348     opus_int16                   frame[],            /* I/O signal           */
349     opus_int                     length              /* I length of residual */
350 )
351 {
352     opus_int   i, energy_shift;
353     opus_int32 energy;
354     silk_PLC_struct *psPLC;
355     psPLC = &psDec->sPLC;
356
357     if( psDec->lossCnt ) {
358         /* Calculate energy in concealed residual */
359         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
360
361         psPLC->last_frame_lost = 1;
362     } else {
363         if( psDec->sPLC.last_frame_lost ) {
364             /* Calculate residual in decoded signal if last frame was lost */
365             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
366
367             /* Normalize energies */
368             if( energy_shift > psPLC->conc_energy_shift ) {
369                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
370             } else if( energy_shift < psPLC->conc_energy_shift ) {
371                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
372             }
373
374             /* Fade in the energy difference */
375             if( energy > psPLC->conc_energy ) {
376                 opus_int32 frac_Q24, LZ;
377                 opus_int32 gain_Q16, slope_Q16;
378
379                 LZ = silk_CLZ32( psPLC->conc_energy );
380                 LZ = LZ - 1;
381                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
382                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
383
384                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
385
386                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
387                 slope_Q16 = silk_DIV32_16( ( 1 << 16 ) - gain_Q16, length );
388                 /* Make slope 4x steeper to avoid missing onsets after DTX */
389                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
390
391                 for( i = 0; i < length; i++ ) {
392                     frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
393                     gain_Q16 += slope_Q16;
394                     if( gain_Q16 > 1 << 16 ) {
395                         break;
396                     }
397                 }
398             }
399         }
400         psPLC->last_frame_lost = 0;
401     }
402 }