void WebRtcVad_LogOfEnergy(WebRtc_Word16 *vector, WebRtc_Word16 *enerlogval, WebRtc_Word16 *power, WebRtc_Word16 offset, int vector_length) { WebRtc_Word16 enerSum = 0; WebRtc_Word16 zeros, frac, log2; WebRtc_Word32 energy; int shfts = 0, shfts2; energy = WebRtcSpl_Energy(vector, vector_length, &shfts); if (energy > 0) { shfts2 = 16 - WebRtcSpl_NormW32(energy); shfts += shfts2; // "shfts" is the total number of right shifts that has been done to enerSum. enerSum = (WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(energy, -shfts2); // Find: // 160*log10(enerSum*2^shfts) = 160*log10(2)*log2(enerSum*2^shfts) = // 160*log10(2)*(log2(enerSum) + log2(2^shfts)) = // 160*log10(2)*(log2(enerSum) + shfts) zeros = WebRtcSpl_NormU32(enerSum); frac = (WebRtc_Word16)(((WebRtc_UWord32)((WebRtc_Word32)(enerSum) << zeros) & 0x7FFFFFFF) >> 21); log2 = (WebRtc_Word16)(((31 - zeros) << 10) + frac); *enerlogval = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kLogConst, log2, 19) + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(shfts, kLogConst, 9); if (*enerlogval < 0) { *enerlogval = 0; } } else
int WebRtcIlbcfix_XcorrCoef( WebRtc_Word16 *target, /* (i) first array */ WebRtc_Word16 *regressor, /* (i) second array */ WebRtc_Word16 subl, /* (i) dimension arrays */ WebRtc_Word16 searchLen, /* (i) the search lenght */ WebRtc_Word16 offset, /* (i) samples offset between arrays */ WebRtc_Word16 step /* (i) +1 or -1 */ ){ int k; WebRtc_Word16 maxlag; WebRtc_Word16 pos; WebRtc_Word16 max; WebRtc_Word16 crossCorrScale, Energyscale; WebRtc_Word16 crossCorrSqMod, crossCorrSqMod_Max; WebRtc_Word32 crossCorr, Energy; WebRtc_Word16 crossCorrmod, EnergyMod, EnergyMod_Max; WebRtc_Word16 *tp, *rp; WebRtc_Word16 *rp_beg, *rp_end; WebRtc_Word16 totscale, totscale_max; WebRtc_Word16 scalediff; WebRtc_Word32 newCrit, maxCrit; int shifts; /* Initializations, to make sure that the first one is selected */ crossCorrSqMod_Max=0; EnergyMod_Max=WEBRTC_SPL_WORD16_MAX; totscale_max=-500; maxlag=0; pos=0; /* Find scale value and start position */ if (step==1) { max=WebRtcSpl_MaxAbsValueW16(regressor, (WebRtc_Word16)(subl+searchLen-1)); rp_beg = regressor; rp_end = ®ressor[subl]; } else { /* step==-1 */ max=WebRtcSpl_MaxAbsValueW16(®ressor[-searchLen], (WebRtc_Word16)(subl+searchLen-1)); rp_beg = ®ressor[-1]; rp_end = ®ressor[subl-1]; } /* Introduce a scale factor on the Energy in WebRtc_Word32 in order to make sure that the calculation does not overflow */ if (max>5000) { shifts=2; } else { shifts=0; } /* Calculate the first energy, then do a +/- to get the other energies */ Energy=WebRtcSpl_DotProductWithScale(regressor, regressor, subl, shifts); for (k=0;k<searchLen;k++) { tp = target; rp = ®ressor[pos]; crossCorr=WebRtcSpl_DotProductWithScale(tp, rp, subl, shifts); if ((Energy>0)&&(crossCorr>0)) { /* Put cross correlation and energy on 16 bit word */ crossCorrScale=(WebRtc_Word16)WebRtcSpl_NormW32(crossCorr)-16; crossCorrmod=(WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(crossCorr, crossCorrScale); Energyscale=(WebRtc_Word16)WebRtcSpl_NormW32(Energy)-16; EnergyMod=(WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(Energy, Energyscale); /* Square cross correlation and store upper WebRtc_Word16 */ crossCorrSqMod=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(crossCorrmod, crossCorrmod, 16); /* Calculate the total number of (dynamic) right shifts that have been performed on (crossCorr*crossCorr)/energy */ totscale=Energyscale-(crossCorrScale<<1); /* Calculate the shift difference in order to be able to compare the two (crossCorr*crossCorr)/energy in the same domain */ scalediff=totscale-totscale_max; scalediff=WEBRTC_SPL_MIN(scalediff,31); scalediff=WEBRTC_SPL_MAX(scalediff,-31); /* Compute the cross multiplication between the old best criteria and the new one to be able to compare them without using a division */ if (scalediff<0) { newCrit = ((WebRtc_Word32)crossCorrSqMod*EnergyMod_Max)>>(-scalediff); maxCrit = ((WebRtc_Word32)crossCorrSqMod_Max*EnergyMod); } else {
void WebRtcIlbcfix_CbSearch( IlbcEncoder *iLBCenc_inst, /* (i) the encoder state structure */ int16_t *index, /* (o) Codebook indices */ int16_t *gain_index, /* (o) Gain quantization indices */ int16_t *intarget, /* (i) Target vector for encoding */ int16_t *decResidual,/* (i) Decoded residual for codebook construction */ int16_t lMem, /* (i) Length of buffer */ int16_t lTarget, /* (i) Length of vector */ int16_t *weightDenum,/* (i) weighting filter coefficients in Q12 */ int16_t block /* (i) the subblock number */ ) { int16_t i, j, stage, range; int16_t *pp, scale, tmp; int16_t bits, temp1, temp2; int16_t base_size; int32_t codedEner, targetEner; int16_t gains[CB_NSTAGES+1]; int16_t *cb_vecPtr; int16_t indexOffset, sInd, eInd; int32_t CritMax=0; int16_t shTotMax=WEBRTC_SPL_WORD16_MIN; int16_t bestIndex=0; int16_t bestGain=0; int16_t indexNew, CritNewSh; int32_t CritNew; int32_t *cDotPtr; int16_t noOfZeros; int16_t *gainPtr; int32_t t32, tmpW32; int16_t *WebRtcIlbcfix_kGainSq5_ptr; /* Stack based */ int16_t CBbuf[CB_MEML+LPC_FILTERORDER+CB_HALFFILTERLEN]; int32_t cDot[128]; int32_t Crit[128]; int16_t targetVec[SUBL+LPC_FILTERORDER]; int16_t cbvectors[CB_MEML + 1]; /* Adding one extra position for Coverity warnings. */ int16_t codedVec[SUBL]; int16_t interpSamples[20*4]; int16_t interpSamplesFilt[20*4]; int16_t energyW16[CB_EXPAND*128]; int16_t energyShifts[CB_EXPAND*128]; int16_t *inverseEnergy=energyW16; /* Reuse memory */ int16_t *inverseEnergyShifts=energyShifts; /* Reuse memory */ int16_t *buf = &CBbuf[LPC_FILTERORDER]; int16_t *target = &targetVec[LPC_FILTERORDER]; int16_t *aug_vec = (int16_t*)cDot; /* length [SUBL], reuse memory */ /* Determine size of codebook sections */ base_size=lMem-lTarget+1; if (lTarget==SUBL) { base_size=lMem-19; } /* weighting of the CB memory */ noOfZeros=lMem-WebRtcIlbcfix_kFilterRange[block]; WebRtcSpl_MemSetW16(&buf[-LPC_FILTERORDER], 0, noOfZeros+LPC_FILTERORDER); WebRtcSpl_FilterARFastQ12( decResidual+noOfZeros, buf+noOfZeros, weightDenum, LPC_FILTERORDER+1, WebRtcIlbcfix_kFilterRange[block]); /* weighting of the target vector */ WEBRTC_SPL_MEMCPY_W16(&target[-LPC_FILTERORDER], buf+noOfZeros+WebRtcIlbcfix_kFilterRange[block]-LPC_FILTERORDER, LPC_FILTERORDER); WebRtcSpl_FilterARFastQ12( intarget, target, weightDenum, LPC_FILTERORDER+1, lTarget); /* Store target, towards the end codedVec is calculated as the initial target minus the remaining target */ WEBRTC_SPL_MEMCPY_W16(codedVec, target, lTarget); /* Find the highest absolute value to calculate proper vector scale factor (so that it uses 12 bits) */ temp1 = WebRtcSpl_MaxAbsValueW16(buf, (int16_t)lMem); temp2 = WebRtcSpl_MaxAbsValueW16(target, (int16_t)lTarget); if ((temp1>0)&&(temp2>0)) { temp1 = WEBRTC_SPL_MAX(temp1, temp2); scale = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(temp1, temp1)); } else { /* temp1 or temp2 is negative (maximum was -32768) */ scale = 30; } /* Scale to so that a mul-add 40 times does not overflow */ scale = scale - 25; scale = WEBRTC_SPL_MAX(0, scale); /* Compute energy of the original target */ targetEner = WebRtcSpl_DotProductWithScale(target, target, lTarget, scale); /* Prepare search over one more codebook section. This section is created by filtering the original buffer with a filter. */ WebRtcIlbcfix_FilteredCbVecs(cbvectors, buf, lMem, WebRtcIlbcfix_kFilterRange[block]); range = WebRtcIlbcfix_kSearchRange[block][0]; if(lTarget == SUBL) { /* Create the interpolated samples and store them for use in all stages */ /* First section, non-filtered half of the cb */ WebRtcIlbcfix_InterpolateSamples(interpSamples, buf, lMem); /* Second section, filtered half of the cb */ WebRtcIlbcfix_InterpolateSamples(interpSamplesFilt, cbvectors, lMem); /* Compute the CB vectors' energies for the first cb section (non-filtered) */ WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamples, buf, scale, 20, energyW16, energyShifts); /* Compute the CB vectors' energies for the second cb section (filtered cb) */ WebRtcIlbcfix_CbMemEnergyAugmentation(interpSamplesFilt, cbvectors, scale, (int16_t)(base_size+20), energyW16, energyShifts); /* Compute the CB vectors' energies and store them in the vector * energyW16. Also the corresponding shift values are stored. The * energy values are used in all three stages. */ WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem, lTarget, energyW16+20, energyShifts+20, scale, base_size); } else { /* Compute the CB vectors' energies and store them in the vector * energyW16. Also the corresponding shift values are stored. The * energy values are used in all three stages. */ WebRtcIlbcfix_CbMemEnergy(range, buf, cbvectors, lMem, lTarget, energyW16, energyShifts, scale, base_size); /* Set the energy positions 58-63 and 122-127 to zero (otherwise they are uninitialized) */ WebRtcSpl_MemSetW16(energyW16+range, 0, (base_size-range)); WebRtcSpl_MemSetW16(energyW16+range+base_size, 0, (base_size-range)); } /* Calculate Inverse Energy (energyW16 is already normalized and will contain the inverse energy in Q29 after this call */ WebRtcIlbcfix_EnergyInverse(energyW16, base_size*CB_EXPAND); /* The gain value computed in the previous stage is used * as an upper limit to what the next stage gain value * is allowed to be. In stage 0, 16384 (1.0 in Q14) is used as * the upper limit. */ gains[0] = 16384; for (stage=0; stage<CB_NSTAGES; stage++) { /* Set up memories */ range = WebRtcIlbcfix_kSearchRange[block][stage]; /* initialize search measures */ CritMax=0; shTotMax=-100; bestIndex=0; bestGain=0; /* loop over lags 40+ in the first codebook section, full search */ cb_vecPtr = buf+lMem-lTarget; /* Calculate all the cross correlations (augmented part of CB) */ if (lTarget==SUBL) { WebRtcIlbcfix_AugmentedCbCorr(target, buf+lMem, interpSamples, cDot, 20, 39, scale); cDotPtr=&cDot[20]; } else { cDotPtr=cDot; } /* Calculate all the cross correlations (main part of CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, range, scale, -1); /* Adjust the search range for the augmented vectors */ if (lTarget==SUBL) { range=WebRtcIlbcfix_kSearchRange[block][stage]+20; } else { range=WebRtcIlbcfix_kSearchRange[block][stage]; } indexOffset=0; /* Search for best index in this part of the vector */ WebRtcIlbcfix_CbSearchCore( cDot, range, stage, inverseEnergy, inverseEnergyShifts, Crit, &indexNew, &CritNew, &CritNewSh); /* Update the global best index and the corresponding gain */ WebRtcIlbcfix_CbUpdateBestIndex( CritNew, CritNewSh, (int16_t)(indexNew+indexOffset), cDot[indexNew+indexOffset], inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset], &CritMax, &shTotMax, &bestIndex, &bestGain); sInd=bestIndex-(int16_t)(CB_RESRANGE>>1); eInd=sInd+CB_RESRANGE; if (sInd<0) { eInd-=sInd; sInd=0; } if (eInd>=range) { eInd=range-1; sInd=eInd-CB_RESRANGE; } range = WebRtcIlbcfix_kSearchRange[block][stage]; if (lTarget==SUBL) { i=sInd; if (sInd<20) { WebRtcIlbcfix_AugmentedCbCorr(target, cbvectors+lMem, interpSamplesFilt, cDot, (int16_t)(sInd+20), (int16_t)(WEBRTC_SPL_MIN(39, (eInd+20))), scale); i=20; } cDotPtr=&cDot[WEBRTC_SPL_MAX(0,(20-sInd))]; cb_vecPtr = cbvectors+lMem-20-i; /* Calculate the cross correlations (main part of the filtered CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, (int16_t)(eInd-i+1), scale, -1); } else { cDotPtr = cDot; cb_vecPtr = cbvectors+lMem-lTarget-sInd; /* Calculate the cross correlations (main part of the filtered CB) */ WebRtcSpl_CrossCorrelation(cDotPtr, target, cb_vecPtr, lTarget, (int16_t)(eInd-sInd+1), scale, -1); } /* Adjust the search range for the augmented vectors */ indexOffset=base_size+sInd; /* Search for best index in this part of the vector */ WebRtcIlbcfix_CbSearchCore( cDot, (int16_t)(eInd-sInd+1), stage, inverseEnergy+indexOffset, inverseEnergyShifts+indexOffset, Crit, &indexNew, &CritNew, &CritNewSh); /* Update the global best index and the corresponding gain */ WebRtcIlbcfix_CbUpdateBestIndex( CritNew, CritNewSh, (int16_t)(indexNew+indexOffset), cDot[indexNew], inverseEnergy[indexNew+indexOffset], inverseEnergyShifts[indexNew+indexOffset], &CritMax, &shTotMax, &bestIndex, &bestGain); index[stage] = bestIndex; bestGain = WebRtcIlbcfix_GainQuant(bestGain, (int16_t)WEBRTC_SPL_ABS_W16(gains[stage]), stage, &gain_index[stage]); /* Extract the best (according to measure) codebook vector Also adjust the index, so that the augmented vectors are last. Above these vectors were first... */ if(lTarget==(STATE_LEN-iLBCenc_inst->state_short_len)) { if(index[stage]<base_size) { pp=buf+lMem-lTarget-index[stage]; } else { pp=cbvectors+lMem-lTarget- index[stage]+base_size; } } else { if (index[stage]<base_size) { if (index[stage]>=20) { /* Adjust index and extract vector */ index[stage]-=20; pp=buf+lMem-lTarget-index[stage]; } else { /* Adjust index and extract vector */ index[stage]+=(base_size-20); WebRtcIlbcfix_CreateAugmentedVec((int16_t)(index[stage]-base_size+40), buf+lMem, aug_vec); pp = aug_vec; } } else { if ((index[stage] - base_size) >= 20) { /* Adjust index and extract vector */ index[stage]-=20; pp=cbvectors+lMem-lTarget- index[stage]+base_size; } else { /* Adjust index and extract vector */ index[stage]+=(base_size-20); WebRtcIlbcfix_CreateAugmentedVec((int16_t)(index[stage]-2*base_size+40), cbvectors+lMem, aug_vec); pp = aug_vec; } } } /* Subtract the best codebook vector, according to measure, from the target vector */ WebRtcSpl_AddAffineVectorToVector(target, pp, (int16_t)(-bestGain), (int32_t)8192, (int16_t)14, (int)lTarget); /* record quantized gain */ gains[stage+1] = bestGain; } /* end of Main Loop. for (stage=0;... */ /* Calculte the coded vector (original target - what's left) */ for (i=0;i<lTarget;i++) { codedVec[i]-=target[i]; } /* Gain adjustment for energy matching */ codedEner = WebRtcSpl_DotProductWithScale(codedVec, codedVec, lTarget, scale); j=gain_index[0]; temp1 = (int16_t)WebRtcSpl_NormW32(codedEner); temp2 = (int16_t)WebRtcSpl_NormW32(targetEner); if(temp1 < temp2) { bits = 16 - temp1; } else { bits = 16 - temp2; } tmp = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(gains[1],gains[1], 14); targetEner = WEBRTC_SPL_MUL_16_16( WEBRTC_SPL_SHIFT_W32(targetEner, -bits), tmp); tmpW32 = ((int32_t)(gains[1]-1))<<1; /* Pointer to the table that contains gain_sq5TblFIX * gain_sq5TblFIX in Q14 */ gainPtr=(int16_t*)WebRtcIlbcfix_kGainSq5Sq+gain_index[0]; temp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(codedEner, -bits); WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[j]; /* targetEner and codedEner are in Q(-2*scale) */ for (i=gain_index[0];i<32;i++) { /* Change the index if (codedEnergy*gainTbl[i]*gainTbl[i])<(targetEn*gain[0]*gain[0]) AND gainTbl[i] < 2*gain[0] */ t32 = WEBRTC_SPL_MUL_16_16(temp1, (*gainPtr)); t32 = t32 - targetEner; if (t32 < 0) { if ((*WebRtcIlbcfix_kGainSq5_ptr) < tmpW32) { j=i; WebRtcIlbcfix_kGainSq5_ptr = (int16_t*)&WebRtcIlbcfix_kGainSq5[i]; } } gainPtr++; } gain_index[0]=j; return; }
void WebRtcIlbcfix_CbSearchCore( int32_t *cDot, /* (i) Cross Correlation */ int16_t range, /* (i) Search range */ int16_t stage, /* (i) Stage of this search */ int16_t *inverseEnergy, /* (i) Inversed energy */ int16_t *inverseEnergyShift, /* (i) Shifts of inversed energy with the offset 2*16-29 */ int32_t *Crit, /* (o) The criteria */ int16_t *bestIndex, /* (o) Index that corresponds to maximum criteria (in this vector) */ int32_t *bestCrit, /* (o) Value of critera for the chosen index */ int16_t *bestCritSh) /* (o) The domain of the chosen criteria */ { int32_t maxW32, tmp32; int16_t max, sh, tmp16; int i; int32_t *cDotPtr; int16_t cDotSqW16; int16_t *inverseEnergyPtr; int32_t *critPtr; int16_t *inverseEnergyShiftPtr; /* Don't allow negative values for stage 0 */ if (stage==0) { cDotPtr=cDot; for (i=0;i<range;i++) { *cDotPtr=WEBRTC_SPL_MAX(0, (*cDotPtr)); cDotPtr++; } } /* Normalize cDot to int16_t, calculate the square of cDot and store the upper int16_t */ maxW32 = WebRtcSpl_MaxAbsValueW32(cDot, range); sh = (int16_t)WebRtcSpl_NormW32(maxW32); cDotPtr = cDot; inverseEnergyPtr = inverseEnergy; critPtr = Crit; inverseEnergyShiftPtr=inverseEnergyShift; max=WEBRTC_SPL_WORD16_MIN; for (i=0;i<range;i++) { /* Calculate cDot*cDot and put the result in a int16_t */ tmp32 = WEBRTC_SPL_LSHIFT_W32(*cDotPtr,sh); tmp16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32,16); cDotSqW16 = (int16_t)(((int32_t)(tmp16)*(tmp16))>>16); /* Calculate the criteria (cDot*cDot/energy) */ *critPtr=WEBRTC_SPL_MUL_16_16(cDotSqW16, (*inverseEnergyPtr)); /* Extract the maximum shift value under the constraint that the criteria is not zero */ if ((*critPtr)!=0) { max = WEBRTC_SPL_MAX((*inverseEnergyShiftPtr), max); } inverseEnergyPtr++; inverseEnergyShiftPtr++; critPtr++; cDotPtr++; } /* If no max shifts still at initialization value, set shift to zero */ if (max==WEBRTC_SPL_WORD16_MIN) { max = 0; } /* Modify the criterias, so that all of them use the same Q domain */ critPtr=Crit; inverseEnergyShiftPtr=inverseEnergyShift; for (i=0;i<range;i++) { /* Guarantee that the shift value is less than 16 in order to simplify for DSP's (and guard against >31) */ tmp16 = WEBRTC_SPL_MIN(16, max-(*inverseEnergyShiftPtr)); (*critPtr)=WEBRTC_SPL_SHIFT_W32((*critPtr),-tmp16); critPtr++; inverseEnergyShiftPtr++; } /* Find the index of the best value */ *bestIndex = WebRtcSpl_MaxIndexW32(Crit, range); *bestCrit = Crit[*bestIndex]; /* Calculate total shifts of this criteria */ *bestCritSh = 32 - 2*sh + max; return; }
// Compute speech/noise probability // speech/noise probability is returned in: probSpeechFinal //snrLocPrior is the prior SNR for each frequency (in Q11) //snrLocPost is the post SNR for each frequency (in Q11) void WebRtcNsx_SpeechNoiseProb(NsxInst_t* inst, uint16_t* nonSpeechProbFinal, uint32_t* priorLocSnr, uint32_t* postLocSnr) { uint32_t zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3; int32_t invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32; int32_t frac32, logTmp; int32_t logLrtTimeAvgKsumFX; int16_t indPriorFX16; int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart; int i, normTmp, normTmp2, nShifts; // compute feature based on average LR factor // this is the average over all frequencies of the smooth log LRT logLrtTimeAvgKsumFX = 0; for (i = 0; i < inst->magnLen; i++) { besselTmpFX32 = (int32_t)postLocSnr[i]; // Q11 normTmp = WebRtcSpl_NormU32(postLocSnr[i]); num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp) if (normTmp > 10) { den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp) } else { den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp) } if (den > 0) { besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11 } else { besselTmpFX32 -= num; // Q11 } // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) // - inst->logLrtTimeAvg[i]); // Here, LRT_TAVG = 0.5 zeros = WebRtcSpl_NormU32(priorLocSnr[i]); frac32 = (int32_t)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19); tmp32 = WEBRTC_SPL_MUL(frac32, frac32); tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19); tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((int16_t)frac32, 5412, 12); frac32 = tmp32 + 37; // tmp32 = log2(priorLocSnr[i]) tmp32 = (int32_t)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12 logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2) tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12 inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12 logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12 } inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2 // done with computation of LR factor // //compute the indicator functions // // average LRT feature // FLOAT code // indicator0 = 0.5 * (tanh(widthPrior * // (logLrtTimeAvgKsum - threshPrior0)) + 1.0); tmpIndFX = 16384; // Q14(1.0) tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12 nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5; //use larger width in tanh map for pause regions if (tmp32no1 < 0) { tmpIndFX = 0; tmp32no1 = -tmp32no1; //widthPrior = widthPrior * 2.0; nShifts++; } tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14 // compute indicator function: sigmoid map tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14); if ((tableIndex < 16) && (tableIndex >= 0)) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); if (tmpIndFX == 0) { tmpIndFX = 8192 - tmp16no2; // Q14 } else { tmpIndFX = 8192 + tmp16no2; // Q14 } } indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14 //spectral flatness feature if (inst->weightSpecFlat) { tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10 tmpIndFX = 16384; // Q14(1.0) //use larger width in tanh map for pause regions tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10 nShifts = 4; if (inst->thresholdSpecFlat < tmpU32no1) { tmpIndFX = 0; tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat; //widthPrior = widthPrior * 2.0; nShifts++; } tmp32no1 = (int32_t)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 // compute indicator function: sigmoid map // FLOAT code // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * // (threshPrior1 - tmpFloat1)) + 1.0); tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); if (tableIndex < 16) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); if (tmpIndFX) { tmpIndFX = 8192 + tmp16no2; // Q14 } else { tmpIndFX = 8192 - tmp16no2; // Q14 } } indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14 } //for template spectral-difference if (inst->weightSpecDiff) { tmpU32no1 = 0; if (inst->featureSpecDiff) { normTmp = WEBRTC_SPL_MIN(20 - inst->stages, WebRtcSpl_NormU32(inst->featureSpecDiff)); tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages) tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages - normTmp); if (tmpU32no2 > 0) { // Q(20 - inst->stages) tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); } else { tmpU32no1 = (uint32_t)(0x7fffffff); } } tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25); tmpU32no2 = tmpU32no1 - tmpU32no3; nShifts = 1; tmpIndFX = 16384; // Q14(1.0) //use larger width in tanh map for pause regions if (tmpU32no2 & 0x80000000) { tmpIndFX = 0; tmpU32no2 = tmpU32no3 - tmpU32no1; //widthPrior = widthPrior * 2.0; nShifts--; } tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts); // compute indicator function: sigmoid map /* FLOAT code indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0); */ tableIndex = (int16_t)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); if (tableIndex < 16) { tmp16no2 = kIndicatorTable[tableIndex]; tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14 tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( tmp16no1, frac, 14); if (tmpIndFX) { tmpIndFX = 8192 + tmp16no2; } else { tmpIndFX = 8192 - tmp16no2; } } indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14 } //combine the indicator function with the feature weights // FLOAT code // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * // indicator1 + weightIndPrior2 * indicator2); indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14 // done with computing indicator function //compute the prior probability // FLOAT code // inst->priorNonSpeechProb += PRIOR_UPDATE * // (indPriorNonSpeech - inst->priorNonSpeechProb); tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14 inst->priorNonSpeechProb += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( PRIOR_UPDATE_Q14, tmp16, 14); // Q14 //final speech probability: combine prior model with LR factor: memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen); if (inst->priorNonSpeechProb > 0) { for (i = 0; i < inst->magnLen; i++) { // FLOAT code // invLrt = exp(inst->logLrtTimeAvg[i]); // invLrt = inst->priorSpeechProb * invLrt; // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / // (1.0 - inst->priorSpeechProb + invLrt); // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt; // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / // (inst->priorNonSpeechProb + invLrt); if (inst->logLrtTimeAvgW32[i] < 65300) { tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL( inst->logLrtTimeAvgW32[i], 23637), 14); // Q12 intPart = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12); if (intPart < -8) { intPart = -8; } frac = (int16_t)(tmp32no1 & 0x00000fff); // Q12 // Quadratic approximation of 2^frac tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12 tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12 invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart) + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8 normTmp = WebRtcSpl_NormW32(invLrtFX); normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb)); if (normTmp + normTmp2 >= 7) { if (normTmp + normTmp2 < 15) { invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); // Q(normTmp+normTmp2-7) tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q(normTmp+normTmp2+7) invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14 } else { tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22 invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14 } tmp32no1 = WEBRTC_SPL_LSHIFT_W32((int32_t)inst->priorNonSpeechProb, 8); // Q22 nonSpeechProbFinal[i] = (uint16_t)WEBRTC_SPL_DIV(tmp32no1, (int32_t)inst->priorNonSpeechProb + invLrtFX); // Q8 } } } } }
/* MA filter */ void WebRtcIsacfix_NormLatticeFilterMa(int16_t orderCoef, int32_t *stateGQ15, int16_t *lat_inQ0, int16_t *filt_coefQ15, int32_t *gain_lo_hiQ17, int16_t lo_hi, int16_t *lat_outQ9) { int16_t sthQ15[MAX_AR_MODEL_ORDER]; int16_t cthQ15[MAX_AR_MODEL_ORDER]; int u, i, k, n; int16_t temp2,temp3; int16_t ord_1 = orderCoef+1; int32_t inv_cthQ16[MAX_AR_MODEL_ORDER]; int32_t gain32, fQtmp; int16_t gain16; int16_t gain_sh; int32_t tmp32, tmp32b; int32_t fQ15vec[HALF_SUBFRAMELEN]; int32_t gQ15[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN]; int16_t sh; int16_t t16a; int16_t t16b; for (u=0;u<SUBFRAMES;u++) { int32_t temp1 = WEBRTC_SPL_MUL_16_16(u, HALF_SUBFRAMELEN); /* set the Direct Form coefficients */ temp2 = (int16_t)WEBRTC_SPL_MUL_16_16(u, orderCoef); temp3 = (int16_t)WEBRTC_SPL_MUL_16_16(2, u)+lo_hi; /* compute lattice filter coefficients */ memcpy(sthQ15, &filt_coefQ15[temp2], orderCoef * sizeof(int16_t)); WebRtcSpl_SqrtOfOneMinusXSquared(sthQ15, orderCoef, cthQ15); /* compute the gain */ gain32 = gain_lo_hiQ17[temp3]; gain_sh = WebRtcSpl_NormW32(gain32); gain32 = WEBRTC_SPL_LSHIFT_W32(gain32, gain_sh); //Q(17+gain_sh) for (k=0;k<orderCoef;k++) { gain32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], gain32); //Q15*Q(17+gain_sh)>>15 = Q(17+gain_sh) inv_cthQ16[k] = WebRtcSpl_DivW32W16((int32_t)2147483647, cthQ15[k]); // 1/cth[k] in Q31/Q15 = Q16 } gain16 = (int16_t)(gain32 >> 16); // Q(1+gain_sh). /* normalized lattice filter */ /*****************************/ /* initial conditions */ for (i=0;i<HALF_SUBFRAMELEN;i++) { fQ15vec[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)lat_inQ0[i + temp1], 15); //Q15 gQ15[0][i] = WEBRTC_SPL_LSHIFT_W32((int32_t)lat_inQ0[i + temp1], 15); //Q15 } fQtmp = fQ15vec[0]; /* get the state of f&g for the first input, for all orders */ for (i=1;i<ord_1;i++) { // Calculate f[i][0] = inv_cth[i-1]*(f[i-1][0] + sth[i-1]*stateG[i-1]); tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(sthQ15[i-1], stateGQ15[i-1]);//Q15*Q15>>15 = Q15 tmp32b= fQtmp + tmp32; //Q15+Q15=Q15 tmp32 = inv_cthQ16[i-1]; //Q16 t16a = (int16_t)(tmp32 >> 16); t16b = (int16_t) (tmp32-WEBRTC_SPL_LSHIFT_W32(((int32_t)t16a), 16)); if (t16b<0) t16a++; tmp32 = LATTICE_MUL_32_32_RSFT16(t16a, t16b, tmp32b); fQtmp = tmp32; // Q15 // Calculate g[i][0] = cth[i-1]*stateG[i-1] + sth[i-1]* f[i][0]; tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[i-1], stateGQ15[i-1]); //Q15*Q15>>15 = Q15 tmp32b = WEBRTC_SPL_MUL_16_32_RSFT15(sthQ15[i-1], fQtmp); //Q15*Q15>>15 = Q15 tmp32 = tmp32 + tmp32b;//Q15+Q15 = Q15 gQ15[i][0] = tmp32; // Q15 } /* filtering */ /* save the states */ for(k=0;k<orderCoef;k++) { // for 0 <= n < HALF_SUBFRAMELEN - 1: // f[k+1][n+1] = inv_cth[k]*(f[k][n+1] + sth[k]*g[k][n]); // g[k+1][n+1] = cth[k]*g[k][n] + sth[k]* f[k+1][n+1]; WebRtcIsacfix_FilterMaLoopFix(sthQ15[k], cthQ15[k], inv_cthQ16[k], &gQ15[k][0], &gQ15[k+1][1], &fQ15vec[1]); } fQ15vec[0] = fQtmp; for(n=0;n<HALF_SUBFRAMELEN;n++) { //gain32 >>= gain_sh; // Q(17+gain_sh) -> Q17 tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(gain16, fQ15vec[n]); //Q(1+gain_sh)*Q15>>16 = Q(gain_sh) sh = 9-gain_sh; //number of needed shifts to reach Q9 t16a = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32, sh); lat_outQ9[n + temp1] = t16a; } /* save the states */ for (i=0;i<ord_1;i++) { stateGQ15[i] = gQ15[i][HALF_SUBFRAMELEN-1]; } //process next frame } return; }
/* filter the signal using normalized lattice filter */ void WebRtcIsacfix_NormLatticeFilterAr(int16_t orderCoef, int16_t *stateGQ0, int32_t *lat_inQ25, int16_t *filt_coefQ15, int32_t *gain_lo_hiQ17, int16_t lo_hi, int16_t *lat_outQ0) { int ii,n,k,i,u; int16_t sthQ15[MAX_AR_MODEL_ORDER]; int16_t cthQ15[MAX_AR_MODEL_ORDER]; int32_t tmp32; int16_t tmpAR; int16_t ARfQ0vec[HALF_SUBFRAMELEN]; int16_t ARgQ0vec[MAX_AR_MODEL_ORDER+1]; int32_t inv_gain32; int16_t inv_gain16; int16_t den16; int16_t sh; int16_t temp2,temp3; int16_t ord_1 = orderCoef+1; for (u=0;u<SUBFRAMES;u++) { int32_t temp1 = WEBRTC_SPL_MUL_16_16(u, HALF_SUBFRAMELEN); //set the denominator and numerator of the Direct Form temp2 = (int16_t)WEBRTC_SPL_MUL_16_16(u, orderCoef); temp3 = (int16_t)WEBRTC_SPL_MUL_16_16(2, u) + lo_hi; for (ii=0; ii<orderCoef; ii++) { sthQ15[ii] = filt_coefQ15[temp2+ii]; } WebRtcSpl_SqrtOfOneMinusXSquared(sthQ15, orderCoef, cthQ15); /* Simulation of the 25 files shows that maximum value in the vector gain_lo_hiQ17[] is 441344, which means that it is log2((2^31)/441344) = 12.2 shifting bits from saturation. Therefore, it should be safe to use Q27 instead of Q17. */ tmp32 = WEBRTC_SPL_LSHIFT_W32(gain_lo_hiQ17[temp3], 10); // Q27 for (k=0;k<orderCoef;k++) { tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], tmp32); // Q15*Q27>>15 = Q27 } sh = WebRtcSpl_NormW32(tmp32); // tmp32 is the gain den16 = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32, sh-16); //Q(27+sh-16) = Q(sh+11) (all 16 bits are value bits) inv_gain32 = WebRtcSpl_DivW32W16((int32_t)2147483647, den16); // 1/gain in Q31/Q(sh+11) = Q(20-sh) //initial conditions inv_gain16 = (int16_t)(inv_gain32 >> 2); // 1/gain in Q(20-sh-2) = Q(18-sh) for (i=0;i<HALF_SUBFRAMELEN;i++) { tmp32 = WEBRTC_SPL_LSHIFT_W32(lat_inQ25[i + temp1], 1); //Q25->Q26 tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(inv_gain16, tmp32); //lat_in[]*inv_gain in (Q(18-sh)*Q26)>>16 = Q(28-sh) tmp32 = WEBRTC_SPL_SHIFT_W32(tmp32, -(28-sh)); // lat_in[]*inv_gain in Q0 ARfQ0vec[i] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 } for (i=orderCoef-1;i>=0;i--) //get the state of f&g for the first input, for all orders { tmp32 = (cthQ15[i] * ARfQ0vec[0] - sthQ15[i] * stateGQ0[i] + 16384) >> 15; tmpAR = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 tmp32 = (sthQ15[i] * ARfQ0vec[0] + cthQ15[i] * stateGQ0[i] + 16384) >> 15; ARgQ0vec[i+1] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 ARfQ0vec[0] = tmpAR; } ARgQ0vec[0] = ARfQ0vec[0]; // Filter ARgQ0vec[] and ARfQ0vec[] through coefficients cthQ15[] and sthQ15[]. WebRtcIsacfix_FilterArLoop(ARgQ0vec, ARfQ0vec, cthQ15, sthQ15, orderCoef); for(n=0;n<HALF_SUBFRAMELEN;n++) { lat_outQ0[n + temp1] = ARfQ0vec[n]; } /* cannot use memcpy in the following */ for (i=0;i<ord_1;i++) { stateGQ0[i] = ARgQ0vec[i]; } } return; }
void WebRtcIlbcfix_CbUpdateBestIndex( WebRtc_Word32 CritNew, /* (i) New Potentially best Criteria */ WebRtc_Word16 CritNewSh, /* (i) Shift value of above Criteria */ WebRtc_Word16 IndexNew, /* (i) Index of new Criteria */ WebRtc_Word32 cDotNew, /* (i) Cross dot of new index */ WebRtc_Word16 invEnergyNew, /* (i) Inversed energy new index */ WebRtc_Word16 energyShiftNew, /* (i) Energy shifts of new index */ WebRtc_Word32 *CritMax, /* (i/o) Maximum Criteria (so far) */ WebRtc_Word16 *shTotMax, /* (i/o) Shifts of maximum criteria */ WebRtc_Word16 *bestIndex, /* (i/o) Index that corresponds to maximum criteria */ WebRtc_Word16 *bestGain) /* (i/o) Gain in Q14 that corresponds to maximum criteria */ { WebRtc_Word16 shOld, shNew, tmp16; WebRtc_Word16 scaleTmp; WebRtc_Word32 gainW32; /* Normalize the new and old Criteria to the same domain */ if (CritNewSh>(*shTotMax)) { shOld=WEBRTC_SPL_MIN(31,CritNewSh-(*shTotMax)); shNew=0; } else { shOld=0; shNew=WEBRTC_SPL_MIN(31,(*shTotMax)-CritNewSh); } /* Compare the two criterias. If the new one is better, calculate the gain and store this index as the new best one */ if (WEBRTC_SPL_RSHIFT_W32(CritNew, shNew)> WEBRTC_SPL_RSHIFT_W32((*CritMax),shOld)) { tmp16 = (WebRtc_Word16)WebRtcSpl_NormW32(cDotNew); tmp16 = 16 - tmp16; /* Calculate the gain in Q14 Compensate for inverseEnergyshift in Q29 and that the energy value was stored in a WebRtc_Word16 (shifted down 16 steps) => 29-14+16 = 31 */ scaleTmp = -energyShiftNew-tmp16+31; scaleTmp = WEBRTC_SPL_MIN(31, scaleTmp); gainW32 = WEBRTC_SPL_MUL_16_16_RSFT( ((WebRtc_Word16)WEBRTC_SPL_SHIFT_W32(cDotNew, -tmp16)), invEnergyNew, scaleTmp); /* Check if criteria satisfies Gain criteria (max 1.3) if it is larger set the gain to 1.3 (slightly different from FLP version) */ if (gainW32>21299) { *bestGain=21299; } else if (gainW32<-21299) { *bestGain=-21299; } else { *bestGain=(WebRtc_Word16)gainW32; } *CritMax=CritNew; *shTotMax=CritNewSh; *bestIndex = IndexNew; } return; }
/* filter the signal using normalized lattice filter */ void WebRtcIsacfix_NormLatticeFilterAr(size_t orderCoef, int16_t *stateGQ0, int32_t *lat_inQ25, int16_t *filt_coefQ15, int32_t *gain_lo_hiQ17, int16_t lo_hi, int16_t *lat_outQ0) { size_t ii, k, i; int n, u; int16_t sthQ15[MAX_AR_MODEL_ORDER]; int16_t cthQ15[MAX_AR_MODEL_ORDER]; int32_t tmp32; int16_t tmpAR; int16_t ARfQ0vec[HALF_SUBFRAMELEN]; int16_t ARgQ0vec[MAX_AR_MODEL_ORDER+1]; int32_t inv_gain32; int16_t inv_gain16; int16_t den16; int16_t sh; int16_t temp2,temp3; size_t ord_1 = orderCoef+1; for (u=0;u<SUBFRAMES;u++) { int32_t temp1 = u * HALF_SUBFRAMELEN; //set the denominator and numerator of the Direct Form temp2 = (int16_t)(u * orderCoef); temp3 = (int16_t)(2 * u + lo_hi); for (ii=0; ii<orderCoef; ii++) { sthQ15[ii] = filt_coefQ15[temp2+ii]; } WebRtcSpl_SqrtOfOneMinusXSquared(sthQ15, orderCoef, cthQ15); // Originally, this line was assumed to never overflow, since "[s]imulation // of the 25 files shows that maximum value in the vector gain_lo_hiQ17[] // is 441344, which means that it is log2((2^31)/441344) = 12.2 shifting // bits from saturation. Therefore, it should be safe to use Q27 instead of // Q17." However, a fuzzer test succeeded in provoking an overflow here, // which we ignore on the theory that only "abnormal" inputs cause // overflow. tmp32 = OverflowingLShiftS32(gain_lo_hiQ17[temp3], 10); // Q27 for (k=0;k<orderCoef;k++) { tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], tmp32); // Q15*Q27>>15 = Q27 } sh = WebRtcSpl_NormW32(tmp32); // tmp32 is the gain den16 = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32, sh-16); //Q(27+sh-16) = Q(sh+11) (all 16 bits are value bits) inv_gain32 = WebRtcSpl_DivW32W16((int32_t)2147483647, den16); // 1/gain in Q31/Q(sh+11) = Q(20-sh) //initial conditions inv_gain16 = (int16_t)(inv_gain32 >> 2); // 1/gain in Q(20-sh-2) = Q(18-sh) for (i=0;i<HALF_SUBFRAMELEN;i++) { tmp32 = OverflowingLShiftS32(lat_inQ25[i + temp1], 1); // Q25->Q26 tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(inv_gain16, tmp32); //lat_in[]*inv_gain in (Q(18-sh)*Q26)>>16 = Q(28-sh) tmp32 = WEBRTC_SPL_SHIFT_W32(tmp32, -(28-sh)); // lat_in[]*inv_gain in Q0 ARfQ0vec[i] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 } // Get the state of f & g for the first input, for all orders. for (i = orderCoef; i > 0; i--) { tmp32 = (cthQ15[i - 1] * ARfQ0vec[0] - sthQ15[i - 1] * stateGQ0[i - 1] + 16384) >> 15; tmpAR = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 tmp32 = (sthQ15[i - 1] * ARfQ0vec[0] + cthQ15[i - 1] * stateGQ0[i - 1] + 16384) >> 15; ARgQ0vec[i] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0 ARfQ0vec[0] = tmpAR; } ARgQ0vec[0] = ARfQ0vec[0]; // Filter ARgQ0vec[] and ARfQ0vec[] through coefficients cthQ15[] and sthQ15[]. WebRtcIsacfix_FilterArLoop(ARgQ0vec, ARfQ0vec, cthQ15, sthQ15, orderCoef); for(n=0;n<HALF_SUBFRAMELEN;n++) { lat_outQ0[n + temp1] = ARfQ0vec[n]; } /* cannot use memcpy in the following */ for (i=0;i<ord_1;i++) { stateGQ0[i] = ARgQ0vec[i]; } } return; }