1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libopus/silk/PLC.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,423 @@ 1.4 +/*********************************************************************** 1.5 +Copyright (c) 2006-2011, Skype Limited. All rights reserved. 1.6 +Redistribution and use in source and binary forms, with or without 1.7 +modification, are permitted provided that the following conditions 1.8 +are met: 1.9 +- Redistributions of source code must retain the above copyright notice, 1.10 +this list of conditions and the following disclaimer. 1.11 +- Redistributions in binary form must reproduce the above copyright 1.12 +notice, this list of conditions and the following disclaimer in the 1.13 +documentation and/or other materials provided with the distribution. 1.14 +- Neither the name of Internet Society, IETF or IETF Trust, nor the 1.15 +names of specific contributors, may be used to endorse or promote 1.16 +products derived from this software without specific prior written 1.17 +permission. 1.18 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.19 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.20 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.21 +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.22 +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.23 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.24 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.25 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.26 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.27 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.28 +POSSIBILITY OF SUCH DAMAGE. 1.29 +***********************************************************************/ 1.30 + 1.31 +#ifdef HAVE_CONFIG_H 1.32 +#include "config.h" 1.33 +#endif 1.34 + 1.35 +#include "main.h" 1.36 +#include "stack_alloc.h" 1.37 +#include "PLC.h" 1.38 + 1.39 +#define NB_ATT 2 1.40 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ 1.41 +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ 1.42 +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ 1.43 + 1.44 +static OPUS_INLINE void silk_PLC_update( 1.45 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.46 + silk_decoder_control *psDecCtrl /* I/O Decoder control */ 1.47 +); 1.48 + 1.49 +static OPUS_INLINE void silk_PLC_conceal( 1.50 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.51 + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 1.52 + opus_int16 frame[] /* O LPC residual signal */ 1.53 +); 1.54 + 1.55 + 1.56 +void silk_PLC_Reset( 1.57 + silk_decoder_state *psDec /* I/O Decoder state */ 1.58 +) 1.59 +{ 1.60 + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); 1.61 + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); 1.62 + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); 1.63 + psDec->sPLC.subfr_length = 20; 1.64 + psDec->sPLC.nb_subfr = 2; 1.65 +} 1.66 + 1.67 +void silk_PLC( 1.68 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.69 + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 1.70 + opus_int16 frame[], /* I/O signal */ 1.71 + opus_int lost /* I Loss flag */ 1.72 +) 1.73 +{ 1.74 + /* PLC control function */ 1.75 + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { 1.76 + silk_PLC_Reset( psDec ); 1.77 + psDec->sPLC.fs_kHz = psDec->fs_kHz; 1.78 + } 1.79 + 1.80 + if( lost ) { 1.81 + /****************************/ 1.82 + /* Generate Signal */ 1.83 + /****************************/ 1.84 + silk_PLC_conceal( psDec, psDecCtrl, frame ); 1.85 + 1.86 + psDec->lossCnt++; 1.87 + } else { 1.88 + /****************************/ 1.89 + /* Update state */ 1.90 + /****************************/ 1.91 + silk_PLC_update( psDec, psDecCtrl ); 1.92 + } 1.93 +} 1.94 + 1.95 +/**************************************************/ 1.96 +/* Update state of PLC */ 1.97 +/**************************************************/ 1.98 +static OPUS_INLINE void silk_PLC_update( 1.99 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.100 + silk_decoder_control *psDecCtrl /* I/O Decoder control */ 1.101 +) 1.102 +{ 1.103 + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; 1.104 + opus_int i, j; 1.105 + silk_PLC_struct *psPLC; 1.106 + 1.107 + psPLC = &psDec->sPLC; 1.108 + 1.109 + /* Update parameters used in case of packet loss */ 1.110 + psDec->prevSignalType = psDec->indices.signalType; 1.111 + LTP_Gain_Q14 = 0; 1.112 + if( psDec->indices.signalType == TYPE_VOICED ) { 1.113 + /* Find the parameters for the last subframe which contains a pitch pulse */ 1.114 + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { 1.115 + if( j == psDec->nb_subfr ) { 1.116 + break; 1.117 + } 1.118 + temp_LTP_Gain_Q14 = 0; 1.119 + for( i = 0; i < LTP_ORDER; i++ ) { 1.120 + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; 1.121 + } 1.122 + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { 1.123 + LTP_Gain_Q14 = temp_LTP_Gain_Q14; 1.124 + silk_memcpy( psPLC->LTPCoef_Q14, 1.125 + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], 1.126 + LTP_ORDER * sizeof( opus_int16 ) ); 1.127 + 1.128 + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); 1.129 + } 1.130 + } 1.131 + 1.132 + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); 1.133 + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; 1.134 + 1.135 + /* Limit LT coefs */ 1.136 + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { 1.137 + opus_int scale_Q10; 1.138 + opus_int32 tmp; 1.139 + 1.140 + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); 1.141 + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); 1.142 + for( i = 0; i < LTP_ORDER; i++ ) { 1.143 + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); 1.144 + } 1.145 + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { 1.146 + opus_int scale_Q14; 1.147 + opus_int32 tmp; 1.148 + 1.149 + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); 1.150 + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); 1.151 + for( i = 0; i < LTP_ORDER; i++ ) { 1.152 + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); 1.153 + } 1.154 + } 1.155 + } else { 1.156 + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); 1.157 + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); 1.158 + } 1.159 + 1.160 + /* Save LPC coeficients */ 1.161 + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); 1.162 + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; 1.163 + 1.164 + /* Save last two gains */ 1.165 + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); 1.166 + 1.167 + psPLC->subfr_length = psDec->subfr_length; 1.168 + psPLC->nb_subfr = psDec->nb_subfr; 1.169 +} 1.170 + 1.171 +static OPUS_INLINE void silk_PLC_conceal( 1.172 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.173 + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 1.174 + opus_int16 frame[] /* O LPC residual signal */ 1.175 +) 1.176 +{ 1.177 + opus_int i, j, k; 1.178 + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; 1.179 + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; 1.180 + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; 1.181 + opus_int32 LPC_pred_Q10, LTP_pred_Q12; 1.182 + opus_int16 rand_scale_Q14; 1.183 + opus_int16 *B_Q14, *exc_buf_ptr; 1.184 + opus_int32 *sLPC_Q14_ptr; 1.185 + VARDECL( opus_int16, exc_buf ); 1.186 + opus_int16 A_Q12[ MAX_LPC_ORDER ]; 1.187 + VARDECL( opus_int16, sLTP ); 1.188 + VARDECL( opus_int32, sLTP_Q14 ); 1.189 + silk_PLC_struct *psPLC = &psDec->sPLC; 1.190 + opus_int32 prevGain_Q10[2]; 1.191 + SAVE_STACK; 1.192 + 1.193 + ALLOC( exc_buf, 2*psPLC->subfr_length, opus_int16 ); 1.194 + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); 1.195 + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); 1.196 + 1.197 + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); 1.198 + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); 1.199 + 1.200 + if( psDec->first_frame_after_reset ) { 1.201 + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); 1.202 + } 1.203 + 1.204 + /* Find random noise component */ 1.205 + /* Scale previous excitation signal */ 1.206 + exc_buf_ptr = exc_buf; 1.207 + for( k = 0; k < 2; k++ ) { 1.208 + for( i = 0; i < psPLC->subfr_length; i++ ) { 1.209 + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( 1.210 + silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], prevGain_Q10[ k ] ), 8 ) ); 1.211 + } 1.212 + exc_buf_ptr += psPLC->subfr_length; 1.213 + } 1.214 + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ 1.215 + silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length ); 1.216 + silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length ); 1.217 + 1.218 + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { 1.219 + /* First sub-frame has lowest energy */ 1.220 + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; 1.221 + } else { 1.222 + /* Second sub-frame has lowest energy */ 1.223 + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; 1.224 + } 1.225 + 1.226 + /* Set up Gain to random noise component */ 1.227 + B_Q14 = psPLC->LTPCoef_Q14; 1.228 + rand_scale_Q14 = psPLC->randScale_Q14; 1.229 + 1.230 + /* Set up attenuation gains */ 1.231 + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 1.232 + if( psDec->prevSignalType == TYPE_VOICED ) { 1.233 + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 1.234 + } else { 1.235 + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 1.236 + } 1.237 + 1.238 + /* LPC concealment. Apply BWE to previous LPC */ 1.239 + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); 1.240 + 1.241 + /* Preload LPC coeficients to array on stack. Gives small performance gain */ 1.242 + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); 1.243 + 1.244 + /* First Lost frame */ 1.245 + if( psDec->lossCnt == 0 ) { 1.246 + rand_scale_Q14 = 1 << 14; 1.247 + 1.248 + /* Reduce random noise Gain for voiced frames */ 1.249 + if( psDec->prevSignalType == TYPE_VOICED ) { 1.250 + for( i = 0; i < LTP_ORDER; i++ ) { 1.251 + rand_scale_Q14 -= B_Q14[ i ]; 1.252 + } 1.253 + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ 1.254 + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); 1.255 + } else { 1.256 + /* Reduce random noise for unvoiced frames with high LPC gain */ 1.257 + opus_int32 invGain_Q30, down_scale_Q30; 1.258 + 1.259 + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order ); 1.260 + 1.261 + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); 1.262 + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); 1.263 + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); 1.264 + 1.265 + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); 1.266 + } 1.267 + } 1.268 + 1.269 + rand_seed = psPLC->rand_seed; 1.270 + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); 1.271 + sLTP_buf_idx = psDec->ltp_mem_length; 1.272 + 1.273 + /* Rewhiten LTP state */ 1.274 + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; 1.275 + silk_assert( idx > 0 ); 1.276 + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order ); 1.277 + /* Scale LTP state */ 1.278 + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); 1.279 + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); 1.280 + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { 1.281 + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); 1.282 + } 1.283 + 1.284 + /***************************/ 1.285 + /* LTP synthesis filtering */ 1.286 + /***************************/ 1.287 + for( k = 0; k < psDec->nb_subfr; k++ ) { 1.288 + /* Set up pointer */ 1.289 + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; 1.290 + for( i = 0; i < psDec->subfr_length; i++ ) { 1.291 + /* Unrolled loop */ 1.292 + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ 1.293 + LTP_pred_Q12 = 2; 1.294 + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); 1.295 + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); 1.296 + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); 1.297 + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); 1.298 + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); 1.299 + pred_lag_ptr++; 1.300 + 1.301 + /* Generate LPC excitation */ 1.302 + rand_seed = silk_RAND( rand_seed ); 1.303 + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; 1.304 + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); 1.305 + sLTP_buf_idx++; 1.306 + } 1.307 + 1.308 + /* Gradually reduce LTP gain */ 1.309 + for( j = 0; j < LTP_ORDER; j++ ) { 1.310 + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); 1.311 + } 1.312 + /* Gradually reduce excitation gain */ 1.313 + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); 1.314 + 1.315 + /* Slowly increase pitch lag */ 1.316 + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); 1.317 + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); 1.318 + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); 1.319 + } 1.320 + 1.321 + /***************************/ 1.322 + /* LPC synthesis filtering */ 1.323 + /***************************/ 1.324 + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; 1.325 + 1.326 + /* Copy LPC state */ 1.327 + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); 1.328 + 1.329 + silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ 1.330 + for( i = 0; i < psDec->frame_length; i++ ) { 1.331 + /* partly unrolled */ 1.332 + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ 1.333 + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); 1.334 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); 1.335 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); 1.336 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); 1.337 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); 1.338 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); 1.339 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); 1.340 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); 1.341 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); 1.342 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); 1.343 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); 1.344 + for( j = 10; j < psDec->LPC_order; j++ ) { 1.345 + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); 1.346 + } 1.347 + 1.348 + /* Add prediction to LPC excitation */ 1.349 + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 ); 1.350 + 1.351 + /* Scale with Gain */ 1.352 + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); 1.353 + } 1.354 + 1.355 + /* Save LPC state */ 1.356 + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); 1.357 + 1.358 + /**************************************/ 1.359 + /* Update states */ 1.360 + /**************************************/ 1.361 + psPLC->rand_seed = rand_seed; 1.362 + psPLC->randScale_Q14 = rand_scale_Q14; 1.363 + for( i = 0; i < MAX_NB_SUBFR; i++ ) { 1.364 + psDecCtrl->pitchL[ i ] = lag; 1.365 + } 1.366 + RESTORE_STACK; 1.367 +} 1.368 + 1.369 +/* Glues concealed frames with new good received frames */ 1.370 +void silk_PLC_glue_frames( 1.371 + silk_decoder_state *psDec, /* I/O decoder state */ 1.372 + opus_int16 frame[], /* I/O signal */ 1.373 + opus_int length /* I length of signal */ 1.374 +) 1.375 +{ 1.376 + opus_int i, energy_shift; 1.377 + opus_int32 energy; 1.378 + silk_PLC_struct *psPLC; 1.379 + psPLC = &psDec->sPLC; 1.380 + 1.381 + if( psDec->lossCnt ) { 1.382 + /* Calculate energy in concealed residual */ 1.383 + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); 1.384 + 1.385 + psPLC->last_frame_lost = 1; 1.386 + } else { 1.387 + if( psDec->sPLC.last_frame_lost ) { 1.388 + /* Calculate residual in decoded signal if last frame was lost */ 1.389 + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); 1.390 + 1.391 + /* Normalize energies */ 1.392 + if( energy_shift > psPLC->conc_energy_shift ) { 1.393 + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); 1.394 + } else if( energy_shift < psPLC->conc_energy_shift ) { 1.395 + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); 1.396 + } 1.397 + 1.398 + /* Fade in the energy difference */ 1.399 + if( energy > psPLC->conc_energy ) { 1.400 + opus_int32 frac_Q24, LZ; 1.401 + opus_int32 gain_Q16, slope_Q16; 1.402 + 1.403 + LZ = silk_CLZ32( psPLC->conc_energy ); 1.404 + LZ = LZ - 1; 1.405 + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); 1.406 + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); 1.407 + 1.408 + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); 1.409 + 1.410 + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); 1.411 + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); 1.412 + /* Make slope 4x steeper to avoid missing onsets after DTX */ 1.413 + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); 1.414 + 1.415 + for( i = 0; i < length; i++ ) { 1.416 + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); 1.417 + gain_Q16 += slope_Q16; 1.418 + if( gain_Q16 > (opus_int32)1 << 16 ) { 1.419 + break; 1.420 + } 1.421 + } 1.422 + } 1.423 + } 1.424 + psPLC->last_frame_lost = 0; 1.425 + } 1.426 +}