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