Home | History | Annotate | Download | only in silk
      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 }
    447