1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*********************************************************************** 2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCopyright (c) 2006-2011, Skype Limited. All rights reserved. 3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgRedistribution and use in source and binary forms, with or without 4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgmodification, are permitted provided that the following conditions 5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgare met: 6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions of source code must retain the above copyright notice, 7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgthis list of conditions and the following disclaimer. 8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions in binary form must reproduce the above copyright 9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnotice, this list of conditions and the following disclaimer in the 10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgdocumentation and/or other materials provided with the distribution. 11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org- Neither the name of Internet Society, IETF or IETF Trust, nor the 12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnames of specific contributors, may be used to endorse or promote 13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgproducts derived from this software without specific prior written 14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgpermission. 15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgPOSSIBILITY OF SUCH DAMAGE. 26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org***********************************************************************/ 27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef HAVE_CONFIG_H 29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "config.h" 30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif 31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "main.h" 336b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org#include "stack_alloc.h" 34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "PLC.h" 35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define NB_ATT 2 37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ 38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ 39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ 40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 413c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_PLC_update( 42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O Decoder state */ 43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_control *psDecCtrl /* I/O Decoder control */ 44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org); 45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 463c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_PLC_conceal( 47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O Decoder state */ 48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 frame[] /* O LPC residual signal */ 50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org); 51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_PLC_Reset( 54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec /* I/O Decoder state */ 55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); 58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); 59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); 60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.subfr_length = 20; 61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.nb_subfr = 2; 62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_PLC( 65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O Decoder state */ 66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 frame[], /* I/O signal */ 68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int lost /* I Loss flag */ 69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* PLC control function */ 72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { 73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_Reset( psDec ); 74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->sPLC.fs_kHz = psDec->fs_kHz; 75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( lost ) { 78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /****************************/ 79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Generate Signal */ 80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /****************************/ 81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_conceal( psDec, psDecCtrl, frame ); 82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->lossCnt++; 84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /****************************/ 86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Update state */ 87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /****************************/ 88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_update( psDec, psDecCtrl ); 89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/**************************************************/ 93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Update state of PLC */ 94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/**************************************************/ 953c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_PLC_update( 96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O Decoder state */ 97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_control *psDecCtrl /* I/O Decoder control */ 98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; 101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int i, j; 102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_struct *psPLC; 103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC = &psDec->sPLC; 105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Update parameters used in case of packet loss */ 107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDec->prevSignalType = psDec->indices.signalType; 108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_Gain_Q14 = 0; 109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->indices.signalType == TYPE_VOICED ) { 110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Find the parameters for the last subframe which contains a pitch pulse */ 111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { 112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( j == psDec->nb_subfr ) { 113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org break; 114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org temp_LTP_Gain_Q14 = 0; 116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < LTP_ORDER; i++ ) { 117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; 118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { 120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_Gain_Q14 = temp_LTP_Gain_Q14; 121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( psPLC->LTPCoef_Q14, 122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], 123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_ORDER * sizeof( opus_int16 ) ); 124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); 126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); 130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; 131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Limit LT coefs */ 133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { 134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int scale_Q10; 135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 tmp; 136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); 138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); 139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < LTP_ORDER; i++ ) { 140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); 141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { 143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int scale_Q14; 144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 tmp; 145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); 147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); 148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < LTP_ORDER; i++ ) { 149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); 150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); 154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); 155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Save LPC coeficients */ 158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); 159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; 160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Save last two gains */ 162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); 163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->subfr_length = psDec->subfr_length; 165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->nb_subfr = psDec->nb_subfr; 166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 1683c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_PLC_conceal( 169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O Decoder state */ 170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 frame[] /* O LPC residual signal */ 172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int i, j, k; 175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int lag, idx, sLTP_buf_idx, shift1, shift2; 176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; 177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; 178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 LPC_pred_Q10, LTP_pred_Q12; 179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 rand_scale_Q14; 180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 *B_Q14, *exc_buf_ptr; 181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 *sLPC_Q14_ptr; 1826b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org VARDECL( opus_int16, exc_buf ); 183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 A_Q12[ MAX_LPC_ORDER ]; 1846b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org VARDECL( opus_int16, sLTP ); 1856b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org VARDECL( opus_int32, sLTP_Q14 ); 186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_struct *psPLC = &psDec->sPLC; 187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 prevGain_Q10[2]; 1886b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org SAVE_STACK; 1896b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org 1906b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org ALLOC( exc_buf, 2*psPLC->subfr_length, opus_int16 ); 1916b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); 1926b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); 193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); 195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); 196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->first_frame_after_reset ) { 198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); 199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Find random noise component */ 202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Scale previous excitation signal */ 203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org exc_buf_ptr = exc_buf; 204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( k = 0; k < 2; k++ ) { 205885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < psPLC->subfr_length; i++ ) { 206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( 207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], prevGain_Q10[ k ] ), 8 ) ); 208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org exc_buf_ptr += psPLC->subfr_length; 210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Find the subframe with lowest energy of the last two and use that as random noise generator */ 212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length ); 213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length ); 214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { 216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* First sub-frame has lowest energy */ 217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; 218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Second sub-frame has lowest energy */ 220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; 221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Set up Gain to random noise component */ 224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org B_Q14 = psPLC->LTPCoef_Q14; 225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 = psPLC->randScale_Q14; 226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Set up attenuation gains */ 228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->prevSignalType == TYPE_VOICED ) { 230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; 233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* LPC concealment. Apply BWE to previous LPC */ 236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); 237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Preload LPC coeficients to array on stack. Gives small performance gain */ 239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); 240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* First Lost frame */ 242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->lossCnt == 0 ) { 243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 = 1 << 14; 244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Reduce random noise Gain for voiced frames */ 246885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->prevSignalType == TYPE_VOICED ) { 247885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < LTP_ORDER; i++ ) { 248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 -= B_Q14[ i ]; 249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ 251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); 252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 253885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Reduce random noise for unvoiced frames with high LPC gain */ 254885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 invGain_Q30, down_scale_Q30; 255885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 256885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order ); 257885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 258885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); 259885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); 260885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); 261885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 262885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); 263885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 264885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 265885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 266885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_seed = psPLC->rand_seed; 267885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); 268885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLTP_buf_idx = psDec->ltp_mem_length; 269885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 270885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Rewhiten LTP state */ 271885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; 272885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( idx > 0 ); 273885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order ); 274885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Scale LTP state */ 275885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); 276885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); 277885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { 278885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); 279885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 280885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 281885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /***************************/ 282885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* LTP synthesis filtering */ 283885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /***************************/ 284885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( k = 0; k < psDec->nb_subfr; k++ ) { 285885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Set up pointer */ 286885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; 287885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < psDec->subfr_length; i++ ) { 288885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Unrolled loop */ 289885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ 290885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = 2; 291885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); 292885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); 293885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); 294885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); 295885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); 296885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org pred_lag_ptr++; 297885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 298885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Generate LPC excitation */ 299885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_seed = silk_RAND( rand_seed ); 300885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; 301885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); 302885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLTP_buf_idx++; 303885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 304885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 305885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Gradually reduce LTP gain */ 306885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( j = 0; j < LTP_ORDER; j++ ) { 307885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); 308885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 309885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Gradually reduce excitation gain */ 310885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); 311885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 312885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Slowly increase pitch lag */ 313885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); 314885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); 315885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); 316885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 317885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 318885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /***************************/ 319885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* LPC synthesis filtering */ 320885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /***************************/ 321885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; 322885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 323885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Copy LPC state */ 324885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); 325885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 326885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ 327885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < psDec->frame_length; i++ ) { 328885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* partly unrolled */ 329885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ 330885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); 331885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); 332885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); 333885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); 334885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); 335885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); 336885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); 337885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); 338885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); 339885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); 340885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); 341885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( j = 10; j < psDec->LPC_order; j++ ) { 342885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); 343885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 344885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 345885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Add prediction to LPC excitation */ 346885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 ); 347885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 348885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Scale with Gain */ 349885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); 350885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 351885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 352885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Save LPC state */ 353885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); 354885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 355885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /**************************************/ 356885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Update states */ 357885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /**************************************/ 358885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->rand_seed = rand_seed; 359885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->randScale_Q14 = rand_scale_Q14; 360885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < MAX_NB_SUBFR; i++ ) { 361885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psDecCtrl->pitchL[ i ] = lag; 362885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 3636b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org RESTORE_STACK; 364885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 365885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 3666b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org/* Glues concealed frames with new good received frames */ 367885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_PLC_glue_frames( 368885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_decoder_state *psDec, /* I/O decoder state */ 369885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 frame[], /* I/O signal */ 370885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int length /* I length of signal */ 371885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 372885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 373885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int i, energy_shift; 374885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 energy; 375885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_PLC_struct *psPLC; 376885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC = &psDec->sPLC; 377885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 378885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->lossCnt ) { 379885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Calculate energy in concealed residual */ 380885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); 381885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 382885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->last_frame_lost = 1; 383885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 384885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psDec->sPLC.last_frame_lost ) { 385885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Calculate residual in decoded signal if last frame was lost */ 386885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); 387885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 388885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Normalize energies */ 389885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( energy_shift > psPLC->conc_energy_shift ) { 390885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); 391885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else if( energy_shift < psPLC->conc_energy_shift ) { 392885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); 393885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 394885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 395885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Fade in the energy difference */ 396885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( energy > psPLC->conc_energy ) { 397885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 frac_Q24, LZ; 398885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 gain_Q16, slope_Q16; 399885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 400885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LZ = silk_CLZ32( psPLC->conc_energy ); 401885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org LZ = LZ - 1; 402885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); 403885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); 404885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 405885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); 406885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 407885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); 408885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); 409885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Make slope 4x steeper to avoid missing onsets after DTX */ 410885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); 411885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 412885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( i = 0; i < length; i++ ) { 413885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); 414885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org gain_Q16 += slope_Q16; 415885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( gain_Q16 > (opus_int32)1 << 16 ) { 416885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org break; 417885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 418885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 419885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 420885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 421885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psPLC->last_frame_lost = 0; 422885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 423885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 424