tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PLC.c (21986B)


      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 
     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 
     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 /**************************************************/
    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 coefficients */
    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 
    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 
    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 coefficients 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 */
    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 }