xref: /aosp_15_r20/external/libopus/silk/PLC.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
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 #ifdef ENABLE_DEEP_PLC
37 #include "lpcnet.h"
38 #endif
39 
40 #define NB_ATT 2
41 static const opus_int16 HARM_ATT_Q15[NB_ATT]              = { 32440, 31130 }; /* 0.99, 0.95 */
42 static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT]  = { 31130, 26214 }; /* 0.95, 0.8 */
43 static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
44 
45 static OPUS_INLINE void silk_PLC_update(
46     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
47     silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
48 );
49 
50 static OPUS_INLINE void silk_PLC_conceal(
51     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
52     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
53     opus_int16                          frame[],            /* O LPC residual signal    */
54 #ifdef ENABLE_DEEP_PLC
55     LPCNetPLCState                      *lpcnet,
56 #endif
57     int                                 arch                /* I  Run-time architecture */
58 );
59 
60 
silk_PLC_Reset(silk_decoder_state * psDec)61 void silk_PLC_Reset(
62     silk_decoder_state                  *psDec              /* I/O Decoder state        */
63 )
64 {
65     psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
66     psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
67     psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
68     psDec->sPLC.subfr_length = 20;
69     psDec->sPLC.nb_subfr = 2;
70 }
71 
silk_PLC(silk_decoder_state * psDec,silk_decoder_control * psDecCtrl,opus_int16 frame[],opus_int lost,LPCNetPLCState * lpcnet,int arch)72 void silk_PLC(
73     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
74     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
75     opus_int16                          frame[],            /* I/O  signal              */
76     opus_int                            lost,               /* I Loss flag              */
77 #ifdef ENABLE_DEEP_PLC
78     LPCNetPLCState                      *lpcnet,
79 #endif
80     int                                 arch                /* I Run-time architecture  */
81 )
82 {
83     /* PLC control function */
84     if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
85         silk_PLC_Reset( psDec );
86         psDec->sPLC.fs_kHz = psDec->fs_kHz;
87     }
88 
89     if( lost ) {
90         /****************************/
91         /* Generate Signal          */
92         /****************************/
93         silk_PLC_conceal( psDec, psDecCtrl, frame,
94 #ifdef ENABLE_DEEP_PLC
95             lpcnet,
96 #endif
97             arch );
98 
99         psDec->lossCnt++;
100     } else {
101         /****************************/
102         /* Update state             */
103         /****************************/
104         silk_PLC_update( psDec, psDecCtrl );
105 #ifdef ENABLE_DEEP_PLC
106         if ( lpcnet != NULL && psDec->sPLC.fs_kHz == 16 ) {
107             int k;
108             for( k = 0; k < psDec->nb_subfr; k += 2 ) {
109                 lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length );
110             }
111         }
112 #endif
113     }
114 }
115 
116 /**************************************************/
117 /* Update state of PLC                            */
118 /**************************************************/
silk_PLC_update(silk_decoder_state * psDec,silk_decoder_control * psDecCtrl)119 static OPUS_INLINE void silk_PLC_update(
120     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
121     silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
122 )
123 {
124     opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
125     opus_int   i, j;
126     silk_PLC_struct *psPLC;
127 
128     psPLC = &psDec->sPLC;
129 
130     /* Update parameters used in case of packet loss */
131     psDec->prevSignalType = psDec->indices.signalType;
132     LTP_Gain_Q14 = 0;
133     if( psDec->indices.signalType == TYPE_VOICED ) {
134         /* Find the parameters for the last subframe which contains a pitch pulse */
135         for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
136             if( j == psDec->nb_subfr ) {
137                 break;
138             }
139             temp_LTP_Gain_Q14 = 0;
140             for( i = 0; i < LTP_ORDER; i++ ) {
141                 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
142             }
143             if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
144                 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
145                 silk_memcpy( psPLC->LTPCoef_Q14,
146                     &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
147                     LTP_ORDER * sizeof( opus_int16 ) );
148 
149                 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
150             }
151         }
152 
153         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
154         psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
155 
156         /* Limit LT coefs */
157         if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
158             opus_int   scale_Q10;
159             opus_int32 tmp;
160 
161             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
162             scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
163             for( i = 0; i < LTP_ORDER; i++ ) {
164                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
165             }
166         } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
167             opus_int   scale_Q14;
168             opus_int32 tmp;
169 
170             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
171             scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
172             for( i = 0; i < LTP_ORDER; i++ ) {
173                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
174             }
175         }
176     } else {
177         psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
178         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
179     }
180 
181     /* Save LPC coeficients */
182     silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
183     psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
184 
185     /* Save last two gains */
186     silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
187 
188     psPLC->subfr_length = psDec->subfr_length;
189     psPLC->nb_subfr = psDec->nb_subfr;
190 }
191 
silk_PLC_energy(opus_int32 * energy1,opus_int * shift1,opus_int32 * energy2,opus_int * shift2,const opus_int32 * exc_Q14,const opus_int32 * prevGain_Q10,int subfr_length,int nb_subfr)192 static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2,
193       const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr)
194 {
195     int i, k;
196     VARDECL( opus_int16, exc_buf );
197     opus_int16 *exc_buf_ptr;
198     SAVE_STACK;
199     ALLOC( exc_buf, 2*subfr_length, opus_int16 );
200     /* Find random noise component */
201     /* Scale previous excitation signal */
202     exc_buf_ptr = exc_buf;
203     for( k = 0; k < 2; k++ ) {
204         for( i = 0; i < subfr_length; i++ ) {
205             exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
206                 silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
207         }
208         exc_buf_ptr += subfr_length;
209     }
210     /* Find the subframe with lowest energy of the last two and use that as random noise generator */
211     silk_sum_sqr_shift( energy1, shift1, exc_buf,                  subfr_length );
212     silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
213     RESTORE_STACK;
214 }
215 
silk_PLC_conceal(silk_decoder_state * psDec,silk_decoder_control * psDecCtrl,opus_int16 frame[],LPCNetPLCState * lpcnet,int arch)216 static OPUS_INLINE void silk_PLC_conceal(
217     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
218     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
219     opus_int16                          frame[],            /* O LPC residual signal    */
220 #ifdef ENABLE_DEEP_PLC
221     LPCNetPLCState                      *lpcnet,
222 #endif
223     int                                 arch                /* I Run-time architecture  */
224 )
225 {
226     opus_int   i, j, k;
227     opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
228     opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
229     opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
230     opus_int32 LPC_pred_Q10, LTP_pred_Q12;
231     opus_int16 rand_scale_Q14;
232     opus_int16 *B_Q14;
233     opus_int32 *sLPC_Q14_ptr;
234     opus_int16 A_Q12[ MAX_LPC_ORDER ];
235 #ifdef SMALL_FOOTPRINT
236     opus_int16 *sLTP;
237 #else
238     VARDECL( opus_int16, sLTP );
239 #endif
240     VARDECL( opus_int32, sLTP_Q14 );
241     silk_PLC_struct *psPLC = &psDec->sPLC;
242     opus_int32 prevGain_Q10[2];
243     SAVE_STACK;
244 
245     ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
246 #ifdef SMALL_FOOTPRINT
247     /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */
248     sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length;
249 #else
250     ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
251 #endif
252 
253     prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
254     prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
255 
256     if( psDec->first_frame_after_reset ) {
257        silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
258     }
259 
260     silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
261 
262     if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
263         /* First sub-frame has lowest energy */
264         rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
265     } else {
266         /* Second sub-frame has lowest energy */
267         rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
268     }
269 
270     /* Set up Gain to random noise component */
271     B_Q14          = psPLC->LTPCoef_Q14;
272     rand_scale_Q14 = psPLC->randScale_Q14;
273 
274     /* Set up attenuation gains */
275     harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
276     if( psDec->prevSignalType == TYPE_VOICED ) {
277         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
278     } else {
279         rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
280     }
281 
282     /* LPC concealment. Apply BWE to previous LPC */
283     silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
284 
285     /* Preload LPC coeficients to array on stack. Gives small performance gain */
286     silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
287 
288     /* First Lost frame */
289     if( psDec->lossCnt == 0 ) {
290         rand_scale_Q14 = 1 << 14;
291 
292         /* Reduce random noise Gain for voiced frames */
293         if( psDec->prevSignalType == TYPE_VOICED ) {
294             for( i = 0; i < LTP_ORDER; i++ ) {
295                 rand_scale_Q14 -= B_Q14[ i ];
296             }
297             rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
298             rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
299         } else {
300             /* Reduce random noise for unvoiced frames with high LPC gain */
301             opus_int32 invGain_Q30, down_scale_Q30;
302 
303             invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch );
304 
305             down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
306             down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
307             down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
308 
309             rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
310         }
311     }
312 
313     rand_seed    = psPLC->rand_seed;
314     lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
315     sLTP_buf_idx = psDec->ltp_mem_length;
316 
317     /* Rewhiten LTP state */
318     idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
319     celt_assert( idx > 0 );
320     silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
321     /* Scale LTP state */
322     inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
323     inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
324     for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
325         sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
326     }
327 
328     /***************************/
329     /* LTP synthesis filtering */
330     /***************************/
331     for( k = 0; k < psDec->nb_subfr; k++ ) {
332         /* Set up pointer */
333         pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
334         for( i = 0; i < psDec->subfr_length; i++ ) {
335             /* Unrolled loop */
336             /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
337             LTP_pred_Q12 = 2;
338             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
339             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
340             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
341             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
342             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
343             pred_lag_ptr++;
344 
345             /* Generate LPC excitation */
346             rand_seed = silk_RAND( rand_seed );
347             idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
348             sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
349             sLTP_buf_idx++;
350         }
351 
352         /* Gradually reduce LTP gain */
353         for( j = 0; j < LTP_ORDER; j++ ) {
354             B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
355         }
356         /* Gradually reduce excitation gain */
357         rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
358 
359         /* Slowly increase pitch lag */
360         psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
361         psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
362         lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
363     }
364 
365     /***************************/
366     /* LPC synthesis filtering */
367     /***************************/
368     sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
369 
370     /* Copy LPC state */
371     silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
372 
373     celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
374     for( i = 0; i < psDec->frame_length; i++ ) {
375         /* partly unrolled */
376         /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
377         LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
378         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
379         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
380         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
381         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
382         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
383         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
384         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
385         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
386         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
387         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
388         for( j = 10; j < psDec->LPC_order; j++ ) {
389             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
390         }
391 
392         /* Add prediction to LPC excitation */
393         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
394                                             silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
395 
396         /* Scale with Gain */
397         frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
398     }
399 #ifdef ENABLE_DEEP_PLC
400     if ( lpcnet != NULL && lpcnet->loaded && psDec->sPLC.fs_kHz == 16 ) {
401         int run_deep_plc = psDec->sPLC.enable_deep_plc || lpcnet->fec_fill_pos != 0;
402         if( run_deep_plc ) {
403             for( k = 0; k < psDec->nb_subfr; k += 2 ) {
404                 lpcnet_plc_conceal( lpcnet, frame + k * psDec->subfr_length );
405             }
406             /* We *should* be able to copy only from psDec->frame_length-MAX_LPC_ORDER, i.e. the last MAX_LPC_ORDER samples. */
407             for( i = 0; i < psDec->frame_length; i++ ) {
408                 sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = (int)floor(.5 + frame[ i ] * (float)(1 << 24) / prevGain_Q10[ 1 ] );
409             }
410         } else {
411           for( k = 0; k < psDec->nb_subfr; k += 2 ) {
412               lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length );
413           }
414         }
415     }
416 #endif
417 
418     /* Save LPC state */
419     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
420 
421     /**************************************/
422     /* Update states                      */
423     /**************************************/
424     psPLC->rand_seed     = rand_seed;
425     psPLC->randScale_Q14 = rand_scale_Q14;
426     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
427         psDecCtrl->pitchL[ i ] = lag;
428     }
429     RESTORE_STACK;
430 }
431 
432 /* Glues concealed frames with new good received frames */
silk_PLC_glue_frames(silk_decoder_state * psDec,opus_int16 frame[],opus_int length)433 void silk_PLC_glue_frames(
434     silk_decoder_state                  *psDec,             /* I/O decoder state        */
435     opus_int16                          frame[],            /* I/O signal               */
436     opus_int                            length              /* I length of signal       */
437 )
438 {
439     opus_int   i, energy_shift;
440     opus_int32 energy;
441     silk_PLC_struct *psPLC;
442     psPLC = &psDec->sPLC;
443 
444     if( psDec->lossCnt ) {
445         /* Calculate energy in concealed residual */
446         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
447 
448         psPLC->last_frame_lost = 1;
449     } else {
450         if( psDec->sPLC.last_frame_lost ) {
451             /* Calculate residual in decoded signal if last frame was lost */
452             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
453 
454             /* Normalize energies */
455             if( energy_shift > psPLC->conc_energy_shift ) {
456                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
457             } else if( energy_shift < psPLC->conc_energy_shift ) {
458                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
459             }
460 
461             /* Fade in the energy difference */
462             if( energy > psPLC->conc_energy ) {
463                 opus_int32 frac_Q24, LZ;
464                 opus_int32 gain_Q16, slope_Q16;
465 
466                 LZ = silk_CLZ32( psPLC->conc_energy );
467                 LZ = LZ - 1;
468                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
469                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
470 
471                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
472 
473                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
474                 slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
475                 /* Make slope 4x steeper to avoid missing onsets after DTX */
476                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
477 #ifdef ENABLE_DEEP_PLC
478                 if ( psDec->sPLC.fs_kHz != 16 )
479 #endif
480                 {
481                     for( i = 0; i < length; i++ ) {
482                         frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
483                         gain_Q16 += slope_Q16;
484                         if( gain_Q16 > (opus_int32)1 << 16 ) {
485                             break;
486                         }
487                     }
488                 }
489             }
490         }
491         psPLC->last_frame_lost = 0;
492     }
493 }
494