void WebRtcIlbcfix_InterpolateSamples( int16_t *interpSamples, /* (o) The interpolated samples */ int16_t *CBmem, /* (i) The CB memory */ int16_t lMem /* (i) Length of the CB memory */ ) { int16_t *ppi, *ppo, i, j, temp1, temp2; int16_t *tmpPtr; /* Calculate the 20 vectors of interpolated samples (4 samples each) that are used in the codebooks for lag 20 to 39 */ tmpPtr = interpSamples; for (j=0; j<20; j++) { temp1 = 0; temp2 = 3; ppo = CBmem+lMem-4; ppi = CBmem+lMem-j-24; for (i=0; i<4; i++) { *tmpPtr++ = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIlbcfix_kAlpha[temp2],*ppo, 15) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIlbcfix_kAlpha[temp1], *ppi, 15); ppo++; ppi++; temp1++; temp2--; } } return; }
WebRtc_Word32 WebRtcVad_GaussianProbability(WebRtc_Word16 in_sample, WebRtc_Word16 mean, WebRtc_Word16 std, WebRtc_Word16 *delta) { WebRtc_Word16 tmp16, tmpDiv, tmpDiv2, expVal, tmp16_1, tmp16_2; WebRtc_Word32 tmp32, y32; // Calculate tmpDiv=1/std, in Q10 tmp32 = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_W16(std,1) + (WebRtc_Word32)131072; // 1 in Q17 tmpDiv = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32, std); // Q17/Q7 = Q10 // Calculate tmpDiv2=1/std^2, in Q14 tmp16 = WEBRTC_SPL_RSHIFT_W16(tmpDiv, 2); // From Q10 to Q8 tmpDiv2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, tmp16, 2); // (Q8 * Q8)>>2 = Q14 tmp16 = WEBRTC_SPL_LSHIFT_W16(in_sample, 3); // Q7 tmp16 = tmp16 - mean; // Q7 - Q7 = Q7 // To be used later, when updating noise/speech model // delta = (x-m)/std^2, in Q11 *delta = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmpDiv2, tmp16, 10); //(Q14*Q7)>>10 = Q11 // Calculate tmp32=(x-m)^2/(2*std^2), in Q10 tmp32 = (WebRtc_Word32)WEBRTC_SPL_MUL_16_16_RSFT(*delta, tmp16, 9); // One shift for /2 // Calculate expVal ~= exp(-(x-m)^2/(2*std^2)) ~= exp2(-log2(exp(1))*tmp32) if (tmp32 < kCompVar) { // Calculate tmp16 = log2(exp(1))*tmp32 , in Q10 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)tmp32, kLog10Const, 12); tmp16 = -tmp16; tmp16_2 = (WebRtc_Word16)(0x0400 | (tmp16 & 0x03FF)); tmp16_1 = (WebRtc_Word16)(tmp16 ^ 0xFFFF); tmp16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(tmp16_1, 10); tmp16 += 1; // Calculate expVal=log2(-tmp32), in Q10 expVal = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)tmp16_2, tmp16); } else { expVal = 0; } // Calculate y32=(1/std)*exp(-(x-m)^2/(2*std^2)), in Q20 y32 = WEBRTC_SPL_MUL_16_16(tmpDiv, expVal); // Q10 * Q10 = Q20 return y32; // Q20 }
/* Autocorrelation function in fixed point. NOTE! Different from SPLIB-version in how it scales the signal. */ int WebRtcIsacfix_AutocorrFix( WebRtc_Word32 *r, const WebRtc_Word16 *x, WebRtc_Word16 N, WebRtc_Word16 order, WebRtc_Word16 *scale) { int j, i; WebRtc_Word16 scaling; WebRtc_Word32 sum, prod, newsum; G_CONST WebRtc_Word16 *xptr1; G_CONST WebRtc_Word16 *xptr2; sum=0; scaling=0; /* Calculate r[0] and how much scaling is needed */ for (i=0; i < N; i++) { prod = WEBRTC_SPL_MUL_16_16_RSFT(x[i],x[i],scaling); newsum = sum+prod; /* If sum gets less than 0 we have overflow and need to scale the signal */ if(newsum<0) { scaling++; sum=WEBRTC_SPL_RSHIFT_W32(sum, 1); prod=WEBRTC_SPL_RSHIFT_W32(prod, 1); } sum += prod; } r[0]=sum; /* Perform the actual correlation calculation */ for (i = 1; i < order + 1; i++) { int loops=(N-i); sum = 0; xptr1=(G_CONST WebRtc_Word16 *)x; xptr2=(G_CONST WebRtc_Word16 *)&x[i]; for (j = loops;j > 0; j--) { sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1++,*xptr2++,scaling); } r[i] = sum; } *scale = scaling; return(order + 1); }
void WebRtcIlbcfix_Lsp2Lsf( WebRtc_Word16 *lsp, /* (i) lsp vector -1...+1 in Q15 */ WebRtc_Word16 *lsf, /* (o) Lsf vector 0...Pi in Q13 (ordered, so that lsf[i]<lsf[i+1]) */ WebRtc_Word16 m /* (i) Number of coefficients */ ) { WebRtc_Word16 i, k; WebRtc_Word16 diff; /* diff between table value and desired value (Q15) */ WebRtc_Word16 freq; /* lsf/(2*pi) (Q16) */ WebRtc_Word16 *lspPtr, *lsfPtr, *cosTblPtr; WebRtc_Word16 tmp; /* set the index to maximum index value in WebRtcIlbcfix_kCos */ k = 63; /* Start with the highest LSP and then work the way down For each LSP the lsf is calculated by first order approximation of the acos(x) function */ lspPtr = &lsp[9]; lsfPtr = &lsf[9]; cosTblPtr=(WebRtc_Word16*)&WebRtcIlbcfix_kCos[k]; for(i=m-1; i>=0; i--) { /* locate value in the table, which is just above lsp[i], basically an approximation to acos(x) */ while( (((WebRtc_Word32)(*cosTblPtr)-(*lspPtr)) < 0)&&(k>0) ) { k-=1; cosTblPtr--; } /* Calculate diff, which is used in the linear approximation of acos(x) */ diff = (*lspPtr)-(*cosTblPtr); /* The linear approximation of acos(lsp[i]) : acos(lsp[i])= k*512 + (WebRtcIlbcfix_kAcosDerivative[ind]*offset >> 11) */ /* tmp (linear offset) in Q16 */ tmp = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIlbcfix_kAcosDerivative[k],diff, 11); /* freq in Q16 */ freq = (WebRtc_Word16)WEBRTC_SPL_LSHIFT_W16(k,9)+tmp; /* lsf = freq*2*pi */ (*lsfPtr) = (WebRtc_Word16)(((WebRtc_Word32)freq*25736)>>15); lsfPtr--; lspPtr--; } return; }
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
void WebRtcSpl_ElementwiseVectorMult(int16_t *out, const int16_t *in, const int16_t *win, int16_t vector_length, int16_t right_shifts) { int i; int16_t *outptr = out; const int16_t *inptr = in; const int16_t *winptr = win; for (i = 0; i < vector_length; i++) { (*outptr++) = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, *winptr++, right_shifts); } }
void WebRtcSpl_ElementwiseVectorMult(WebRtc_Word16 *out, G_CONST WebRtc_Word16 *in, G_CONST WebRtc_Word16 *win, WebRtc_Word16 vector_length, WebRtc_Word16 right_shifts) { int i; WebRtc_Word16 *outptr = out; G_CONST WebRtc_Word16 *inptr = in; G_CONST WebRtc_Word16 *winptr = win; for (i = 0; i < vector_length; i++) { (*outptr++) = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, *winptr++, right_shifts); } }
// Downsampling filter based on the splitting filter and the allpass functions // in vad_filterbank.c void WebRtcVad_Downsampling(WebRtc_Word16* signal_in, WebRtc_Word16* signal_out, WebRtc_Word32* filter_state, int inlen) { WebRtc_Word16 tmp16_1, tmp16_2; WebRtc_Word32 tmp32_1, tmp32_2; int n, halflen; // Downsampling by 2 and get two branches halflen = WEBRTC_SPL_RSHIFT_W16(inlen, 1); tmp32_1 = filter_state[0]; tmp32_2 = filter_state[1]; // Filter coefficients in Q13, filter state in Q0 for (n = 0; n < halflen; n++) { // All-pass filtering upper branch tmp16_1 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32_1, 1) + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((kAllPassCoefsQ13[0]), *signal_in, 14); *signal_out = tmp16_1; tmp32_1 = (WebRtc_Word32)(*signal_in++) - (WebRtc_Word32)WEBRTC_SPL_MUL_16_16_RSFT((kAllPassCoefsQ13[0]), tmp16_1, 12); // All-pass filtering lower branch tmp16_2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32_2, 1) + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((kAllPassCoefsQ13[1]), *signal_in, 14); *signal_out++ += tmp16_2; tmp32_2 = (WebRtc_Word32)(*signal_in++) - (WebRtc_Word32)WEBRTC_SPL_MUL_16_16_RSFT((kAllPassCoefsQ13[1]), tmp16_2, 12); } filter_state[0] = tmp32_1; filter_state[1] = tmp32_2; }
void WebRtcSpl_ReverseOrderMultArrayElements(int16_t *out, const int16_t *in, const int16_t *win, int16_t vector_length, int16_t right_shifts) { int i; int16_t *outptr = out; const int16_t *inptr = in; const int16_t *winptr = win; for (i = 0; i < vector_length; i++) { (*outptr++) = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, *winptr--, right_shifts); } }
int32_t WebRtcSpl_Energy(int16_t* vector, int vector_length, int* scale_factor) { int32_t en = 0; int i; int scaling = WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length); int looptimes = vector_length; int16_t *vectorptr = vector; for (i = 0; i < looptimes; i++) { en += WEBRTC_SPL_MUL_16_16_RSFT(*vectorptr, *vectorptr, scaling); vectorptr++; } *scale_factor = scaling; return en; }
void WebRtcIlbcfix_CbMemEnergyAugmentation( int16_t *interpSamples, /* (i) The interpolated samples */ int16_t *CBmem, /* (i) The CB memory */ int16_t scale, /* (i) The scaling of all energy values */ int16_t base_size, /* (i) Index to where the energy values should be stored */ int16_t *energyW16, /* (o) Energy in the CB vectors */ int16_t *energyShifts /* (o) Shift value of the energy */ ){ int32_t energy, tmp32; int16_t *ppe, *pp, *interpSamplesPtr; int16_t *CBmemPtr, lagcount; int16_t *enPtr=&energyW16[base_size-20]; int16_t *enShPtr=&energyShifts[base_size-20]; int32_t nrjRecursive; CBmemPtr = CBmem+147; interpSamplesPtr = interpSamples; /* Compute the energy for the first (low-5) noninterpolated samples */ nrjRecursive = WebRtcSpl_DotProductWithScale( CBmemPtr-19, CBmemPtr-19, 15, scale); ppe = CBmemPtr - 20; for (lagcount=20; lagcount<=39; lagcount++) { /* Update the energy recursively to save complexity */ nrjRecursive = nrjRecursive + WEBRTC_SPL_MUL_16_16_RSFT(*ppe, *ppe, scale); ppe--; energy = nrjRecursive; /* interpolation */ energy += WebRtcSpl_DotProductWithScale(interpSamplesPtr, interpSamplesPtr, 4, scale); interpSamplesPtr += 4; /* Compute energy for the remaining samples */ pp = CBmemPtr - lagcount; energy += WebRtcSpl_DotProductWithScale(pp, pp, SUBL-lagcount, scale); /* Normalize the energy and store the number of shifts */ (*enShPtr) = (int16_t)WebRtcSpl_NormW32(energy); tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, (*enShPtr)); (*enPtr) = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32, 16); enShPtr++; enPtr++; } }
// Noise Estimation static void NoiseEstimationNeon(NsxInst_t* inst, uint16_t* magn, uint32_t* noise, int16_t* q_noise) { int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv; int16_t countProd, delta, zeros, frac; int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2; const int16_t log2_const = 22713; const int16_t width_factor = 21845; int i, s, offset; tabind = inst->stages - inst->normData; assert(tabind < 9); assert(tabind > -9); if (tabind < 0) { logval = -WebRtcNsx_kLogTable[-tabind]; } else { logval = WebRtcNsx_kLogTable[tabind]; } int16x8_t logval_16x8 = vdupq_n_s16(logval); // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) // magn is in Q(-stages), and the real lmagn values are: // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) // lmagn in Q8 for (i = 0; i < inst->magnLen; i++) { if (magn[i]) { zeros = WebRtcSpl_NormU32((uint32_t)magn[i]); frac = (int16_t)((((uint32_t)magn[i] << zeros) & 0x7FFFFFFF) >> 23); assert(frac < 256); // log2(magn(i)) log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // log2(magn(i))*log(2) lmagn[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2_const, 15); // + log(2^stages) lmagn[i] += logval; } else { lmagn[i] = logval; } }
void WebRtcSpl_ReflCoefToLpc(const int16_t *k, int use_order, int16_t *a) { int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; int16_t *aptr, *aptr2, *anyptr; const int16_t *kptr; int m, i; kptr = k; *a = 4096; // i.e., (Word16_MAX >> 3)+1. *any = *a; a[1] = WEBRTC_SPL_RSHIFT_W16((*k), 3); for (m = 1; m < use_order; m++) { kptr++; aptr = a; aptr++; aptr2 = &a[m]; anyptr = any; anyptr++; any[m + 1] = WEBRTC_SPL_RSHIFT_W16((*kptr), 3); for (i = 0; i < m; i++) { *anyptr = (*aptr) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT((*aptr2), (*kptr), 15); anyptr++; aptr++; aptr2--; } aptr = a; anyptr = any; for (i = 0; i < (m + 2); i++) { *aptr = *anyptr; aptr++; anyptr++; } } }
void WebRtcIlbcfix_Lsf2Lsp( int16_t *lsf, /* (i) lsf in Q13 values between 0 and pi */ int16_t *lsp, /* (o) lsp in Q15 values between -1 and 1 */ int16_t m /* (i) number of coefficients */ ) { int16_t i, k; int16_t diff; /* difference, which is used for the linear approximation (Q8) */ int16_t freq; /* normalized frequency in Q15 (0..1) */ int32_t tmpW32; for(i=0; i<m; i++) { freq = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(lsf[i], 20861, 15); /* 20861: 1.0/(2.0*PI) in Q17 */ /* Upper 8 bits give the index k and Lower 8 bits give the difference, which needs to be approximated linearly */ k = WEBRTC_SPL_RSHIFT_W16(freq, 8); diff = (freq&0x00ff); /* Guard against getting outside table */ if (k>63) { k = 63; } /* Calculate linear approximation */ tmpW32 = WEBRTC_SPL_MUL_16_16(WebRtcIlbcfix_kCosDerivative[k], diff); lsp[i] = WebRtcIlbcfix_kCos[k]+(int16_t)(WEBRTC_SPL_RSHIFT_W32(tmpW32, 12)); } return; }
void WebRtcIsacfix_PitchFilter(int16_t* indatQQ, // Q10 if type is 1 or 4, // Q0 if type is 2. int16_t* outdatQQ, PitchFiltstr* pfp, int16_t* lagsQ7, int16_t* gainsQ12, int16_t type) { int k, ind, cnt; int16_t sign = 1; int16_t inystateQQ[PITCH_DAMPORDER]; int16_t ubufQQ[PITCH_INTBUFFSIZE + QLOOKAHEAD]; const int16_t Gain = 21299; // 1.3 in Q14 int16_t oldLagQ7; int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12; int indW32 = 0, frcQQ = 0; int32_t tmpW32; const int16_t* fracoeffQQ = NULL; // Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM(). COMPILE_ASSERT(PITCH_FRACORDER == 9); COMPILE_ASSERT(PITCH_DAMPORDER == 5); // Set up buffer and states. memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ)); memcpy(inystateQQ, pfp->ystateQQ, sizeof(inystateQQ)); // Get old lag and gain value from memory. oldLagQ7 = pfp->oldlagQ7; oldGainQ12 = pfp->oldgainQ12; if (type == 4) { sign = -1; // Make output more periodic. for (k = 0; k < PITCH_SUBFRAMES; k++) { gainsQ12[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( gainsQ12[k], Gain, 14); } } // No interpolation if pitch lag step is big. if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) || (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) { oldLagQ7 = lagsQ7[0]; oldGainQ12 = gainsQ12[0]; } ind = 0; for (k = 0; k < PITCH_SUBFRAMES; k++) { // Calculate interpolation steps. lagdeltaQ7 = lagsQ7[k] - oldLagQ7; lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( lagdeltaQ7, kDivFactor, 15); curLagQ7 = oldLagQ7; gaindeltaQ12 = gainsQ12[k] - oldGainQ12; gaindeltaQ12 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( gaindeltaQ12, kDivFactor, 15); curGainQ12 = oldGainQ12; oldLagQ7 = lagsQ7[k]; oldGainQ12 = gainsQ12[k]; // Each frame has 4 60-sample pitch subframes, and each subframe has 5 // 12-sample segments. Each segment need to be processed with // newly-updated parameters, so we break the pitch filtering into // two for-loops (5 x 12) below. It's also why kDivFactor = 0.2 (in Q15). for (cnt = 0; cnt < kSegments; cnt++) { // Update parameters for each segment. curGainQ12 += gaindeltaQ12; curLagQ7 += lagdeltaQ7; indW32 = CalcLrIntQ(curLagQ7, 7); tmpW32 = WEBRTC_SPL_LSHIFT_W32(indW32, 7); tmpW32 -= curLagQ7; frcQQ = WEBRTC_SPL_RSHIFT_W32(tmpW32, 4); frcQQ += 4; if (frcQQ == PITCH_FRACS) { frcQQ = 0; } fracoeffQQ = kIntrpCoef[frcQQ]; // Pitch filtering. WebRtcIsacfix_PitchFilterCore(PITCH_SUBFRAME_LEN / kSegments, curGainQ12, indW32, sign, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind); } } // Export buffer and states. memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ)); memcpy(pfp->ystateQQ, inystateQQ, sizeof(pfp->ystateQQ)); pfp->oldlagQ7 = oldLagQ7; pfp->oldgainQ12 = oldGainQ12; if (type == 2) { // Filter look-ahead segment. WebRtcIsacfix_PitchFilterCore(QLOOKAHEAD, curGainQ12, indW32, 1, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind); } }
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 {
static void PCorr2Q32(const int16_t *in, int32_t *logcorQ8) { int16_t scaling,n,k; int32_t ysum32,csum32, lys, lcs; int32_t oneQ8; const int16_t *x, *inptr; oneQ8 = WEBRTC_SPL_LSHIFT_W32((int32_t)1, 8); // 1.00 in Q8 x = in + PITCH_MAX_LAG/2 + 2; scaling = WebRtcSpl_GetScalingSquare ((int16_t *) in, PITCH_CORR_LEN2, PITCH_CORR_LEN2); ysum32 = 1; csum32 = 0; x = in + PITCH_MAX_LAG/2 + 2; for (n = 0; n < PITCH_CORR_LEN2; n++) { ysum32 += WEBRTC_SPL_MUL_16_16_RSFT( (int16_t) in[n],(int16_t) in[n], scaling); // Q0 csum32 += WEBRTC_SPL_MUL_16_16_RSFT((int16_t) x[n],(int16_t) in[n], scaling); // Q0 } logcorQ8 += PITCH_LAG_SPAN2 - 1; lys=Log2Q8((uint32_t) ysum32); // Q8 lys=WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum); if (csum32>0) { lcs=Log2Q8((uint32_t) csum32); // 2log(csum) in Q8 if (lcs>(lys + oneQ8) ){ // csum/sqrt(ysum) > 2 in Q8 *logcorQ8 = lcs - lys; // log2(csum/sqrt(ysum)) } else { *logcorQ8 = oneQ8; // 1.00 } } else { *logcorQ8 = 0; } for (k = 1; k < PITCH_LAG_SPAN2; k++) { inptr = &in[k]; ysum32 -= WEBRTC_SPL_MUL_16_16_RSFT( (int16_t) in[k-1],(int16_t) in[k-1], scaling); ysum32 += WEBRTC_SPL_MUL_16_16_RSFT( (int16_t) in[PITCH_CORR_LEN2 + k - 1],(int16_t) in[PITCH_CORR_LEN2 + k - 1], scaling); #ifdef WEBRTC_ARCH_ARM_NEON { int32_t vbuff[4]; int32x4_t int_32x4_sum = vmovq_n_s32(0); // Can't shift a Neon register to right with a non-constant shift value. int32x4_t int_32x4_scale = vdupq_n_s32(-scaling); // Assert a codition used in loop unrolling at compile-time. COMPILE_ASSERT(PITCH_CORR_LEN2 %4 == 0); for (n = 0; n < PITCH_CORR_LEN2; n += 4) { int16x4_t int_16x4_x = vld1_s16(&x[n]); int16x4_t int_16x4_in = vld1_s16(&inptr[n]); int32x4_t int_32x4 = vmull_s16(int_16x4_x, int_16x4_in); int_32x4 = vshlq_s32(int_32x4, int_32x4_scale); int_32x4_sum = vaddq_s32(int_32x4_sum, int_32x4); } // Use vector store to avoid long stall from data trasferring // from vector to general register. vst1q_s32(vbuff, int_32x4_sum); csum32 = vbuff[0] + vbuff[1]; csum32 += vbuff[2]; csum32 += vbuff[3]; } #else csum32 = 0; if(scaling == 0) { for (n = 0; n < PITCH_CORR_LEN2; n++) { csum32 += x[n] * inptr[n]; } } else { for (n = 0; n < PITCH_CORR_LEN2; n++) { csum32 += (x[n] * inptr[n]) >> scaling; } } #endif logcorQ8--; lys=Log2Q8((uint32_t)ysum32); // Q8 lys=WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum); if (csum32>0) { lcs=Log2Q8((uint32_t) csum32); // 2log(csum) in Q8 if (lcs>(lys + oneQ8) ){ // csum/sqrt(ysum) > 2 *logcorQ8 = lcs - lys; // log2(csum/sqrt(ysum)) } else { *logcorQ8 = oneQ8; // 1.00 } } else { *logcorQ8 = 0; } } }
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; }
void WebRtcIsacfix_InitialPitch(const int16_t *in, /* Q0 */ PitchAnalysisStruct *State, int16_t *lagsQ7 /* Q7 */ ) { int16_t buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; int32_t *crrvecQ8_1,*crrvecQ8_2; int32_t cv1q[PITCH_LAG_SPAN2+2],cv2q[PITCH_LAG_SPAN2+2], peakvq[PITCH_LAG_SPAN2+2]; int k; int16_t peaks_indq; int16_t peakiq[PITCH_LAG_SPAN2]; int32_t corr; int32_t corr32, corr_max32, corr_max_o32; int16_t npkq; int16_t best4q[4]={0,0,0,0}; int32_t xq[3],yq[1],fyq[1]; int32_t *fxq; int32_t best_lag1q, best_lag2q; int32_t tmp32a,tmp32b,lag32,ratq; int16_t start; int16_t oldgQ12, tmp16a, tmp16b, gain_bias16,tmp16c, tmp16d, bias16; int32_t tmp32c,tmp32d, tmp32e; int16_t old_lagQ; int32_t old_lagQ8; int32_t lagsQ8[4]; old_lagQ = State->PFstr_wght.oldlagQ7; // Q7 old_lagQ8= WEBRTC_SPL_LSHIFT_W32((int32_t)old_lagQ,1); //Q8 oldgQ12= State->PFstr_wght.oldgainQ12; crrvecQ8_1=&cv1q[1]; crrvecQ8_2=&cv2q[1]; /* copy old values from state buffer */ memcpy(buf_dec16, State->dec_buffer16, WEBRTC_SPL_MUL_16_16(sizeof(int16_t), (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2))); /* decimation; put result after the old values */ WebRtcIsacfix_DecimateAllpass32(in, State->decimator_state32, PITCH_FRAME_LEN, &buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); /* low-pass filtering */ start= PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; WebRtcSpl_FilterARFastQ12(&buf_dec16[start],&buf_dec16[start],(int16_t*)kACoefQ12,3, PITCH_FRAME_LEN/2); /* copy end part back into state buffer */ for (k = 0; k < (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2); k++) State->dec_buffer16[k] = buf_dec16[k+PITCH_FRAME_LEN/2]; /* compute correlation for first and second half of the frame */ PCorr2Q32(buf_dec16, crrvecQ8_1); PCorr2Q32(buf_dec16 + PITCH_CORR_STEP2, crrvecQ8_2); /* bias towards pitch lag of previous frame */ tmp32a = Log2Q8((uint32_t) old_lagQ8) - 2304; // log2(0.5*oldlag) in Q8 tmp32b = WEBRTC_SPL_MUL_16_16_RSFT(oldgQ12,oldgQ12, 10); //Q12 & * 4.0; gain_bias16 = (int16_t) tmp32b; //Q12 if (gain_bias16 > 3276) gain_bias16 = 3276; // 0.8 in Q12 for (k = 0; k < PITCH_LAG_SPAN2; k++) { if (crrvecQ8_1[k]>0) { tmp32b = Log2Q8((uint32_t) (k + (PITCH_MIN_LAG/2-2))); tmp16a = (int16_t) (tmp32b - tmp32a); // Q8 & fabs(ratio)<4 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(tmp16a,tmp16a, 6); //Q10 tmp16b = (int16_t) tmp32c; // Q10 & <8 tmp32d = WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 177 , 8); // mult with ln2 in Q8 tmp16c = (int16_t) tmp32d; // Q10 & <4 tmp16d = Exp2Q10((int16_t) -tmp16c); //Q10 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(gain_bias16,tmp16d,13); // Q10 & * 0.5 bias16 = (int16_t) (1024 + tmp32c); // Q10 tmp32b = Log2Q8((uint32_t) bias16) - 2560; // Q10 in -> Q8 out with 10*2^8 offset crrvecQ8_1[k] += tmp32b ; // -10*2^8 offset } } /* taper correlation functions */ for (k = 0; k < 3; k++) { crrvecQ8_1[k] += kLogLagWinQ8[k]; crrvecQ8_2[k] += kLogLagWinQ8[k]; crrvecQ8_1[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; crrvecQ8_2[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; } /* Make zeropadded corr vectors */ cv1q[0]=0; cv2q[0]=0; cv1q[PITCH_LAG_SPAN2+1]=0; cv2q[PITCH_LAG_SPAN2+1]=0; corr_max32 = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr32=crrvecQ8_1[k-1]; if (corr32 > corr_max32) corr_max32 = corr32; corr32=crrvecQ8_2[k-1]; corr32 += -4; // Compensate for later (log2(0.99)) if (corr32 > corr_max32) corr_max32 = corr32; } /* threshold value to qualify as a peak */ // corr_max32 += -726; // log(0.14)/log(2.0) in Q8 corr_max32 += -1000; // log(0.14)/log(2.0) in Q8 corr_max_o32 = corr_max32; /* find peaks in corr1 */ peaks_indq = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr32=cv1q[k]; if (corr32>corr_max32) { // Disregard small peaks if ((corr32>=cv1q[k-1]) && (corr32>cv1q[k+1])) { // Peak? peakvq[peaks_indq] = corr32; peakiq[peaks_indq++] = k; } } } /* find highest interpolated peak */ corr_max32=0; best_lag1q =0; if (peaks_indq > 0) { FindFour32(peakvq, (int16_t) peaks_indq, best4q); npkq = WEBRTC_SPL_MIN(peaks_indq, 4); for (k=0;k<npkq;k++) { lag32 = peakiq[best4q[k]]; fxq = &cv1q[peakiq[best4q[k]]-1]; xq[0]= lag32; xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); Intrp1DQ8(xq, fxq, yq, fyq); tmp32a= Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 /* Bias towards short lags */ /* log(pow(0.8, log(2.0 * *y )))/log(2.0) */ tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -42, 8); tmp32c= tmp32b + 256; *fyq += tmp32c; if (*fyq > corr_max32) { corr_max32 = *fyq; best_lag1q = *yq; } } tmp32a = best_lag1q - OFFSET_Q8; tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); lagsQ8[0] = tmp32b + PITCH_MIN_LAG_Q8; lagsQ8[1] = lagsQ8[0]; } else { lagsQ8[0] = old_lagQ8; lagsQ8[1] = lagsQ8[0]; } /* Bias towards constant pitch */ tmp32a = lagsQ8[0] - PITCH_MIN_LAG_Q8; ratq = WEBRTC_SPL_RSHIFT_W32(tmp32a, 1) + OFFSET_Q8; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { tmp32a = WEBRTC_SPL_LSHIFT_W32(k, 7); // 0.5*k Q8 tmp32b = (int32_t) (WEBRTC_SPL_LSHIFT_W32(tmp32a, 1)) - ratq; // Q8 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32b, (int16_t) tmp32b, 8); // Q8 tmp32b = (int32_t) tmp32c + (int32_t) WEBRTC_SPL_RSHIFT_W32(ratq, 1); // (k-r)^2 + 0.5 * r Q8 tmp32c = Log2Q8((uint32_t) tmp32a) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 tmp32d = Log2Q8((uint32_t) tmp32b) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 tmp32e = tmp32c -tmp32d; cv2q[k] += WEBRTC_SPL_RSHIFT_W32(tmp32e, 1); } /* find peaks in corr2 */ corr_max32 = corr_max_o32; peaks_indq = 0; for (k = 1; k <= PITCH_LAG_SPAN2; k++) { corr=cv2q[k]; if (corr>corr_max32) { // Disregard small peaks if ((corr>=cv2q[k-1]) && (corr>cv2q[k+1])) { // Peak? peakvq[peaks_indq] = corr; peakiq[peaks_indq++] = k; } } } /* find highest interpolated peak */ corr_max32 = 0; best_lag2q =0; if (peaks_indq > 0) { FindFour32(peakvq, (int16_t) peaks_indq, best4q); npkq = WEBRTC_SPL_MIN(peaks_indq, 4); for (k=0;k<npkq;k++) { lag32 = peakiq[best4q[k]]; fxq = &cv2q[peakiq[best4q[k]]-1]; xq[0]= lag32; xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); Intrp1DQ8(xq, fxq, yq, fyq); /* Bias towards short lags */ /* log(pow(0.8, log(2.0f * *y )))/log(2.0f) */ tmp32a= Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -82, 8); tmp32c= tmp32b + 256; *fyq += tmp32c; if (*fyq > corr_max32) { corr_max32 = *fyq; best_lag2q = *yq; } } tmp32a = best_lag2q - OFFSET_Q8; tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); lagsQ8[2] = tmp32b + PITCH_MIN_LAG_Q8; lagsQ8[3] = lagsQ8[2]; } else { lagsQ8[2] = lagsQ8[0]; lagsQ8[3] = lagsQ8[0]; } lagsQ7[0]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[0], 1); lagsQ7[1]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[1], 1); lagsQ7[2]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[2], 1); lagsQ7[3]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[3], 1); }
/* Uses 16x16 mul, without rounding, which is faster. Uses WEBRTC_SPL_MUL_16_16_RSFT */ int16_t WebRtcIsacfix_FftRadix16Fastest(int16_t RexQx[], int16_t ImxQx[], int16_t iSign) { int16_t dd, ee, ff, gg, hh, ii; int16_t k0, k1, k2, k3, k4, kk; int16_t tmp116, tmp216; int16_t ccc1Q14, ccc2Q14, ccc3Q14, sss1Q14, sss2Q14, sss3Q14; int16_t sss60Q14, ccc72Q14, sss72Q14; int16_t aaQx, ajQx, akQx, ajmQx, ajpQx, akmQx, akpQx; int16_t bbQx, bjQx, bkQx, bjmQx, bjpQx, bkmQx, bkpQx; int16_t ReDATAQx[240], ImDATAQx[240]; sss60Q14 = kCosTabFfftQ14[20]; ccc72Q14 = kCosTabFfftQ14[48]; sss72Q14 = kCosTabFfftQ14[12]; if (iSign < 0) { sss72Q14 = -sss72Q14; sss60Q14 = -sss60Q14; } /* Complexity is: 10 cycles */ /* compute fourier transform */ // transform for factor of 4 for (kk=0; kk<60; kk++) { k0 = kk; k1 = k0 + 60; k2 = k1 + 60; k3 = k2 + 60; akpQx = RexQx[k0] + RexQx[k2]; akmQx = RexQx[k0] - RexQx[k2]; ajpQx = RexQx[k1] + RexQx[k3]; ajmQx = RexQx[k1] - RexQx[k3]; bkpQx = ImxQx[k0] + ImxQx[k2]; bkmQx = ImxQx[k0] - ImxQx[k2]; bjpQx = ImxQx[k1] + ImxQx[k3]; bjmQx = ImxQx[k1] - ImxQx[k3]; RexQx[k0] = akpQx + ajpQx; ImxQx[k0] = bkpQx + bjpQx; ajpQx = akpQx - ajpQx; bjpQx = bkpQx - bjpQx; if (iSign < 0) { akpQx = akmQx + bjmQx; bkpQx = bkmQx - ajmQx; akmQx -= bjmQx; bkmQx += ajmQx; } else { akpQx = akmQx - bjmQx; bkpQx = bkmQx + ajmQx; akmQx += bjmQx; bkmQx -= ajmQx; } ccc1Q14 = kCosTabFfftQ14[kk]; ccc2Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(2, kk)]; ccc3Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(3, kk)]; sss1Q14 = kCosTabFfftQ14[kk+60]; sss2Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(2, kk)+60]; sss3Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(3, kk)+60]; if (iSign==1) { sss1Q14 = -sss1Q14; sss2Q14 = -sss2Q14; sss3Q14 = -sss3Q14; } //Do several multiplications like Q14*Q16>>14 = Q16 // RexQ16[k1] = akpQ16 * ccc1Q14 - bkpQ16 * sss1Q14; // RexQ16[k2] = ajpQ16 * ccc2Q14 - bjpQ16 * sss2Q14; // RexQ16[k3] = akmQ16 * ccc3Q14 - bkmQ16 * sss3Q14; // ImxQ16[k1] = akpQ16 * sss1Q14 + bkpQ16 * ccc1Q14; // ImxQ16[k2] = ajpQ16 * sss2Q14 + bjpQ16 * ccc2Q14; // ImxQ16[k3] = akmQ16 * sss3Q14 + bkmQ16 * ccc3Q14; RexQx[k1] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc1Q14, akpQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss1Q14, bkpQx, 14); // 6 non-mul + 2 mul cycles, i.e. 8 cycles (6+2*7=20 cycles if 16x32mul) RexQx[k2] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, ajpQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bjpQx, 14); RexQx[k3] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc3Q14, akmQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss3Q14, bkmQx, 14); ImxQx[k1] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss1Q14, akpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc1Q14, bkpQx, 14); ImxQx[k2] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, ajpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bjpQx, 14); ImxQx[k3] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss3Q14, akmQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc3Q14, bkmQx, 14); //This mul segment needs 6*8 = 48 cycles for 16x16 muls, but 6*20 = 120 cycles for 16x32 muls } /* Complexity is: 51+48 = 99 cycles for 16x16 muls, but 51+120 = 171 cycles for 16x32 muls*/ // transform for factor of 3 kk=0; k1=20; k2=40; for (hh=0; hh<4; hh++) { for (ii=0; ii<20; ii++) { akQx = RexQx[kk]; bkQx = ImxQx[kk]; ajQx = RexQx[k1] + RexQx[k2]; bjQx = ImxQx[k1] + ImxQx[k2]; RexQx[kk] = akQx + ajQx; ImxQx[kk] = bkQx + bjQx; tmp116 = WEBRTC_SPL_RSHIFT_W16(ajQx, 1); tmp216 = WEBRTC_SPL_RSHIFT_W16(bjQx, 1); akQx = akQx - tmp116; bkQx = bkQx - tmp216; tmp116 = RexQx[k1] - RexQx[k2]; tmp216 = ImxQx[k1] - ImxQx[k2]; ajQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss60Q14, tmp116, 14); // Q14*Qx>>14 = Qx bjQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss60Q14, tmp216, 14); // Q14*Qx>>14 = Qx RexQx[k1] = akQx - bjQx; RexQx[k2] = akQx + bjQx; ImxQx[k1] = bkQx + ajQx; ImxQx[k2] = bkQx - ajQx; kk++; k1++; k2++; } /* Complexity : (31+6)*20 = 740 cycles for 16x16 muls, but (31+18)*20 = 980 cycles for 16x32 muls*/ kk=kk+40; k1=k1+40; k2=k2+40; } /* Complexity : 4*(740+3) = 2972 cycles for 16x16 muls, but 4*(980+3) = 3932 cycles for 16x32 muls*/ /* multiply by rotation factor for odd factor 3 or 5 (not for 4) Same code (duplicated) for both ii=2 and ii=3 */ kk = 1; ee = 0; ff = 0; for (gg=0; gg<19; gg++) { kk += 20; ff = ff+4; for (hh=0; hh<2; hh++) { ee = ff + (int16_t)WEBRTC_SPL_MUL_16_16(hh, ff); dd = ee + 60; ccc2Q14 = kCosTabFfftQ14[ee]; sss2Q14 = kCosTabFfftQ14[dd]; if (iSign==1) { sss2Q14 = -sss2Q14; } for (ii=0; ii<4; ii++) { akQx = RexQx[kk]; bkQx = ImxQx[kk]; RexQx[kk] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akQx, 14) - // Q14*Qx>>14 = Qx (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkQx, 14); ImxQx[kk] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akQx, 14) + // Q14*Qx>>14 = Qx (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkQx, 14); kk += 60; } kk = kk - 220; } // Complexity: 2*(13+5+4*13+2) = 144 for 16x16 muls, but 2*(13+5+4*33+2) = 304 cycles for 16x32 muls kk = kk - 59; } // Complexity: 19*144 = 2736 for 16x16 muls, but 19*304 = 5776 cycles for 16x32 muls // transform for factor of 5 kk = 0; ccc2Q14 = kCosTabFfftQ14[96]; sss2Q14 = kCosTabFfftQ14[84]; if (iSign==1) { sss2Q14 = -sss2Q14; } for (hh=0; hh<4; hh++) { for (ii=0; ii<12; ii++) { k1 = kk + 4; k2 = k1 + 4; k3 = k2 + 4; k4 = k3 + 4; akpQx = RexQx[k1] + RexQx[k4]; akmQx = RexQx[k1] - RexQx[k4]; bkpQx = ImxQx[k1] + ImxQx[k4]; bkmQx = ImxQx[k1] - ImxQx[k4]; ajpQx = RexQx[k2] + RexQx[k3]; ajmQx = RexQx[k2] - RexQx[k3]; bjpQx = ImxQx[k2] + ImxQx[k3]; bjmQx = ImxQx[k2] - ImxQx[k3]; aaQx = RexQx[kk]; bbQx = ImxQx[kk]; RexQx[kk] = aaQx + akpQx + ajpQx; ImxQx[kk] = bbQx + bkpQx + bjpQx; akQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, akpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, ajpQx, 14) + aaQx; bkQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, bkpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bjpQx, 14) + bbQx; ajQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, akmQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, ajmQx, 14); bjQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, bkmQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bjmQx, 14); // 32+4*8=64 or 32+4*20=112 RexQx[k1] = akQx - bjQx; RexQx[k4] = akQx + bjQx; ImxQx[k1] = bkQx + ajQx; ImxQx[k4] = bkQx - ajQx; akQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, ajpQx, 14) + aaQx; bkQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkpQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, bjpQx, 14) + bbQx; ajQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akmQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, ajmQx, 14); bjQx = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkmQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, bjmQx, 14); // 8+4*8=40 or 8+4*20=88 RexQx[k2] = akQx - bjQx; RexQx[k3] = akQx + bjQx; ImxQx[k2] = bkQx + ajQx; ImxQx[k3] = bkQx - ajQx; kk = k4 + 4; } // Complexity: 12*(64+40+10) = 1368 for 16x16 muls, but 12*(112+88+10) = 2520 cycles for 16x32 muls kk -= 239; } // Complexity: 4*1368 = 5472 for 16x16 muls, but 4*2520 = 10080 cycles for 16x32 muls /* multiply by rotation factor for odd factor 3 or 5 (not for 4) Same code (duplicated) for both ii=2 and ii=3 */ kk = 1; ee=0; for (gg=0; gg<3; gg++) { kk += 4; dd = 12 + (int16_t)WEBRTC_SPL_MUL_16_16(12, gg); ff = 0; for (hh=0; hh<4; hh++) { ff = ff+dd; ee = ff+60; for (ii=0; ii<12; ii++) { akQx = RexQx[kk]; bkQx = ImxQx[kk]; ccc2Q14 = kCosTabFfftQ14[ff]; sss2Q14 = kCosTabFfftQ14[ee]; if (iSign==1) { sss2Q14 = -sss2Q14; } RexQx[kk] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akQx, 14) - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkQx, 14); ImxQx[kk] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akQx, 14) + (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkQx, 14); kk += 20; } kk = kk - 236; // Complexity: 12*(12+12) = 288 for 16x16 muls, but 12*(12+32) = 528 cycles for 16x32 muls } kk = kk - 19; // Complexity: 4*288+6 for 16x16 muls, but 4*528+6 cycles for 16x32 muls } // Complexity: 3*4*288+6 = 3462 for 16x16 muls, but 3*4*528+6 = 6342 cycles for 16x32 muls // last transform for factor of 4 */ for (kk=0; kk<240; kk=kk+4) { k1 = kk + 1; k2 = k1 + 1; k3 = k2 + 1; akpQx = RexQx[kk] + RexQx[k2]; akmQx = RexQx[kk] - RexQx[k2]; ajpQx = RexQx[k1] + RexQx[k3]; ajmQx = RexQx[k1] - RexQx[k3]; bkpQx = ImxQx[kk] + ImxQx[k2]; bkmQx = ImxQx[kk] - ImxQx[k2]; bjpQx = ImxQx[k1] + ImxQx[k3]; bjmQx = ImxQx[k1] - ImxQx[k3]; RexQx[kk] = akpQx + ajpQx; ImxQx[kk] = bkpQx + bjpQx; ajpQx = akpQx - ajpQx; bjpQx = bkpQx - bjpQx; if (iSign < 0) { akpQx = akmQx + bjmQx; bkpQx = bkmQx - ajmQx; akmQx -= bjmQx; bkmQx += ajmQx; } else { akpQx = akmQx - bjmQx; bkpQx = bkmQx + ajmQx; akmQx += bjmQx; bkmQx -= ajmQx; } RexQx[k1] = akpQx; RexQx[k2] = ajpQx; RexQx[k3] = akmQx; ImxQx[k1] = bkpQx; ImxQx[k2] = bjpQx; ImxQx[k3] = bkmQx; } // Complexity: 60*45 = 2700 for 16x16 muls, but 60*45 = 2700 cycles for 16x32 muls /* permute the results to normal order */ for (ii=0; ii<240; ii++) { ReDATAQx[ii]=RexQx[ii]; ImDATAQx[ii]=ImxQx[ii]; } // Complexity: 240*2=480 cycles for (ii=0; ii<240; ii++) { RexQx[ii]=ReDATAQx[kSortTabFft[ii]]; ImxQx[ii]=ImDATAQx[kSortTabFft[ii]]; } // Complexity: 240*2*2=960 cycles // Total complexity: // 16x16 16x32 // Complexity: 10 10 // Complexity: 99 171 // Complexity: 2972 3932 // Complexity: 2736 5776 // Complexity: 5472 10080 // Complexity: 3462 6342 // Complexity: 2700 2700 // Complexity: 480 480 // Complexity: 960 960 // ======================= // 18891 30451 // // If this FFT is called 2 time each frame, i.e. 67 times per second, it will correspond to // a C54 complexity of 67*18891/1000000 = 1.27 MIPS with 16x16-muls, and 67*30451/1000000 = // = 2.04 MIPS with 16x32-muls. Note that this routine somtimes is called 6 times during the // encoding of a frame, i.e. the max complexity would be 7/2*1.27 = 4.4 MIPS for the 16x16 mul case. return 0; }
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; }
int WebRtcSpl_ComplexIFFT(WebRtc_Word16 frfi[], int stages, int mode) { int i, j, l, k, istep, n, m, scale, shift; WebRtc_Word16 wr, wi; WebRtc_Word32 tr32, ti32, qr32, qi32; WebRtc_Word32 tmp32, round2; /* The 1024-value is a constant given from the size of WebRtcSpl_kSinTable1024[], * and should not be changed depending on the input parameter 'stages' */ n = 1 << stages; if (n > 1024) return -1; scale = 0; l = 1; k = 10 - 1; /* Constant for given WebRtcSpl_kSinTable1024[]. Do not change depending on the input parameter 'stages' */ while (l < n) { // variable scaling, depending upon data shift = 0; round2 = 8192; tmp32 = (WebRtc_Word32)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); if (tmp32 > 13573) { shift++; scale++; round2 <<= 1; } if (tmp32 > 27146) { shift++; scale++; round2 <<= 1; } istep = l << 1; if (mode == 0) { // mode==0: Low-complexity and Low-accuracy mode for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * WebRtcSpl_kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = WebRtcSpl_kSinTable1024[j + 256]; wi = WebRtcSpl_kSinTable1024[j]; for (i = m; i < n; i += istep) { j = i + l; tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0) - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15); ti32 = WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0) + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15); qr32 = (WebRtc_Word32)frfi[2 * i]; qi32 = (WebRtc_Word32)frfi[2 * i + 1]; frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift); frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift); frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift); frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift); } } } else { // mode==1: High-complexity and High-accuracy mode for (m = 0; m < l; ++m) { j = m << k; /* The 256-value is a constant given as 1/4 of the size of * WebRtcSpl_kSinTable1024[], and should not be changed depending on the input * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 */ wr = WebRtcSpl_kSinTable1024[j + 256]; wi = WebRtcSpl_kSinTable1024[j]; for (i = m; i < n; i += istep) { j = i + l; tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0) - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0) + CIFFTRND), 15 - CIFFTSFT); ti32 = WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0) + WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j], 0) + CIFFTRND), 15 - CIFFTSFT); qr32 = ((WebRtc_Word32)frfi[2 * i]) << CIFFTSFT; qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CIFFTSFT; frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2), shift+CIFFTSFT); frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( (qi32 - ti32 + round2), shift + CIFFTSFT); frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2), shift + CIFFTSFT); frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( (qi32 + ti32 + round2), shift + CIFFTSFT); } } } --k; l = istep; } return scale; }
// 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 } } } } }
int WebRtcIsacfix_EncodeImpl(int16_t *in, ISACFIX_EncInst_t *ISACenc_obj, BwEstimatorstr *bw_estimatordata, int16_t CodingMode) { int16_t stream_length = 0; int16_t usefulstr_len = 0; int k; int16_t BWno; int16_t lofilt_coefQ15[(ORDERLO)*SUBFRAMES]; int16_t hifilt_coefQ15[(ORDERHI)*SUBFRAMES]; int32_t gain_lo_hiQ17[2*SUBFRAMES]; int16_t LPandHP[FRAMESAMPLES/2 + QLOOKAHEAD]; int16_t LP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; int16_t HP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; int16_t PitchLags_Q7[PITCH_SUBFRAMES]; int16_t PitchGains_Q12[PITCH_SUBFRAMES]; int16_t AvgPitchGain_Q12; int16_t frame_mode; /* 0 for 30ms, 1 for 60ms */ int16_t processed_samples; int status; int32_t bits_gainsQ11; int16_t MinBytes; int16_t bmodel; transcode_obj transcodingParam; int16_t payloadLimitBytes; int16_t arithLenBeforeEncodingDFT; int16_t iterCntr; /* copy new frame length and bottle neck rate only for the first 10 ms data */ if (ISACenc_obj->buffer_index == 0) { /* set the framelength for the next packet */ ISACenc_obj->current_framesamples = ISACenc_obj->new_framelength; } frame_mode = ISACenc_obj->current_framesamples/MAX_FRAMESAMPLES; /* 0 (30 ms) or 1 (60 ms) */ processed_samples = ISACenc_obj->current_framesamples/(frame_mode+1); /* 480 (30, 60 ms) */ /* buffer speech samples (by 10ms packet) until the framelength is reached (30 or 60 ms) */ /**************************************************************************************/ /* fill the buffer with 10ms input data */ for(k=0; k<FRAMESAMPLES_10ms; k++) { ISACenc_obj->data_buffer_fix[k + ISACenc_obj->buffer_index] = in[k]; } /* if buffersize is not equal to current framesize, and end of file is not reached yet, */ /* increase index and go back to main to get more speech samples */ if (ISACenc_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) { ISACenc_obj->buffer_index = ISACenc_obj->buffer_index + FRAMESAMPLES_10ms; return 0; } /* if buffer reached the right size, reset index and continue with encoding the frame */ ISACenc_obj->buffer_index = 0; /* end of buffer function */ /**************************/ /* encoding */ /************/ if (frame_mode == 0 || ISACenc_obj->frame_nb == 0 ) { /* reset bitstream */ ISACenc_obj->bitstr_obj.W_upper = 0xFFFFFFFF; ISACenc_obj->bitstr_obj.streamval = 0; ISACenc_obj->bitstr_obj.stream_index = 0; ISACenc_obj->bitstr_obj.full = 1; if (CodingMode == 0) { ISACenc_obj->BottleNeck = WebRtcIsacfix_GetUplinkBandwidth(bw_estimatordata); ISACenc_obj->MaxDelay = WebRtcIsacfix_GetUplinkMaxDelay(bw_estimatordata); } if (CodingMode == 0 && frame_mode == 0 && (ISACenc_obj->enforceFrameSize == 0)) { ISACenc_obj->new_framelength = WebRtcIsacfix_GetNewFrameLength(ISACenc_obj->BottleNeck, ISACenc_obj->current_framesamples); } // multiply the bottleneck by 0.88 before computing SNR, 0.88 is tuned by experimenting on TIMIT // 901/1024 is 0.87988281250000 ISACenc_obj->s2nr = WebRtcIsacfix_GetSnr((int16_t)WEBRTC_SPL_MUL_16_16_RSFT(ISACenc_obj->BottleNeck, 901, 10), ISACenc_obj->current_framesamples); /* encode frame length */ status = WebRtcIsacfix_EncodeFrameLen(ISACenc_obj->current_framesamples, &ISACenc_obj->bitstr_obj); if (status < 0) { /* Wrong frame size */ if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } /* Save framelength for multiple packets memory */ if (ISACenc_obj->SaveEnc_ptr != NULL) { (ISACenc_obj->SaveEnc_ptr)->framelength=ISACenc_obj->current_framesamples; } /* bandwidth estimation and coding */ BWno = WebRtcIsacfix_GetDownlinkBwIndexImpl(bw_estimatordata); status = WebRtcIsacfix_EncodeReceiveBandwidth(&BWno, &ISACenc_obj->bitstr_obj); if (status < 0) { if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } } /* split signal in two bands */ WebRtcIsacfix_SplitAndFilter1(ISACenc_obj->data_buffer_fix, LP16a, HP16a, &ISACenc_obj->prefiltbankstr_obj ); /* estimate pitch parameters and pitch-filter lookahead signal */ WebRtcIsacfix_PitchAnalysis(LP16a+QLOOKAHEAD, LPandHP, &ISACenc_obj->pitchanalysisstr_obj, PitchLags_Q7, PitchGains_Q12); /* LPandHP = LP_lookahead_pfQ0, */ /* Set where to store data in multiple packets memory */ if (ISACenc_obj->SaveEnc_ptr != NULL) { if (frame_mode == 0 || ISACenc_obj->frame_nb == 0) { (ISACenc_obj->SaveEnc_ptr)->startIdx = 0; } else { (ISACenc_obj->SaveEnc_ptr)->startIdx = 1; } } /* quantize & encode pitch parameters */ status = WebRtcIsacfix_EncodePitchGain(PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); if (status < 0) { if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } status = WebRtcIsacfix_EncodePitchLag(PitchLags_Q7 , PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); if (status < 0) { if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } AvgPitchGain_Q12 = WEBRTC_SPL_RSHIFT_W32(PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3], 2); /* find coefficients for perceptual pre-filters */ WebRtcIsacfix_GetLpcCoef(LPandHP, HP16a+QLOOKAHEAD, &ISACenc_obj->maskfiltstr_obj, ISACenc_obj->s2nr, PitchGains_Q12, gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15); /*LPandHP = LP_lookahead_pfQ0*/ // record LPC Gains for possible bit-rate reduction for(k = 0; k < KLT_ORDER_GAIN; k++) { transcodingParam.lpcGains[k] = gain_lo_hiQ17[k]; } /* code LPC model and shape - gains not quantized yet */ status = WebRtcIsacfix_EncodeLpc(gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15, &bmodel, &bits_gainsQ11, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr, &transcodingParam); if (status < 0) { if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } arithLenBeforeEncodingDFT = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full); /* low-band filtering */ WebRtcIsacfix_NormLatticeFilterMa(ORDERLO, ISACenc_obj->maskfiltstr_obj.PreStateLoGQ15, LP16a, lofilt_coefQ15, gain_lo_hiQ17, 0, LPandHP);/* LPandHP = LP16b */ /* pitch filter */ WebRtcIsacfix_PitchFilter(LPandHP, LP16a, &ISACenc_obj->pitchfiltstr_obj, PitchLags_Q7, PitchGains_Q12, 1);/* LPandHP = LP16b */ /* high-band filtering */ WebRtcIsacfix_NormLatticeFilterMa(ORDERHI, ISACenc_obj->maskfiltstr_obj.PreStateHiGQ15, HP16a, hifilt_coefQ15, gain_lo_hiQ17, 1, LPandHP);/*LPandHP = HP16b*/ /* transform */ WebRtcIsacfix_Time2Spec(LP16a, LPandHP, LP16a, LPandHP); /*LPandHP = HP16b*/ /* Save data for multiple packets memory */ if (ISACenc_obj->SaveEnc_ptr != NULL) { for (k = 0; k < FRAMESAMPLES_HALF; k++) { (ISACenc_obj->SaveEnc_ptr)->fre[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LP16a[k]; (ISACenc_obj->SaveEnc_ptr)->fim[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LPandHP[k]; } (ISACenc_obj->SaveEnc_ptr)->AvgPitchGain[(ISACenc_obj->SaveEnc_ptr)->startIdx] = AvgPitchGain_Q12; } /* quantization and lossless coding */ status = WebRtcIsacfix_EncodeSpec(LP16a, LPandHP, &ISACenc_obj->bitstr_obj, AvgPitchGain_Q12); if((status <= -1) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) /*LPandHP = HP16b*/ { if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) { // If this is the second 30ms of a 60ms frame reset this such that in the next call // encoder starts fresh. ISACenc_obj->frame_nb = 0; } return status; } if((frame_mode == 1) && (ISACenc_obj->frame_nb == 0)) { // it is a 60ms and we are in the first 30ms // then the limit at this point should be half of the assigned value payloadLimitBytes = ISACenc_obj->payloadLimitBytes60 >> 1; }
int16_t WebRtcIsacfix_DecodeImpl(int16_t *signal_out16, ISACFIX_DecInst_t *ISACdec_obj, int16_t *current_framesamples) { int k; int err; int16_t BWno; int16_t len = 0; int16_t model; int16_t Vector_Word16_1[FRAMESAMPLES/2]; int16_t Vector_Word16_2[FRAMESAMPLES/2]; int32_t Vector_Word32_1[FRAMESAMPLES/2]; int32_t Vector_Word32_2[FRAMESAMPLES/2]; int16_t lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs int16_t hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs int32_t gain_lo_hiQ17[2*SUBFRAMES]; int16_t PitchLags_Q7[PITCH_SUBFRAMES]; int16_t PitchGains_Q12[PITCH_SUBFRAMES]; int16_t AvgPitchGain_Q12; int16_t tmp_1, tmp_2; int32_t tmp32a, tmp32b; int16_t gainQ13; int16_t frame_nb; /* counter */ int16_t frame_mode; /* 0 for 20ms and 30ms, 1 for 60ms */ int16_t processed_samples; /* PLC */ int16_t overlapWin[ 240 ]; (ISACdec_obj->bitstr_obj).W_upper = 0xFFFFFFFF; (ISACdec_obj->bitstr_obj).streamval = 0; (ISACdec_obj->bitstr_obj).stream_index = 0; (ISACdec_obj->bitstr_obj).full = 1; /* decode framelength and BW estimation - not used, only for stream pointer*/ err = WebRtcIsacfix_DecodeFrameLen(&ISACdec_obj->bitstr_obj, current_framesamples); if (err<0) // error check return err; frame_mode = (int16_t)WEBRTC_SPL_DIV(*current_framesamples, MAX_FRAMESAMPLES); /* 0, or 1 */ processed_samples = (int16_t)WEBRTC_SPL_DIV(*current_framesamples, frame_mode+1); /* either 320 (20ms) or 480 (30, 60 ms) */ err = WebRtcIsacfix_DecodeSendBandwidth(&ISACdec_obj->bitstr_obj, &BWno); if (err<0) // error check return err; /* one loop if it's one frame (20 or 30ms), 2 loops if 2 frames bundled together (60ms) */ for (frame_nb = 0; frame_nb <= frame_mode; frame_nb++) { /* decode & dequantize pitch parameters */ err = WebRtcIsacfix_DecodePitchGain(&(ISACdec_obj->bitstr_obj), PitchGains_Q12); if (err<0) // error check return err; err = WebRtcIsacfix_DecodePitchLag(&ISACdec_obj->bitstr_obj, PitchGains_Q12, PitchLags_Q7); if (err<0) // error check return err; AvgPitchGain_Q12 = (int16_t)(((int32_t)PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3])>>2); /* decode & dequantize FiltCoef */ err = WebRtcIsacfix_DecodeLpc(gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15, &ISACdec_obj->bitstr_obj, &model); if (err<0) // error check return err; /* decode & dequantize spectrum */ len = WebRtcIsacfix_DecodeSpec(&ISACdec_obj->bitstr_obj, Vector_Word16_1, Vector_Word16_2, AvgPitchGain_Q12); if (len < 0) // error check return len; // Why does this need Q16 in and out? /JS WebRtcIsacfix_Spec2Time(Vector_Word16_1, Vector_Word16_2, Vector_Word32_1, Vector_Word32_2); for (k=0; k<FRAMESAMPLES/2; k++) { Vector_Word16_1[k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(Vector_Word32_1[k]+64, 7); //Q16 -> Q9 } /* ---- If this is recovery frame ---- */ if( (ISACdec_obj->plcstr_obj).used == PLC_WAS_USED ) { (ISACdec_obj->plcstr_obj).used = PLC_NOT_USED; if( (ISACdec_obj->plcstr_obj).B < 1000 ) { (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 4000; } ISACdec_obj->plcstr_obj.decayCoeffPriodic = WEBRTC_SPL_WORD16_MAX; /* DECAY_RATE is in Q15 */ ISACdec_obj->plcstr_obj.decayCoeffNoise = WEBRTC_SPL_WORD16_MAX; /* DECAY_RATE is in Q15 */ ISACdec_obj->plcstr_obj.pitchCycles = 0; PitchGains_Q12[0] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(PitchGains_Q12[0], 700, 10 ); /* ---- Add-overlap ---- */ WebRtcSpl_GetHanningWindow( overlapWin, RECOVERY_OVERLAP ); for( k = 0; k < RECOVERY_OVERLAP; k++ ) Vector_Word16_1[k] = WebRtcSpl_AddSatW16( (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( (ISACdec_obj->plcstr_obj).overlapLP[k], overlapWin[RECOVERY_OVERLAP - k - 1], 14), (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( Vector_Word16_1[k], overlapWin[k], 14) ); } /* --- Store side info --- */ if( frame_nb == frame_mode ) { /* --- LPC info */ WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).lofilt_coefQ15, &lofilt_coefQ15[(SUBFRAMES-1)*ORDERLO], ORDERLO ); WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).hifilt_coefQ15, &hifilt_coefQ15[(SUBFRAMES-1)*ORDERHI], ORDERHI ); (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0] = gain_lo_hiQ17[(SUBFRAMES-1) * 2]; (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1] = gain_lo_hiQ17[(SUBFRAMES-1) * 2 + 1]; /* --- LTP info */ (ISACdec_obj->plcstr_obj).AvgPitchGain_Q12 = PitchGains_Q12[3]; (ISACdec_obj->plcstr_obj).lastPitchGain_Q12 = PitchGains_Q12[3]; (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 = PitchLags_Q7[3]; if( PitchLags_Q7[3] < 3000 ) (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 += PitchLags_Q7[3]; WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).prevPitchInvIn, Vector_Word16_1, FRAMESAMPLES/2 ); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* inverse pitch filter */ WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2, &ISACdec_obj->pitchfiltstr_obj, PitchLags_Q7, PitchGains_Q12, 4); if( frame_nb == frame_mode ) { WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).prevPitchInvOut, &(Vector_Word16_2[FRAMESAMPLES/2 - (PITCH_MAX_LAG + 10)]), PITCH_MAX_LAG ); } /* reduce gain to compensate for pitch enhancer */ /* gain = 1.0f - 0.45f * AvgPitchGain; */ tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(AvgPitchGain_Q12, 29, 0); // Q18 tmp32b = 262144 - tmp32a; // Q18 gainQ13 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q13 for (k = 0; k < FRAMESAMPLES/2; k++) { Vector_Word32_1[k] = (int32_t) WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(Vector_Word16_2[k], gainQ13), 3); // Q25 } /* perceptual post-filtering (using normalized lattice filter) */ WebRtcIsacfix_NormLatticeFilterAr(ORDERLO, (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0, Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1); /* --- Store Highpass Residual --- */ for (k = 0; k < FRAMESAMPLES/2; k++) Vector_Word32_1[k] = WEBRTC_SPL_LSHIFT_W32(Vector_Word32_2[k], 9); // Q16 -> Q25 for( k = 0; k < PITCH_MAX_LAG + 10; k++ ) (ISACdec_obj->plcstr_obj).prevHP[k] = Vector_Word32_1[FRAMESAMPLES/2 - (PITCH_MAX_LAG + 10) + k]; WebRtcIsacfix_NormLatticeFilterAr(ORDERHI, (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0, Vector_Word32_1, 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/2;k++) { tmp_1 = (int16_t)WebRtcSpl_SatW32ToW16(((int32_t)Vector_Word16_1[k]+Vector_Word16_2[k] + 1)); /* Construct a new upper channel signal*/ tmp_2 = (int16_t)WebRtcSpl_SatW32ToW16(((int32_t)Vector_Word16_1[k]-Vector_Word16_2[k])); /* Construct a new lower channel signal*/ Vector_Word16_1[k] = tmp_1; Vector_Word16_2[k] = tmp_2; } WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1, Vector_Word16_2, signal_out16 + frame_nb * processed_samples, &ISACdec_obj->postfiltbankstr_obj); } return len; }
void WebRtcIsacfix_PitchFilterGains(const int16_t* indatQ0, PitchFiltstr* pfp, int16_t* lagsQ7, int16_t* gainsQ12) { int k, n, m, ind, pos, pos3QQ; int16_t ubufQQ[PITCH_INTBUFFSIZE]; int16_t oldLagQ7, lagdeltaQ7, curLagQ7; const int16_t* fracoeffQQ = NULL; int16_t scale; int16_t cnt = 0, frcQQ, indW16 = 0, tmpW16; int32_t tmpW32, tmp2W32, csum1QQ, esumxQQ; // Set up buffer and states. memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ)); oldLagQ7 = pfp->oldlagQ7; // No interpolation if pitch lag step is big. if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) || (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) { oldLagQ7 = lagsQ7[0]; } ind = 0; pos = ind + PITCH_BUFFSIZE; scale = 0; for (k = 0; k < PITCH_SUBFRAMES; k++) { // Calculate interpolation steps. lagdeltaQ7 = lagsQ7[k] - oldLagQ7; lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( lagdeltaQ7, kDivFactor, 15); curLagQ7 = oldLagQ7; oldLagQ7 = lagsQ7[k]; csum1QQ = 1; esumxQQ = 1; // Same as function WebRtcIsacfix_PitchFilter(), we break the pitch // filtering into two for-loops (5 x 12) below. for (cnt = 0; cnt < kSegments; cnt++) { // Update parameters for each segment. curLagQ7 += lagdeltaQ7; indW16 = (int16_t)CalcLrIntQ(curLagQ7, 7); tmpW16 = WEBRTC_SPL_LSHIFT_W16(indW16, 7); tmpW16 -= curLagQ7; frcQQ = WEBRTC_SPL_RSHIFT_W16(tmpW16, 4); frcQQ += 4; if (frcQQ == PITCH_FRACS) { frcQQ = 0; } fracoeffQQ = kIntrpCoef[frcQQ]; pos3QQ = pos - (indW16 + 4); for (n = 0; n < PITCH_SUBFRAME_LEN / kSegments; n++) { // Filter to get fractional pitch. tmpW32 = 0; for (m = 0; m < PITCH_FRACORDER; m++) { tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos3QQ + m], fracoeffQQ[m]); } // Subtract from input and update buffer. ubufQQ[pos] = indatQ0[ind]; tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32); tmpW32 += 8192; tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14); tmpW32 = WEBRTC_SPL_MUL_16_16(tmpW16, tmpW16); if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) || (tmpW32 > 1073700000) || (esumxQQ > 1073700000)) { // 2^30 scale++; csum1QQ = WEBRTC_SPL_RSHIFT_W32(csum1QQ, 1); esumxQQ = WEBRTC_SPL_RSHIFT_W32(esumxQQ, 1); } tmp2W32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, scale); csum1QQ += tmp2W32; tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmpW32, scale); esumxQQ += tmpW32; ind++; pos++; pos3QQ++; } } if (csum1QQ < esumxQQ) { tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ); // Gain should be half the correlation. tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, 20); } else { tmpW32 = 4096; } gainsQ12[k] = (int16_t)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0); } // Export buffer and states. memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ)); pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES - 1]; pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES - 1]; }
void WebRtcIsacfix_GetVars(const WebRtc_Word16 *input, const WebRtc_Word16 *pitchGains_Q12, WebRtc_UWord32 *oldEnergy, WebRtc_Word16 *varscale) { int k; WebRtc_UWord32 nrgQ[4]; WebRtc_Word16 nrgQlog[4]; WebRtc_Word16 tmp16, chng1, chng2, chng3, chng4, tmp, chngQ, oldNrgQlog, pgQ, pg3; WebRtc_Word32 expPg32; WebRtc_Word16 expPg, divVal; WebRtc_Word16 tmp16_1, tmp16_2; /* Calculate energies of first and second frame halfs */ nrgQ[0]=0; for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES/4 + QLOOKAHEAD) / 2; k++) { nrgQ[0] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[1]=0; for ( ; k < (FRAMESAMPLES/2 + QLOOKAHEAD) / 2; k++) { nrgQ[1] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[2]=0; for ( ; k < (WEBRTC_SPL_MUL_16_16(FRAMESAMPLES, 3)/4 + QLOOKAHEAD) / 2; k++) { nrgQ[2] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } nrgQ[3]=0; for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { nrgQ[3] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); } for ( k=0; k<4; k++) { nrgQlog[k] = (WebRtc_Word16)log2_Q8_LPC(nrgQ[k]); /* log2(nrgQ) */ } oldNrgQlog = (WebRtc_Word16)log2_Q8_LPC(*oldEnergy); /* Calculate average level change */ chng1 = WEBRTC_SPL_ABS_W16(nrgQlog[3]-nrgQlog[2]); chng2 = WEBRTC_SPL_ABS_W16(nrgQlog[2]-nrgQlog[1]); chng3 = WEBRTC_SPL_ABS_W16(nrgQlog[1]-nrgQlog[0]); chng4 = WEBRTC_SPL_ABS_W16(nrgQlog[0]-oldNrgQlog); tmp = chng1+chng2+chng3+chng4; chngQ = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp, kChngFactor, 10); /* Q12 */ chngQ += 2926; /* + 1.0/1.4 in Q12 */ /* Find average pitch gain */ pgQ = 0; for (k=0; k<4; k++) { pgQ += pitchGains_Q12[k]; } pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pgQ,11); /* pgQ in Q(12+2)=Q14. Q14*Q14>>11 => Q17 */ pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pg3,13); /* Q17*Q14>>13 =>Q18 */ pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pg3, kMulPitchGain ,5); /* Q10 kMulPitchGain = -25 = -200 in Q-3. */ tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,pg3,13);/* Q13*Q10>>13 => Q10*/ if (tmp16<0) { tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ if (tmp16_1<0) expPg=(WebRtc_Word16) -WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); else expPg=(WebRtc_Word16) -WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); } else expPg = (WebRtc_Word16) -16384; /* 1 in Q14, since 2^0=1 */ expPg32 = (WebRtc_Word32)WEBRTC_SPL_LSHIFT_W16((WebRtc_Word32)expPg, 8); /* Q22 */ divVal = WebRtcSpl_DivW32W16ResW16(expPg32, chngQ); /* Q22/Q12=Q10 */ tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,divVal,13);/* Q13*Q10>>13 => Q10*/ if (tmp16<0) { tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ if (tmp16_1<0) expPg=(WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); else expPg=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); } else expPg = (WebRtc_Word16) 16384; /* 1 in Q14, since 2^0=1 */ *varscale = expPg-1; *oldEnergy = nrgQ[3]; }
void WebRtcIlbcfix_Poly2Lsp( int16_t *a, /* (o) A coefficients in Q12 */ int16_t *lsp, /* (i) LSP coefficients in Q15 */ int16_t *old_lsp /* (i) old LSP coefficients that are used if the new coefficients turn out to be unstable */ ) { int16_t f[2][6]; /* f[0][] represents f1 and f[1][] represents f2 */ int16_t *a_i_ptr, *a_10mi_ptr; int16_t *f1ptr, *f2ptr; int32_t tmpW32; int16_t x, y, xlow, ylow, xmid, ymid, xhigh, yhigh, xint; int16_t shifts, sign; int i, j; int foundFreqs; int fi_select; /* Calculate the two polynomials f1(z) and f2(z) (the sum and the diff polynomial) f1[0] = f2[0] = 1.0; f1[i+1] = a[i+1] + a[10-i] - f1[i]; f2[i+1] = a[i+1] - a[10-i] - f1[i]; */ a_i_ptr = a + 1; a_10mi_ptr = a + 10; f1ptr = f[0]; f2ptr = f[1]; (*f1ptr) = 1024; /* 1.0 in Q10 */ (*f2ptr) = 1024; /* 1.0 in Q10 */ for (i = 0; i < 5; i++) { (*(f1ptr+1)) = (int16_t)(WEBRTC_SPL_RSHIFT_W32(((int32_t)(*a_i_ptr)+(*a_10mi_ptr)), 2) - (*f1ptr)); (*(f2ptr+1)) = (int16_t)(WEBRTC_SPL_RSHIFT_W32(((int32_t)(*a_i_ptr)-(*a_10mi_ptr)), 2) + (*f2ptr)); a_i_ptr++; a_10mi_ptr--; f1ptr++; f2ptr++; } /* find the LSPs using the Chebychev pol. evaluation */ fi_select = 0; /* selector between f1 and f2, start with f1 */ foundFreqs = 0; xlow = WebRtcIlbcfix_kCosGrid[0]; ylow = WebRtcIlbcfix_Chebyshev(xlow, f[fi_select]); /* Iterate until all the 10 LSP's have been found or all the grid points have been tried. If the 10 LSP's can not be found, set the LSP vector to previous LSP */ for (j = 1; j < COS_GRID_POINTS && foundFreqs < 10; j++) { xhigh = xlow; yhigh = ylow; xlow = WebRtcIlbcfix_kCosGrid[j]; ylow = WebRtcIlbcfix_Chebyshev(xlow, f[fi_select]); if (WEBRTC_SPL_MUL_16_16(ylow, yhigh) <= 0) { /* Run 4 times to reduce the interval */ for (i = 0; i < 4; i++) { /* xmid =(xlow + xhigh)/2 */ xmid = WEBRTC_SPL_RSHIFT_W16(xlow, 1) + WEBRTC_SPL_RSHIFT_W16(xhigh, 1); ymid = WebRtcIlbcfix_Chebyshev(xmid, f[fi_select]); if (WEBRTC_SPL_MUL_16_16(ylow, ymid) <= 0) { yhigh = ymid; xhigh = xmid; } else { ylow = ymid; xlow = xmid; } } /* Calculater xint by linear interpolation: xint = xlow - ylow*(xhigh-xlow)/(yhigh-ylow); */ x = xhigh - xlow; y = yhigh - ylow; if (y == 0) { xint = xlow; } else { sign = y; y = WEBRTC_SPL_ABS_W16(y); shifts = (int16_t)WebRtcSpl_NormW32(y)-16; y = WEBRTC_SPL_LSHIFT_W16(y, shifts); y = (int16_t)WebRtcSpl_DivW32W16(536838144, y); /* 1/(yhigh-ylow) */ tmpW32 = WEBRTC_SPL_MUL_16_16_RSFT(x, y, (19-shifts)); /* y=(xhigh-xlow)/(yhigh-ylow) */ y = (int16_t)(tmpW32&0xFFFF); if (sign < 0) { y = -y; } /* tmpW32 = ylow*(xhigh-xlow)/(yhigh-ylow) */ tmpW32 = WEBRTC_SPL_MUL_16_16_RSFT(ylow, y, 10); xint = xlow-(int16_t)(tmpW32&0xFFFF); } /* Store the calculated lsp */ lsp[foundFreqs] = (int16_t)xint; foundFreqs++; /* if needed, set xlow and ylow for next recursion */ if (foundFreqs<10) { xlow = xint; /* Swap between f1 and f2 (f[0][] and f[1][]) */ fi_select = ((fi_select+1)&0x1); ylow = WebRtcIlbcfix_Chebyshev(xlow, f[fi_select]); } } } /* Check if M roots found, if not then use the old LSP */ if (foundFreqs < 10) { WEBRTC_SPL_MEMCPY_W16(lsp, old_lsp, 10); } return; }