Better rate allocation for stereo SILK in hybrid mode
[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, arch );
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         if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) {
332             /* Gradually reduce excitation gain */
333             rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
334         }
335
336         /* Slowly increase pitch lag */
337         psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
338         psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
339         lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
340     }
341
342     /***************************/
343     /* LPC synthesis filtering */
344     /***************************/
345     sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
346
347     /* Copy LPC state */
348     silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
349
350     silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
351     for( i = 0; i < psDec->frame_length; i++ ) {
352         /* partly unrolled */
353         /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
354         LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
355         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
356         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
357         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
358         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
359         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
360         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
361         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
362         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
363         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
364         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
365         for( j = 10; j < psDec->LPC_order; j++ ) {
366             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
367         }
368
369         /* Add prediction to LPC excitation */
370         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
371                                             silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
372
373         /* Scale with Gain */
374         frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
375     }
376
377     /* Save LPC state */
378     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
379
380     /**************************************/
381     /* Update states                      */
382     /**************************************/
383     psPLC->rand_seed     = rand_seed;
384     psPLC->randScale_Q14 = rand_scale_Q14;
385     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
386         psDecCtrl->pitchL[ i ] = lag;
387     }
388     RESTORE_STACK;
389 }
390
391 /* Glues concealed frames with new good received frames */
392 void silk_PLC_glue_frames(
393     silk_decoder_state                  *psDec,             /* I/O decoder state        */
394     opus_int16                          frame[],            /* I/O signal               */
395     opus_int                            length              /* I length of signal       */
396 )
397 {
398     opus_int   i, energy_shift;
399     opus_int32 energy;
400     silk_PLC_struct *psPLC;
401     psPLC = &psDec->sPLC;
402
403     if( psDec->lossCnt ) {
404         /* Calculate energy in concealed residual */
405         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
406
407         psPLC->last_frame_lost = 1;
408     } else {
409         if( psDec->sPLC.last_frame_lost ) {
410             /* Calculate residual in decoded signal if last frame was lost */
411             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
412
413             /* Normalize energies */
414             if( energy_shift > psPLC->conc_energy_shift ) {
415                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
416             } else if( energy_shift < psPLC->conc_energy_shift ) {
417                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
418             }
419
420             /* Fade in the energy difference */
421             if( energy > psPLC->conc_energy ) {
422                 opus_int32 frac_Q24, LZ;
423                 opus_int32 gain_Q16, slope_Q16;
424
425                 LZ = silk_CLZ32( psPLC->conc_energy );
426                 LZ = LZ - 1;
427                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
428                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
429
430                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
431
432                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
433                 slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
434                 /* Make slope 4x steeper to avoid missing onsets after DTX */
435                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
436
437                 for( i = 0; i < length; i++ ) {
438                     frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
439                     gain_Q16 += slope_Q16;
440                     if( gain_Q16 > (opus_int32)1 << 16 ) {
441                         break;
442                     }
443                 }
444             }
445         }
446         psPLC->last_frame_lost = 0;
447     }
448 }