|  | /* | 
|  | *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * decode_plc.c | 
|  | * | 
|  | * Packet Loss Concealment. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | #include "settings.h" | 
|  | #include "entropy_coding.h" | 
|  | #include "pitch_estimator.h" | 
|  | #include "bandwidth_estimator.h" | 
|  | #include "structs.h" | 
|  | #include "codec.h" | 
|  |  | 
|  |  | 
|  | #define NO_OF_PRIMES 8 | 
|  | #define NOISE_FILTER_LEN 30 | 
|  |  | 
|  | /* | 
|  | * function to decode the bitstream | 
|  | * returns the total number of bytes in the stream | 
|  | */ | 
|  |  | 
|  | static int16_t plc_filterma_Fast( | 
|  | int16_t *In,  /* (i)   Vector to be filtered. InOut[-orderCoef+1] | 
|  | to InOut[-1] contains state */ | 
|  | int16_t *Out,  /* (o)   Filtered vector */ | 
|  | int16_t *B,   /* (i)   The filter coefficients (in Q0) */ | 
|  | int16_t Blen,  /* (i)   Number of B coefficients */ | 
|  | int16_t len,   /* (i)  Number of samples to be filtered */ | 
|  | int16_t reduceDecay, | 
|  | int16_t decay, | 
|  | int16_t rshift ) | 
|  | { | 
|  | int i, j; | 
|  | int32_t o; | 
|  | int32_t lim; | 
|  |  | 
|  | lim = WEBRTC_SPL_LSHIFT_W32( (int32_t)1, 15 + rshift )-1; | 
|  |  | 
|  | for (i = 0; i < len; i++) | 
|  | { | 
|  | const int16_t *b_ptr = &B[0]; | 
|  | const int16_t *x_ptr = &In[i]; | 
|  |  | 
|  | o = (int32_t)0; | 
|  |  | 
|  | for (j = 0;j < Blen; j++) | 
|  | { | 
|  | o = WebRtcSpl_AddSatW32(o, WEBRTC_SPL_MUL_16_16(*b_ptr, *x_ptr)); | 
|  | b_ptr++; | 
|  | x_ptr--; | 
|  | } | 
|  |  | 
|  | /* to round off correctly */ | 
|  | o = WebRtcSpl_AddSatW32(o, 1 << (rshift - 1)); | 
|  |  | 
|  | /* saturate according to the domain of the filter coefficients */ | 
|  | o = WEBRTC_SPL_SAT((int32_t)lim, o, (int32_t)-lim); | 
|  |  | 
|  | /* o should be in the range of int16_t */ | 
|  | o >>= rshift; | 
|  |  | 
|  | /* decay the output signal; this is specific to plc */ | 
|  | *Out++ = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( (int16_t)o, decay, 15); // ((o + (int32_t)2048) >> 12); | 
|  |  | 
|  | /* change the decay */ | 
|  | decay -= reduceDecay; | 
|  | if( decay < 0 ) | 
|  | decay = 0; | 
|  | } | 
|  | return( decay ); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | static __inline int32_t log2_Q8_T( uint32_t x ) { | 
|  |  | 
|  | int32_t zeros; | 
|  | int16_t frac; | 
|  |  | 
|  | zeros=WebRtcSpl_NormU32(x); | 
|  | frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23); | 
|  |  | 
|  | /* log2(magn(i)) */ | 
|  | return ((31 - zeros) << 8) + frac; | 
|  | } | 
|  |  | 
|  | static __inline int16_t  exp2_Q10_T(int16_t x) { // Both in and out in Q10 | 
|  |  | 
|  | int16_t tmp16_1, tmp16_2; | 
|  |  | 
|  | tmp16_2=(int16_t)(0x0400|(x&0x03FF)); | 
|  | tmp16_1 = -(x >> 10); | 
|  | if(tmp16_1>0) | 
|  | return tmp16_2 >> tmp16_1; | 
|  | else | 
|  | return tmp16_2 << -tmp16_1; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | This is a fixed-point version of the above code with limLow = 700 and limHigh = 5000, | 
|  | hard-coded. The values 700 and 5000 were experimentally obtained. | 
|  |  | 
|  | The function implements membership values for two sets. The mebership functions are | 
|  | of second orders corresponding to half-bell-shapped pulses. | 
|  | */ | 
|  | static void MemshipValQ15( int16_t in, int16_t *A, int16_t *B ) | 
|  | { | 
|  | int16_t x; | 
|  |  | 
|  | in -= 700;    /* translate the lowLim to 0, limHigh = 5000 - 700, M = 2150 */ | 
|  |  | 
|  | if( in <= 2150 ) | 
|  | { | 
|  | if( in > 0 ) | 
|  | { | 
|  | /* b = in^2 / (2 * M^2), a = 1 - b in Q0. | 
|  | We have to compute in Q15 */ | 
|  |  | 
|  | /* x = in / 2150 {in Q15} = x * 15.2409 {in Q15} = | 
|  | x*15 + (x*983)/(2^12); note that 983/2^12 = 0.23999     */ | 
|  |  | 
|  | /* we are sure that x is in the range of int16_t            */ | 
|  | x = (int16_t)( WEBRTC_SPL_MUL_16_16( in, 15 ) + | 
|  | WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) ); | 
|  | /* b = x^2 / 2 {in Q15} so a shift of 16 is required to | 
|  | be in correct domain and one more for the division by 2 */ | 
|  | *B = (int16_t)((x * x + 0x00010000) >> 17); | 
|  | *A = WEBRTC_SPL_WORD16_MAX - *B; | 
|  | } | 
|  | else | 
|  | { | 
|  | *B = 0; | 
|  | *A = WEBRTC_SPL_WORD16_MAX; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if( in < 4300 ) | 
|  | { | 
|  | /* This is a mirror case of the above */ | 
|  | in = 4300 - in; | 
|  | x = (int16_t)( WEBRTC_SPL_MUL_16_16( in, 15 ) + | 
|  | WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) ); | 
|  | /* b = x^2 / 2 {in Q15} so a shift of 16 is required to | 
|  | be in correct domain and one more for the division by 2 */ | 
|  | *A = (int16_t)((x * x + 0x00010000) >> 17); | 
|  | *B = WEBRTC_SPL_WORD16_MAX - *A; | 
|  |  | 
|  | } | 
|  | else | 
|  | { | 
|  | *A = 0; | 
|  | *B = WEBRTC_SPL_WORD16_MAX; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | static void LinearResampler( int16_t *in, int16_t *out, int16_t lenIn, int16_t lenOut ) | 
|  | { | 
|  | int32_t n; | 
|  | int16_t resOut, i, j, relativePos, diff; /* */ | 
|  | uint16_t udiff; | 
|  |  | 
|  | if( lenIn == lenOut ) | 
|  | { | 
|  | WEBRTC_SPL_MEMCPY_W16( out, in, lenIn ); | 
|  | return; | 
|  | } | 
|  |  | 
|  | n = WEBRTC_SPL_MUL_16_16( (int16_t)(lenIn-1), RESAMP_RES ); | 
|  | resOut = WebRtcSpl_DivW32W16ResW16( n, (int16_t)(lenOut-1) ); | 
|  |  | 
|  | out[0] = in[0]; | 
|  | for( i = 1, j = 0, relativePos = 0; i < lenOut; i++ ) | 
|  | { | 
|  |  | 
|  | relativePos += resOut; | 
|  | while( relativePos > RESAMP_RES ) | 
|  | { | 
|  | j++; | 
|  | relativePos -= RESAMP_RES; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* an overflow may happen and the differce in sample values may | 
|  | * require more than 16 bits. We like to avoid 32 bit arithmatic | 
|  | * as much as possible */ | 
|  |  | 
|  | if( (in[ j ] > 0) && (in[j + 1] < 0) ) | 
|  | { | 
|  | udiff = (uint16_t)(in[ j ] - in[j + 1]); | 
|  | out[ i ] = in[ j ] - (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT); | 
|  | } | 
|  | else | 
|  | { | 
|  | if( (in[j] < 0) && (in[j+1] > 0) ) | 
|  | { | 
|  | udiff = (uint16_t)( in[j + 1] - in[ j ] ); | 
|  | out[ i ] = in[ j ] + (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT); | 
|  | } | 
|  | else | 
|  | { | 
|  | diff = in[ j + 1 ] - in[ j ]; | 
|  | out[ i ] = in[ j ] + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( diff, relativePos, RESAMP_RES_BIT ); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | int16_t WebRtcIsacfix_DecodePlcImpl(int16_t *signal_out16, | 
|  | ISACFIX_DecInst_t *ISACdec_obj, | 
|  | int16_t *current_framesamples ) | 
|  | { | 
|  | int subframecnt; | 
|  | int16_t len = 0; | 
|  |  | 
|  | int16_t* Vector_Word16_1; | 
|  | int16_t  Vector_Word16_Extended_1[FRAMESAMPLES_HALF + NOISE_FILTER_LEN]; | 
|  | int16_t* Vector_Word16_2; | 
|  | int16_t  Vector_Word16_Extended_2[FRAMESAMPLES_HALF + NOISE_FILTER_LEN]; | 
|  |  | 
|  | int32_t Vector_Word32_1[FRAMESAMPLES_HALF]; | 
|  | int32_t Vector_Word32_2[FRAMESAMPLES_HALF]; | 
|  |  | 
|  | int16_t lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs | 
|  | int16_t hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs | 
|  |  | 
|  | int16_t pitchLags_Q7[PITCH_SUBFRAMES]; | 
|  | int16_t pitchGains_Q12[PITCH_SUBFRAMES]; | 
|  |  | 
|  | int16_t tmp_1, tmp_2; | 
|  | int32_t tmp32a, tmp32b; | 
|  | int16_t gainQ13; | 
|  |  | 
|  | int16_t myDecayRate; | 
|  |  | 
|  | /* ---------- PLC variables ------------ */ | 
|  | int16_t lag0, i, k, noiseIndex; | 
|  | int16_t stretchPitchLP[PITCH_MAX_LAG + 10], stretchPitchLP1[PITCH_MAX_LAG + 10]; | 
|  |  | 
|  | int32_t gain_lo_hiQ17[2*SUBFRAMES]; | 
|  |  | 
|  | int16_t nLP, pLP, wNoisyLP, wPriodicLP, tmp16, minIdx; | 
|  | int32_t nHP, pHP, wNoisyHP, wPriodicHP, corr, minCorr, maxCoeff; | 
|  | int16_t noise1, rshift; | 
|  |  | 
|  |  | 
|  | int16_t ltpGain, pitchGain, myVoiceIndicator, myAbs, maxAbs; | 
|  | int32_t varIn, varOut, logVarIn, logVarOut, Q, logMaxAbs; | 
|  | int rightShiftIn, rightShiftOut; | 
|  |  | 
|  |  | 
|  | /* ------------------------------------- */ | 
|  |  | 
|  |  | 
|  | myDecayRate = (DECAY_RATE); | 
|  | Vector_Word16_1 = &Vector_Word16_Extended_1[NOISE_FILTER_LEN]; | 
|  | Vector_Word16_2 = &Vector_Word16_Extended_2[NOISE_FILTER_LEN]; | 
|  |  | 
|  |  | 
|  | /* ----- Simply Copy Previous LPC parameters ------ */ | 
|  | for( subframecnt = 0; subframecnt < SUBFRAMES; subframecnt++ ) | 
|  | { | 
|  | /* lower Band */ | 
|  | WEBRTC_SPL_MEMCPY_W16(&lofilt_coefQ15[ subframecnt * ORDERLO ], | 
|  | (ISACdec_obj->plcstr_obj).lofilt_coefQ15, ORDERLO); | 
|  | gain_lo_hiQ17[2*subframecnt] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0]; | 
|  |  | 
|  | /* Upper Band */ | 
|  | WEBRTC_SPL_MEMCPY_W16(&hifilt_coefQ15[ subframecnt * ORDERHI ], | 
|  | (ISACdec_obj->plcstr_obj).hifilt_coefQ15, ORDERHI); | 
|  | gain_lo_hiQ17[2*subframecnt + 1] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1]; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | lag0 = ((ISACdec_obj->plcstr_obj.lastPitchLag_Q7 + 64) >> 7) + 1; | 
|  |  | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).used != PLC_WAS_USED ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).pitchCycles = 0; | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).lastPitchLP = | 
|  | &((ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0]); | 
|  | minCorr = WEBRTC_SPL_WORD32_MAX; | 
|  |  | 
|  | if ( (FRAMESAMPLES_HALF - 2*lag0 - 10) > 0 ) | 
|  | { | 
|  | minIdx = 11; | 
|  | for( i = 0; i < 21; i++ ) | 
|  | { | 
|  | corr = 0; | 
|  | for( k = 0; k < lag0; k++ ) | 
|  | { | 
|  | corr = WebRtcSpl_AddSatW32(corr, WEBRTC_SPL_ABS_W32( | 
|  | WebRtcSpl_SubSatW16( | 
|  | (ISACdec_obj->plcstr_obj).lastPitchLP[k], | 
|  | (ISACdec_obj->plcstr_obj).prevPitchInvIn[ | 
|  | FRAMESAMPLES_HALF - 2*lag0 - 10 + i + k ] ) ) ); | 
|  | } | 
|  | if( corr < minCorr ) | 
|  | { | 
|  | minCorr = corr; | 
|  | minIdx = i; | 
|  | } | 
|  | } | 
|  | (ISACdec_obj->plcstr_obj).prevPitchLP = | 
|  | &( (ISACdec_obj->plcstr_obj).prevPitchInvIn[ | 
|  | FRAMESAMPLES_HALF - lag0*2 - 10 + minIdx] ); | 
|  | } | 
|  | else | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).prevPitchLP = | 
|  | (ISACdec_obj->plcstr_obj).lastPitchLP; | 
|  | } | 
|  | pitchGain = (ISACdec_obj->plcstr_obj).lastPitchGain_Q12; | 
|  |  | 
|  | WebRtcSpl_AutoCorrelation( | 
|  | &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0], | 
|  | lag0, 0, &varIn, &rightShiftIn); | 
|  | WebRtcSpl_AutoCorrelation( | 
|  | &(ISACdec_obj->plcstr_obj).prevPitchInvOut[PITCH_MAX_LAG + 10 - lag0], | 
|  | lag0, 0, &varOut, &rightShiftOut); | 
|  |  | 
|  | maxAbs = 0; | 
|  | for( i = 0; i< lag0; i++) | 
|  | { | 
|  | myAbs = WEBRTC_SPL_ABS_W16( | 
|  | (ISACdec_obj->plcstr_obj).prevPitchInvOut[ | 
|  | PITCH_MAX_LAG + 10 - lag0 + i] ); | 
|  | maxAbs = (myAbs > maxAbs)? myAbs:maxAbs; | 
|  | } | 
|  | logVarIn = log2_Q8_T( (uint32_t)( varIn ) ) + | 
|  | (int32_t)(rightShiftIn << 8); | 
|  | logVarOut = log2_Q8_T( (uint32_t)( varOut ) ) + | 
|  | (int32_t)(rightShiftOut << 8); | 
|  | logMaxAbs = log2_Q8_T( (uint32_t)( maxAbs ) ); | 
|  |  | 
|  | ltpGain = (int16_t)(logVarOut - logVarIn); | 
|  | Q = 2 * logMaxAbs - ( logVarOut - 1512 ); | 
|  |  | 
|  | /* | 
|  | * --- | 
|  | * We are computing sqrt( (VarIn/lag0) / var( noise ) ) | 
|  | * var( noise ) is almost 256. we have already computed log2( VarIn ) in Q8 | 
|  | * so we actually compute 2^( 0.5*(log2( VarIn ) - log2( lag0 ) - log2( var(noise ) )  ). | 
|  | * Note that put log function is in Q8 but the exponential function is in Q10. | 
|  | * -- | 
|  | */ | 
|  |  | 
|  | logVarIn -= log2_Q8_T( (uint32_t)( lag0 ) ); | 
|  | tmp16 = (int16_t)((logVarIn<<1) - (4<<10) ); | 
|  | rightShiftIn = 0; | 
|  | if( tmp16 > 4096 ) | 
|  | { | 
|  | tmp16 -= 4096; | 
|  | tmp16 = exp2_Q10_T( tmp16 ); | 
|  | tmp16 >>= 6; | 
|  | } | 
|  | else | 
|  | tmp16 = exp2_Q10_T( tmp16 )>>10; | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).std = tmp16 - 4; | 
|  |  | 
|  | if( (ltpGain < 110) || (ltpGain > 230) ) | 
|  | { | 
|  | if( ltpGain < 100 && (pitchGain < 1800) ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).A = WEBRTC_SPL_WORD16_MAX; | 
|  | } | 
|  | else | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).A = ((ltpGain < 110) && (Q < 800) | 
|  | )? WEBRTC_SPL_WORD16_MAX:0; | 
|  | } | 
|  | (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX - | 
|  | (ISACdec_obj->plcstr_obj).A; | 
|  | } | 
|  | else | 
|  | { | 
|  | if( (pitchGain < 450) || (pitchGain > 1600) ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).A = ((pitchGain < 450) | 
|  | )? WEBRTC_SPL_WORD16_MAX:0; | 
|  | (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX - | 
|  | (ISACdec_obj->plcstr_obj).A; | 
|  | } | 
|  | else | 
|  | { | 
|  | myVoiceIndicator = ltpGain * 2 + pitchGain; | 
|  | MemshipValQ15( myVoiceIndicator, | 
|  | &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B ); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | myVoiceIndicator = ltpGain * 16 + pitchGain * 2 + (pitchGain >> 8); | 
|  | MemshipValQ15( myVoiceIndicator, | 
|  | &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B ); | 
|  |  | 
|  |  | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = lag0; | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex = 0; | 
|  |  | 
|  | } | 
|  | else | 
|  | { | 
|  | myDecayRate = (DECAY_RATE<<2); | 
|  | } | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).B < 1000 ) | 
|  | { | 
|  | myDecayRate += (DECAY_RATE<<3); | 
|  | } | 
|  |  | 
|  | /* ------------ reconstructing the residual signal ------------------ */ | 
|  |  | 
|  | LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP, | 
|  | stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); | 
|  | /* inverse pitch filter */ | 
|  |  | 
|  | pitchLags_Q7[0] = pitchLags_Q7[1] = pitchLags_Q7[2] = pitchLags_Q7[3] = | 
|  | ((ISACdec_obj->plcstr_obj).stretchLag<<7); | 
|  | pitchGains_Q12[3] = ( (ISACdec_obj->plcstr_obj).lastPitchGain_Q12); | 
|  | pitchGains_Q12[2] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | pitchGains_Q12[3], 1010, 10 ); | 
|  | pitchGains_Q12[1] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | pitchGains_Q12[2], 1010, 10 ); | 
|  | pitchGains_Q12[0] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | pitchGains_Q12[1], 1010, 10 ); | 
|  |  | 
|  |  | 
|  | /* most of the time either B or A are zero so seperating */ | 
|  | if( (ISACdec_obj->plcstr_obj).B == 0 ) | 
|  | { | 
|  | for( i = 0; i < FRAMESAMPLES_HALF; i++ ) | 
|  | { | 
|  | /* --- Low Pass                                             */ | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  | Vector_Word16_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16; | 
|  |  | 
|  | /* --- Highpass                                              */ | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  | Vector_Word16_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16; | 
|  |  | 
|  | } | 
|  | for( i = 1; i < NOISE_FILTER_LEN; i++ ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  | Vector_Word16_Extended_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16; | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  | Vector_Word16_Extended_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16; | 
|  | } | 
|  | plc_filterma_Fast(Vector_Word16_1, Vector_Word16_Extended_1, | 
|  | &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - | 
|  | NOISE_FILTER_LEN], (int16_t) NOISE_FILTER_LEN, | 
|  | (int16_t) FRAMESAMPLES_HALF, (int16_t)(5), | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise, (int16_t)(6)); | 
|  |  | 
|  | maxCoeff = WebRtcSpl_MaxAbsValueW32( | 
|  | &(ISACdec_obj->plcstr_obj).prevHP[ | 
|  | PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN], NOISE_FILTER_LEN ); | 
|  |  | 
|  | rshift = 0; | 
|  | while( maxCoeff > WEBRTC_SPL_WORD16_MAX ) | 
|  | { | 
|  | maxCoeff >>= 1; | 
|  | rshift++; | 
|  | } | 
|  | for( i = 0; i < NOISE_FILTER_LEN; i++ ) { | 
|  | Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] =(int16_t)( | 
|  | ISACdec_obj->plcstr_obj.prevHP[PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN + | 
|  | i] >> rshift); | 
|  | } | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise = plc_filterma_Fast( | 
|  | Vector_Word16_2, | 
|  | Vector_Word16_Extended_2, | 
|  | &Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN], | 
|  | (int16_t) NOISE_FILTER_LEN, | 
|  | (int16_t) FRAMESAMPLES_HALF, | 
|  | (int16_t) (5), | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise, | 
|  | (int16_t) (7) ); | 
|  |  | 
|  | for( i = 0; i < FRAMESAMPLES_HALF; i++ ) | 
|  | Vector_Word32_2[i] = WEBRTC_SPL_LSHIFT_W32( | 
|  | (int32_t)Vector_Word16_Extended_2[i], rshift ); | 
|  |  | 
|  | Vector_Word16_1 = Vector_Word16_Extended_1; | 
|  | } | 
|  | else | 
|  | { | 
|  | if( (ISACdec_obj->plcstr_obj).A == 0 ) | 
|  | { | 
|  | /* ------ Periodic Vector ---                                */ | 
|  | for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ ) | 
|  | { | 
|  | /* --- Lowpass                                               */ | 
|  | pLP = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | stretchPitchLP[(ISACdec_obj->plcstr_obj).pitchIndex], | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15 ); | 
|  |  | 
|  | /* --- Highpass                                              */ | 
|  | pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15( | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic, | 
|  | (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 - | 
|  | (ISACdec_obj->plcstr_obj).stretchLag + | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex] ); | 
|  |  | 
|  | /* --- lower the muliplier (more decay at next sample) --- */ | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate); | 
|  | if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 ) | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0; | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex++; | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).pitchIndex == | 
|  | (ISACdec_obj->plcstr_obj).stretchLag ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex = 0; | 
|  | (ISACdec_obj->plcstr_obj).pitchCycles++; | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = lag0; | 
|  | } | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = ( | 
|  | (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG | 
|  | )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag; | 
|  |  | 
|  | LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP, | 
|  | stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); | 
|  |  | 
|  | LinearResampler( (ISACdec_obj->plcstr_obj).prevPitchLP, | 
|  | stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); | 
|  |  | 
|  | switch( (ISACdec_obj->plcstr_obj).pitchCycles ) | 
|  | { | 
|  | case 1: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)(( | 
|  | (int32_t)stretchPitchLP[k]* 3 + | 
|  | (int32_t)stretchPitchLP1[k])>>2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case 2: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)(( | 
|  | (int32_t)stretchPitchLP[k] + | 
|  | (int32_t)stretchPitchLP1[k] )>>1); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case 3: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)((stretchPitchLP[k] + | 
|  | (int32_t)stretchPitchLP1[k]*3 )>>2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 ) | 
|  | { | 
|  | myDecayRate += 35; //(myDecayRate>>1); | 
|  | (ISACdec_obj->plcstr_obj).pitchCycles = 0; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* ------ Sum the noisy and periodic signals  ------ */ | 
|  | Vector_Word16_1[i] = pLP; | 
|  | Vector_Word32_2[i] = pHP; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ ) | 
|  | { | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  |  | 
|  | noise1 = (ISACdec_obj->plcstr_obj.seed >> 10) - 16; | 
|  |  | 
|  | nLP = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | (int16_t)((noise1)*(ISACdec_obj->plcstr_obj).std), | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise, 15 ); | 
|  |  | 
|  | /* --- Highpass                                              */ | 
|  | (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( | 
|  | (ISACdec_obj->plcstr_obj).seed ); | 
|  | noise1 = (ISACdec_obj->plcstr_obj.seed >> 11) - 8; | 
|  |  | 
|  | nHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15( | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise, | 
|  | (int32_t)(noise1*(ISACdec_obj->plcstr_obj).std) ); | 
|  |  | 
|  | /* --- lower the muliplier (more decay at next sample) --- */ | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise -= (myDecayRate); | 
|  | if( (ISACdec_obj->plcstr_obj).decayCoeffNoise < 0 ) | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffNoise = 0; | 
|  |  | 
|  | /* ------ Periodic Vector ---                                */ | 
|  | /* --- Lowpass                                               */ | 
|  | pLP = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | stretchPitchLP[(ISACdec_obj->plcstr_obj).pitchIndex], | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15 ); | 
|  |  | 
|  | /* --- Highpass                                              */ | 
|  | pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15( | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic, | 
|  | (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 - | 
|  | (ISACdec_obj->plcstr_obj).stretchLag + | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex] ); | 
|  |  | 
|  | /* --- lower the muliplier (more decay at next sample) --- */ | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate); | 
|  | if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0; | 
|  | } | 
|  |  | 
|  | /* ------ Weighting the noisy and periodic vectors -------   */ | 
|  | wNoisyLP = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | (ISACdec_obj->plcstr_obj).A, nLP, 15 ) ); | 
|  | wNoisyHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15( | 
|  | (ISACdec_obj->plcstr_obj).A, (nHP) ) ); | 
|  |  | 
|  | wPriodicLP = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT( | 
|  | (ISACdec_obj->plcstr_obj).B, pLP, 15)); | 
|  | wPriodicHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15( | 
|  | (ISACdec_obj->plcstr_obj).B, pHP)); | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex++; | 
|  |  | 
|  | if((ISACdec_obj->plcstr_obj).pitchIndex == | 
|  | (ISACdec_obj->plcstr_obj).stretchLag) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).pitchIndex = 0; | 
|  | (ISACdec_obj->plcstr_obj).pitchCycles++; | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) ) | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1; | 
|  | else | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = lag0; | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).stretchLag = ( | 
|  | (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG | 
|  | )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag; | 
|  | LinearResampler( | 
|  | (ISACdec_obj->plcstr_obj).lastPitchLP, | 
|  | stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); | 
|  |  | 
|  | LinearResampler((ISACdec_obj->plcstr_obj).prevPitchLP, | 
|  | stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); | 
|  |  | 
|  | switch((ISACdec_obj->plcstr_obj).pitchCycles) | 
|  | { | 
|  | case 1: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)(( | 
|  | (int32_t)stretchPitchLP[k]* 3 + | 
|  | (int32_t)stretchPitchLP1[k] )>>2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case 2: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)(( | 
|  | (int32_t)stretchPitchLP[k] + | 
|  | (int32_t)stretchPitchLP1[k])>>1); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case 3: | 
|  | { | 
|  | for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) | 
|  | { | 
|  | stretchPitchLP[k] = (int16_t)( | 
|  | (stretchPitchLP[k] + | 
|  | (int32_t)stretchPitchLP1[k]*3 )>>2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 ) | 
|  | { | 
|  | myDecayRate += 55; //(myDecayRate>>1); | 
|  | (ISACdec_obj->plcstr_obj).pitchCycles = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* ------ Sum the noisy and periodic signals  ------ */ | 
|  | Vector_Word16_1[i] = WebRtcSpl_AddSatW16(wNoisyLP, wPriodicLP); | 
|  | Vector_Word32_2[i] = WebRtcSpl_AddSatW32(wNoisyHP, wPriodicHP); | 
|  | } | 
|  | } | 
|  | } | 
|  | /* ----------------- residual signal is reconstructed ------------------ */ | 
|  |  | 
|  | k = (ISACdec_obj->plcstr_obj).pitchIndex; | 
|  | /* --- Write one pitch cycle for recovery block --- */ | 
|  |  | 
|  | for( i = 0; i < RECOVERY_OVERLAP; i++ ) | 
|  | { | 
|  | (ISACdec_obj->plcstr_obj).overlapLP[i] = (int16_t)( | 
|  | WEBRTC_SPL_MUL_16_16_RSFT(stretchPitchLP[k], | 
|  | (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15) ); | 
|  | k = ( k < ((ISACdec_obj->plcstr_obj).stretchLag - 1) )? (k+1):0; | 
|  | } | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 = (ISACdec_obj->plcstr_obj).stretchLag << 7; | 
|  |  | 
|  |  | 
|  | /* --- Inverse Pitch Filter --- */ | 
|  | WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2, | 
|  | &ISACdec_obj->pitchfiltstr_obj, pitchLags_Q7, pitchGains_Q12, 4); | 
|  |  | 
|  | /* reduce gain to compensate for pitch enhancer */ | 
|  | /* gain = 1.0f - 0.45f * AvgPitchGain; */ | 
|  | tmp32a = WEBRTC_SPL_MUL_16_16_RSFT((ISACdec_obj->plcstr_obj).AvgPitchGain_Q12, | 
|  | 29, 0); // Q18 | 
|  | tmp32b = 262144 - tmp32a;  // Q18 | 
|  | gainQ13 = (int16_t) (tmp32b >> 5); // Q13 | 
|  |  | 
|  | /* perceptual post-filtering (using normalized lattice filter) */ | 
|  | for (k = 0; k < FRAMESAMPLES_HALF; k++) | 
|  | Vector_Word32_1[k] = (int32_t) WEBRTC_SPL_MUL_16_16( | 
|  | Vector_Word16_2[k], gainQ13) << 3; // Q25 | 
|  |  | 
|  |  | 
|  | WebRtcIsacfix_NormLatticeFilterAr(ORDERLO, | 
|  | (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0, | 
|  | Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1); | 
|  |  | 
|  | WebRtcIsacfix_NormLatticeFilterAr(ORDERHI, | 
|  | (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0, | 
|  | Vector_Word32_2, hifilt_coefQ15, gain_lo_hiQ17, 1, Vector_Word16_2); | 
|  |  | 
|  | /* recombine the 2 bands */ | 
|  |  | 
|  | /* Form the polyphase signals, and compensate for DC offset */ | 
|  | for (k=0;k<FRAMESAMPLES_HALF;k++) | 
|  | { | 
|  | /* Construct a new upper channel signal*/ | 
|  | tmp_1 = (int16_t)WebRtcSpl_SatW32ToW16( | 
|  | ((int32_t)Vector_Word16_1[k]+Vector_Word16_2[k] + 1)); | 
|  | /* Construct a new lower channel signal*/ | 
|  | tmp_2 = (int16_t)WebRtcSpl_SatW32ToW16( | 
|  | ((int32_t)Vector_Word16_1[k]-Vector_Word16_2[k])); | 
|  | Vector_Word16_1[k] = tmp_1; | 
|  | Vector_Word16_2[k] = tmp_2; | 
|  | } | 
|  |  | 
|  |  | 
|  | WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1, | 
|  | Vector_Word16_2, signal_out16, &ISACdec_obj->postfiltbankstr_obj); | 
|  |  | 
|  | (ISACdec_obj->plcstr_obj).used = PLC_WAS_USED; | 
|  | *current_framesamples = 480; | 
|  |  | 
|  | return len; | 
|  | } |