/* The conversion is implemented by the step-down algorithm */ void WebRtcSpl_AToK_JSK( WebRtc_Word16 *a16, /* Q11 */ WebRtc_Word16 useOrder, WebRtc_Word16 *k16 /* Q15 */ ) { int m, k; WebRtc_Word32 tmp32[MAX_AR_MODEL_ORDER]; WebRtc_Word32 tmp32b; WebRtc_Word32 tmp_inv_denum32; WebRtc_Word16 tmp_inv_denum16; k16[useOrder-1]= WEBRTC_SPL_LSHIFT_W16(a16[useOrder], 4); //Q11<<4 => Q15 for (m=useOrder-1; m>0; m--) { tmp_inv_denum32 = ((WebRtc_Word32) 1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]); // (1 - k^2) in Q30 tmp_inv_denum16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp_inv_denum32, 15); // (1 - k^2) in Q15 for (k=1; k<=m; k++) { tmp32b = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)a16[k], 16) - WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(k16[m], a16[m-k+1]), 1); tmp32[k] = WebRtcSpl_DivW32W16(tmp32b, tmp_inv_denum16); //Q27/Q15 = Q12 } for (k=1; k<m; k++) { a16[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q12>>1 => Q11 } tmp32[m] = WEBRTC_SPL_SAT(4092, tmp32[m], -4092); k16[m-1] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(tmp32[m], 3); //Q12<<3 => Q15 } return; }
void WebRtcVad_Allpass(WebRtc_Word16 *in_vector, WebRtc_Word16 *out_vector, WebRtc_Word16 filter_coefficients, int vector_length, WebRtc_Word16 *filter_state) { // The filter can only cause overflow (in the w16 output variable) // if more than 4 consecutive input numbers are of maximum value and // has the the same sign as the impulse responses first taps. // First 6 taps of the impulse response: 0.6399 0.5905 -0.3779 // 0.2418 -0.1547 0.0990 int n; WebRtc_Word16 tmp16; WebRtc_Word32 tmp32, in32, state32; state32 = WEBRTC_SPL_LSHIFT_W32(((WebRtc_Word32)(*filter_state)), 16); // Q31 for (n = 0; n < vector_length; n++) { tmp32 = state32 + WEBRTC_SPL_MUL_16_16(filter_coefficients, (*in_vector)); tmp16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 16); *out_vector++ = tmp16; in32 = WEBRTC_SPL_LSHIFT_W32(((WebRtc_Word32)(*in_vector)), 14); state32 = in32 - WEBRTC_SPL_MUL_16_16(filter_coefficients, tmp16); state32 = WEBRTC_SPL_LSHIFT_W32(state32, 1); in_vector += 2; } *filter_state = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(state32, 16); }
/* Filter ar_g_Q0[] and ar_f_Q0[] through an AR filter with coefficients * cth_Q15[] and sth_Q15[]. */ void WebRtcIsacfix_FilterArLoop(int16_t* ar_g_Q0, // Input samples int16_t* ar_f_Q0, // Input samples int16_t* cth_Q15, // Filter coefficients int16_t* sth_Q15, // Filter coefficients int16_t order_coef) { // order of the filter int n = 0; for (n = 0; n < HALF_SUBFRAMELEN - 1; n++) { int k = 0; int16_t tmpAR = 0; int32_t tmp32 = 0; int32_t tmp32_2 = 0; tmpAR = ar_f_Q0[n + 1]; for (k = order_coef - 1; k >= 0; k--) { tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(cth_Q15[k], tmpAR)) - (WEBRTC_SPL_MUL_16_16(sth_Q15[k], ar_g_Q0[k])) + 16384), 15); tmp32_2 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(sth_Q15[k], tmpAR)) + (WEBRTC_SPL_MUL_16_16(cth_Q15[k], ar_g_Q0[k])) + 16384), 15); tmpAR = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32); ar_g_Q0[k + 1] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32_2); } ar_f_Q0[n + 1] = tmpAR; ar_g_Q0[0] = tmpAR; } }
void WebRtcIsacfix_PitchFilterCore(int loopNumber, int16_t gain, int index, int16_t sign, int16_t* inputState, int16_t* outputBuf2, const int16_t* coefficient, int16_t* inputBuf, int16_t* outputBuf, int* index2) { int i = 0, j = 0; /* Loop counters. */ int16_t* ubufQQpos2 = &outputBuf2[PITCH_BUFFSIZE - (index + 2)]; int16_t tmpW16 = 0; for (i = 0; i < loopNumber; i++) { int32_t tmpW32 = 0; /* Filter to get fractional pitch. */ for (j = 0; j < PITCH_FRACORDER; j++) { tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQpos2[*index2 + j], coefficient[j]); } /* Saturate to avoid overflow in tmpW16. */ tmpW32 = WEBRTC_SPL_SAT(536862719, tmpW32, -536879104); tmpW32 += 8192; tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14); /* Shift low pass filter state. */ memmove(&inputState[1], &inputState[0], (PITCH_DAMPORDER - 1) * sizeof(int16_t)); inputState[0] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( gain, tmpW16, 12); /* Low pass filter. */ tmpW32 = 0; /* TODO(kma): Define a static inline function WebRtcSpl_DotProduct() in spl_inl.h to replace this and other similar loops. */ for (j = 0; j < PITCH_DAMPORDER; j++) { tmpW32 += WEBRTC_SPL_MUL_16_16(inputState[j], kDampFilter[j]); } /* Saturate to avoid overflow in tmpW16. */ tmpW32 = WEBRTC_SPL_SAT(1073725439, tmpW32, -1073758208); tmpW32 += 16384; tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 15); /* Subtract from input and update buffer. */ tmpW32 = inputBuf[*index2] - WEBRTC_SPL_MUL_16_16(sign, tmpW16); outputBuf[*index2] = WebRtcSpl_SatW32ToW16(tmpW32); tmpW32 = inputBuf[*index2] + outputBuf[*index2]; outputBuf2[*index2 + PITCH_BUFFSIZE] = WebRtcSpl_SatW32ToW16(tmpW32); (*index2)++; } }
void WebRtcIlbcfix_CbMemEnergy(int16_t range, int16_t * CB, /* (i) The CB memory (1:st section) */ int16_t * filteredCB, /* (i) The filtered CB memory (2:nd section) */ int16_t lMem, /* (i) Length of the CB memory */ int16_t lTarget, /* (i) Length of the target vector */ int16_t * energyW16, /* (o) Energy in the CB vectors */ int16_t * energyShifts, /* (o) Shift value of the energy */ 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 *ppi, *ppo, *pp; int32_t energy, tmp32; /* Compute the energy and store it in a vector. Also the * corresponding shift values are stored. The energy values * are reused in all three stages. */ /* Calculate the energy in the first block of 'lTarget' sampels. */ ppi = CB + lMem - lTarget - 1; ppo = CB + lMem - 1; pp = CB + lMem - lTarget; energy = WebRtcSpl_DotProductWithScale(pp, pp, lTarget, scale); /* Normalize the energy and store the number of shifts */ energyShifts[0] = (int16_t) WebRtcSpl_NormW32(energy); tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, energyShifts[0]); energyW16[0] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32, 16); /* Compute the energy of the rest of the cb memory * by step wise adding and subtracting the next * sample and the last sample respectively. */ WebRtcIlbcfix_CbMemEnergyCalc(energy, range, ppi, ppo, energyW16, energyShifts, scale, 0); /* Next, precompute the energy values for the filtered cb section */ pp = filteredCB + lMem - lTarget; energy = WebRtcSpl_DotProductWithScale(pp, pp, lTarget, scale); /* Normalize the energy and store the number of shifts */ energyShifts[base_size] = (int16_t) WebRtcSpl_NormW32(energy); tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, energyShifts[base_size]); energyW16[base_size] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32, 16); ppi = filteredCB + lMem - 1 - lTarget; ppo = filteredCB + lMem - 1; WebRtcIlbcfix_CbMemEnergyCalc(energy, range, ppi, ppo, energyW16, energyShifts, scale, base_size); }
/* 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_SortSq( WebRtc_Word16 *xq, /* (o) the quantized value */ WebRtc_Word16 *index, /* (o) the quantization index */ WebRtc_Word16 x, /* (i) the value to quantize */ const WebRtc_Word16 *cb, /* (i) the quantization codebook */ WebRtc_Word16 cb_size /* (i) the size of the quantization codebook */ ){ int i; if (x <= cb[0]) { *index = 0; *xq = cb[0]; } else { i = 0; while ((x > cb[i]) && (i < (cb_size-1))) { i++; } if (x > WEBRTC_SPL_RSHIFT_W32(( (WebRtc_Word32)cb[i] + cb[i - 1] + 1),1)) { *index = i; *xq = cb[i]; } else { *index = i - 1; *xq = cb[i - 1]; } } }
int WebRtcNetEQ_RTCPUpdate(WebRtcNetEQ_RTCP_t *RTCP_inst, uint16_t uw16_seqNo, uint32_t uw32_timeStamp, uint32_t uw32_recTime) { int16_t w16_SeqDiff; int32_t w32_TimeDiff; int32_t w32_JitterDiff; /* * Update number of received packets, and largest packet number received. */ RTCP_inst->received++; w16_SeqDiff = uw16_seqNo - RTCP_inst->max_seq; if (w16_SeqDiff >= 0) { if (uw16_seqNo < RTCP_inst->max_seq) { /* Wrap around detected */ RTCP_inst->cycles++; } RTCP_inst->max_seq = uw16_seqNo; } /* Calculate Jitter, and update previous timestamps */ /* Note that the value in RTCP_inst->jitter is in Q4. */ if (RTCP_inst->received > 1) { w32_TimeDiff = (uw32_recTime - (uw32_timeStamp - RTCP_inst->transit)); w32_TimeDiff = WEBRTC_SPL_ABS_W32(w32_TimeDiff); w32_JitterDiff = WEBRTC_SPL_LSHIFT_W16(w32_TimeDiff, 4) - RTCP_inst->jitter; RTCP_inst->jitter = RTCP_inst->jitter + WEBRTC_SPL_RSHIFT_W32((w32_JitterDiff + 8), 4); } RTCP_inst->transit = (uw32_timeStamp - uw32_recTime); return 0; }
static __inline int32_t CalcLrIntQ(int32_t fixVal, int16_t qDomain) { int32_t intgr; int32_t roundVal; roundVal = WEBRTC_SPL_LSHIFT_W32((int32_t)1, qDomain - 1); intgr = WEBRTC_SPL_RSHIFT_W32(fixVal + roundVal, qDomain); return intgr; }
WebRtc_UWord32 WebRtcNetEQ_ScaleTimestampInternalToExternal(const MCUInst_t *MCU_inst, WebRtc_UWord32 internalTS) { WebRtc_Word32 timestampDiff; WebRtc_UWord32 externalTS; /* difference between this and last incoming timestamp */ timestampDiff = (WebRtc_Word32) internalTS - MCU_inst->internalTS; switch (MCU_inst->scalingFactor) { case kTSscalingTwo: { /* divide by 2 */ timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1); break; } case kTSscalingTwoThirds: { /* multiply with 3/2 */ timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3); timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1); break; } case kTSscalingFourThirds: { /* multiply with 3/4 */ timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3); timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 2); break; } default: { /* no scaling */ } } /* add the scaled difference to last scaled timestamp and save ... */ externalTS = MCU_inst->externalTS + timestampDiff; return externalTS; }
/* Compute the energy of the rest of the cb memory * by step wise adding and subtracting the next * sample and the last sample respectively */ void WebRtcIlbcfix_CbMemEnergyCalc( WebRtc_Word32 energy, /* (i) input start energy */ WebRtc_Word16 range, /* (i) number of iterations */ WebRtc_Word16 *ppi, /* (i) input pointer 1 */ WebRtc_Word16 *ppo, /* (i) input pointer 2 */ WebRtc_Word16 *energyW16, /* (o) Energy in the CB vectors */ WebRtc_Word16 *energyShifts, /* (o) Shift value of the energy */ WebRtc_Word16 scale, /* (i) The scaling of all energy values */ WebRtc_Word16 base_size /* (i) Index to where the energy values should be stored */ ) { WebRtc_Word16 j,shft; WebRtc_Word32 tmp; WebRtc_Word16 *eSh_ptr; WebRtc_Word16 *eW16_ptr; eSh_ptr = &energyShifts[1+base_size]; eW16_ptr = &energyW16[1+base_size]; for(j=0;j<range-1;j++) { /* Calculate next energy by a +/- operation on the edge samples */ tmp = WEBRTC_SPL_MUL_16_16(*ppi, *ppi); tmp -= WEBRTC_SPL_MUL_16_16(*ppo, *ppo); energy += WEBRTC_SPL_RSHIFT_W32(tmp, scale); energy = WEBRTC_SPL_MAX(energy, 0); ppi--; ppo--; /* Normalize the energy into a WebRtc_Word16 and store the number of shifts */ shft = (WebRtc_Word16)WebRtcSpl_NormW32(energy); *eSh_ptr++ = shft; tmp = WEBRTC_SPL_LSHIFT_W32(energy, shft); *eW16_ptr++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp, 16); } }
static __inline int32_t Log2Q8( uint32_t x ) { int32_t zeros, lg2; int16_t frac; zeros=WebRtcSpl_NormU32(x); frac=(int16_t)WEBRTC_SPL_RSHIFT_W32(((uint32_t)(WEBRTC_SPL_LSHIFT_W32(x, zeros))&0x7FFFFFFF), 23); /* log2(magn(i)) */ lg2= (WEBRTC_SPL_LSHIFT_W32((31-zeros), 8)+frac); return lg2; }
static void AllpassFilterForDec32(WebRtc_Word16 *InOut16, //Q0 const WebRtc_Word32 *APSectionFactors, //Q15 WebRtc_Word16 lengthInOut, WebRtc_Word32 *FilterState) //Q16 { int n, j; WebRtc_Word32 a, b; for (j=0; j<ALLPASSSECTIONS; j++) { for (n=0;n<lengthInOut;n+=2){ a = WEBRTC_SPL_MUL_16_32_RSFT16(InOut16[n], APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15 a = WEBRTC_SPL_LSHIFT_W32(a, 1); // Q15 -> Q16 b = WEBRTC_SPL_ADD_SAT_W32(a, FilterState[j]); //Q16+Q16=Q16 a = WEBRTC_SPL_MUL_16_32_RSFT16( (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16), -APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15 FilterState[j] = WEBRTC_SPL_ADD_SAT_W32( WEBRTC_SPL_LSHIFT_W32(a,1), WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)InOut16[n], 16)); // Q15<<1 + Q0<<16 = Q16 + Q16 = Q16 InOut16[n] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16); //Save as Q0 } } }
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 }
static __inline WebRtc_Word32 log2_Q8_LPC( WebRtc_UWord32 x ) { WebRtc_Word32 zeros, lg2; WebRtc_Word16 frac; zeros=WebRtcSpl_NormU32(x); frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(((WebRtc_UWord32)WEBRTC_SPL_LSHIFT_W32(x, zeros)&0x7FFFFFFF), 23); /* log2(x) */ lg2= (WEBRTC_SPL_LSHIFT_W16((31-zeros), 8)+frac); return lg2; }
// 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_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16) { int m, k; int32_t tmp32[SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER]; int32_t tmp_inv_denom32; int16_t tmp_inv_denom16; k16[use_order - 1] = WEBRTC_SPL_LSHIFT_W16(a16[use_order], 3); //Q12<<3 => Q15 for (m = use_order - 1; m > 0; m--) { // (1 - k^2) in Q30 tmp_inv_denom32 = ((int32_t)1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]); // (1 - k^2) in Q15 tmp_inv_denom16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp_inv_denom32, 15); for (k = 1; k <= m; k++) { // tmp[k] = (a[k] - RC[m] * a[m-k+1]) / (1.0 - RC[m]*RC[m]); // [Q12<<16 - (Q15*Q12)<<1] = [Q28 - Q28] = Q28 tmp32[k] = WEBRTC_SPL_LSHIFT_W32((int32_t)a16[k], 16) - WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(k16[m], a16[m-k+1]), 1); tmp32[k] = WebRtcSpl_DivW32W16(tmp32[k], tmp_inv_denom16); //Q28/Q15 = Q13 } for (k = 1; k < m; k++) { a16[k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q13>>1 => Q12 } tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191); k16[m - 1] = (int16_t)WEBRTC_SPL_LSHIFT_W32(tmp32[m], 2); //Q13<<2 => Q15 } return; }
/* 1D parabolic interpolation . All input and output values are in Q8 */ static __inline void Intrp1DQ8(int32_t *x, int32_t *fx, int32_t *y, int32_t *fy) { int16_t sign1=1, sign2=1; int32_t r32, q32, t32, nom32, den32; int16_t t16, tmp16, tmp16_1; if ((fx[0]>0) && (fx[2]>0)) { r32=fx[1]-fx[2]; q32=fx[0]-fx[1]; nom32=q32+r32; den32=WEBRTC_SPL_MUL_32_16((q32-r32), 2); if (nom32<0) sign1=-1; if (den32<0) sign2=-1; /* t = (q32+r32)/(2*(q32-r32)) = (fx[0]-fx[1] + fx[1]-fx[2])/(2 * fx[0]-fx[1] - (fx[1]-fx[2]))*/ /* (Signs are removed because WebRtcSpl_DivResultInQ31 can't handle negative numbers) */ t32=WebRtcSpl_DivResultInQ31(WEBRTC_SPL_MUL_32_16(nom32, sign1),WEBRTC_SPL_MUL_32_16(den32, sign2)); /* t in Q31, without signs */ t16=(int16_t)WEBRTC_SPL_RSHIFT_W32(t32, 23); /* Q8 */ t16=t16*sign1*sign2; /* t in Q8 with signs */ *y = x[0]+t16; /* Q8 */ // *y = x[1]+t16; /* Q8 */ /* The following code calculates fy in three steps */ /* fy = 0.5 * t * (t-1) * fx[0] + (1-t*t) * fx[1] + 0.5 * t * (t+1) * fx[2]; */ /* Part I: 0.5 * t * (t-1) * fx[0] */ tmp16_1=(int16_t)WEBRTC_SPL_MUL_16_16(t16,t16); /* Q8*Q8=Q16 */ tmp16_1 = WEBRTC_SPL_RSHIFT_W16(tmp16_1,2); /* Q16>>2 = Q14 */ t16 = (int16_t)WEBRTC_SPL_MUL_16_16(t16, 64); /* Q8<<6 = Q14 */ tmp16 = tmp16_1-t16; *fy = WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[0]); /* (Q14 * Q8 >>15)/2 = Q8 */ /* Part II: (1-t*t) * fx[1] */ tmp16 = 16384-tmp16_1; /* 1 in Q14 - Q14 */ *fy += WEBRTC_SPL_MUL_16_32_RSFT14(tmp16, fx[1]);/* Q14 * Q8 >> 14 = Q8 */ /* Part III: 0.5 * t * (t+1) * fx[2] */ tmp16 = tmp16_1+t16; *fy += WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[2]);/* (Q14 * Q8 >>15)/2 = Q8 */ } else { *y = x[0]; *fy= fx[1]; } }
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++; } }
void WebRtcIlbcfix_CbConstruct( WebRtc_Word16 *decvector, /* (o) Decoded vector */ WebRtc_Word16 *index, /* (i) Codebook indices */ WebRtc_Word16 *gain_index, /* (i) Gain quantization indices */ WebRtc_Word16 *mem, /* (i) Buffer for codevector construction */ WebRtc_Word16 lMem, /* (i) Length of buffer */ WebRtc_Word16 veclen /* (i) Length of vector */ ){ int j; WebRtc_Word16 gain[CB_NSTAGES]; /* Stack based */ WebRtc_Word16 cbvec0[SUBL]; WebRtc_Word16 cbvec1[SUBL]; WebRtc_Word16 cbvec2[SUBL]; WebRtc_Word32 a32; WebRtc_Word16 *gainPtr; /* gain de-quantization */ gain[0] = WebRtcIlbcfix_GainDequant(gain_index[0], 16384, 0); gain[1] = WebRtcIlbcfix_GainDequant(gain_index[1], gain[0], 1); gain[2] = WebRtcIlbcfix_GainDequant(gain_index[2], gain[1], 2); /* codebook vector construction and construction of total vector */ /* Stack based */ WebRtcIlbcfix_GetCbVec(cbvec0, mem, index[0], lMem, veclen); WebRtcIlbcfix_GetCbVec(cbvec1, mem, index[1], lMem, veclen); WebRtcIlbcfix_GetCbVec(cbvec2, mem, index[2], lMem, veclen); gainPtr = &gain[0]; for (j=0;j<veclen;j++) { a32 = WEBRTC_SPL_MUL_16_16(*gainPtr++, cbvec0[j]); a32 += WEBRTC_SPL_MUL_16_16(*gainPtr++, cbvec1[j]); a32 += WEBRTC_SPL_MUL_16_16(*gainPtr, cbvec2[j]); gainPtr -= 2; decvector[j] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(a32 + 8192, 14); } return; }
void WebRtcNetEQ_MixVoiceUnvoice(WebRtc_Word16 *pw16_outData, WebRtc_Word16 *pw16_voicedVec, WebRtc_Word16 *pw16_unvoicedVec, WebRtc_Word16 *w16_current_vfraction, WebRtc_Word16 w16_vfraction_change, WebRtc_Word16 N) { int i; WebRtc_Word16 w16_tmp2; WebRtc_Word16 vfraction = *w16_current_vfraction; w16_tmp2 = 16384 - vfraction; for (i = 0; i < N; i++) { pw16_outData[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16(vfraction, pw16_voicedVec[i]) + WEBRTC_SPL_MUL_16_16(w16_tmp2, pw16_unvoicedVec[i]) + 8192, 14); vfraction -= w16_vfraction_change; w16_tmp2 += w16_vfraction_change; } *w16_current_vfraction = vfraction; }
int WebRtcSpl_DownsampleFast(WebRtc_Word16 *in_ptr, WebRtc_Word16 in_length, WebRtc_Word16 *out_ptr, WebRtc_Word16 out_length, WebRtc_Word16 *B, WebRtc_Word16 B_length, WebRtc_Word16 factor, WebRtc_Word16 delay) { WebRtc_Word32 o; int i, j; WebRtc_Word16 *downsampled_ptr = out_ptr; WebRtc_Word16 *b_ptr; WebRtc_Word16 *x_ptr; WebRtc_Word16 endpos = delay + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(factor, (out_length - 1)) + 1; if (in_length < endpos) { return -1; } for (i = delay; i < endpos; i += factor) { b_ptr = &B[0]; x_ptr = &in_ptr[i]; o = (WebRtc_Word32)2048; // Round val for (j = 0; j < B_length; j++) { o += WEBRTC_SPL_MUL_16_16(*b_ptr++, *x_ptr--); } o = WEBRTC_SPL_RSHIFT_W32(o, 12); // If output is higher than 32768, saturate it. Same with negative side *downsampled_ptr++ = WebRtcSpl_SatW32ToW16(o); } return 0; }
void WebRtcIlbcfix_Interpolate( WebRtc_Word16 *out, /* (o) output vector */ WebRtc_Word16 *in1, /* (i) first input vector */ WebRtc_Word16 *in2, /* (i) second input vector */ WebRtc_Word16 coef, /* (i) weight coefficient in Q14 */ WebRtc_Word16 length) /* (i) number of sample is vectors */ { int i; WebRtc_Word16 invcoef; /* Performs the operation out[i] = in[i]*coef + (1-coef)*in2[i] (with rounding) */ invcoef = 16384 - coef; /* 16384 = 1.0 (Q14)*/ for (i = 0; i < length; i++) { out[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16(coef, in1[i]) + WEBRTC_SPL_MUL_16_16(invcoef, in2[i]))+8192, 14); } return; }
void WebRtcVad_HpOutput(WebRtc_Word16 *in_vector, WebRtc_Word16 in_vector_length, WebRtc_Word16 *out_vector, WebRtc_Word16 *filter_state) { WebRtc_Word16 i, *pi, *outPtr; WebRtc_Word32 tmpW32; pi = &in_vector[0]; outPtr = &out_vector[0]; // The sum of the absolute values of the impulse response: // The zero/pole-filter has a max amplification of a single sample of: 1.4546 // Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194 // The all-zero section has a max amplification of a single sample of: 1.6189 // Impulse response: 0.4047 -0.8094 0.4047 0 0 0 // The all-pole section has a max amplification of a single sample of: 1.9931 // Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532 for (i = 0; i < in_vector_length; i++) { // all-zero section (filter coefficients in Q14) tmpW32 = (WebRtc_Word32)WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[0], (*pi)); tmpW32 += (WebRtc_Word32)WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[1], filter_state[0]); tmpW32 += (WebRtc_Word32)WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[2], filter_state[1]); // Q14 filter_state[1] = filter_state[0]; filter_state[0] = *pi++; // all-pole section tmpW32 -= (WebRtc_Word32)WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[1], filter_state[2]); // Q14 tmpW32 -= (WebRtc_Word32)WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[2], filter_state[3]); filter_state[3] = filter_state[2]; filter_state[2] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32 (tmpW32, 14); *outPtr++ = filter_state[2]; } }
int32_t WebRtcIlbcfix_Smooth_odata( int16_t *odata, int16_t *psseq, int16_t *surround, int16_t C) { int i; int16_t err; int32_t errs; for(i=0;i<80;i++) { odata[i]= (int16_t)WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16(C, surround[i])+1024), 11); } errs=0; for(i=0;i<80;i++) { err=(int16_t)WEBRTC_SPL_RSHIFT_W16((psseq[i]-odata[i]), 3); errs+=WEBRTC_SPL_MUL_16_16(err, err); /* errs in Q-6 */ } return errs; }
WebRtc_Word32 WebRtcIlbcfix_Smooth_odata( WebRtc_Word16 *odata, WebRtc_Word16 *psseq, WebRtc_Word16 *surround, WebRtc_Word16 C) { int i; WebRtc_Word16 err; WebRtc_Word32 errs; for(i=0;i<80;i++) { odata[i]= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16(C, surround[i])+1024), 11); } errs=0; for(i=0;i<80;i++) { err=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16((psseq[i]-odata[i]), 3); errs+=WEBRTC_SPL_MUL_16_16(err, err); /* errs in Q-6 */ } return errs; }
void WebRtcIsacfix_DecimateAllpass32(const WebRtc_Word16 *in, WebRtc_Word32 *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */ WebRtc_Word16 N, /* number of input samples */ WebRtc_Word16 *out) /* array of size N/2 */ { int n; WebRtc_Word16 data_vec[PITCH_FRAME_LEN]; /* copy input */ memcpy(data_vec+1, in, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), (N-1))); data_vec[0] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)],16); //the z^(-1) state state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)] = WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)in[N-1],16); AllpassFilterForDec32(data_vec+1, kApUpperQ15, N, state_in); AllpassFilterForDec32(data_vec, kApLowerQ15, N, state_in+ALLPASSSECTIONS); for (n=0;n<N/2;n++) { out[n]=WEBRTC_SPL_ADD_SAT_W16(data_vec[WEBRTC_SPL_MUL_16_16(2, n)], data_vec[WEBRTC_SPL_MUL_16_16(2, n)+1]); } }
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_Spec2TimeC(int16_t *inreQ7, int16_t *inimQ7, int32_t *outre1Q16, int32_t *outre2Q16) { int k; int16_t tmp1rQ14, tmp1iQ14; int32_t xrQ16, xiQ16, yrQ16, yiQ16; int32_t tmpInRe, tmpInIm, tmpInRe2, tmpInIm2; int16_t factQ11; int16_t sh; for (k = 0; k < FRAMESAMPLES/4; k++) { /* Move zero in time to beginning of frames */ tmp1rQ14 = -WebRtcIsacfix_kSinTab2[FRAMESAMPLES/4 - 1 - k]; tmp1iQ14 = WebRtcIsacfix_kSinTab2[k]; tmpInRe = WEBRTC_SPL_LSHIFT_W32((int32_t) inreQ7[k], 9); // Q7 -> Q16 tmpInIm = WEBRTC_SPL_LSHIFT_W32((int32_t) inimQ7[k], 9); // Q7 -> Q16 tmpInRe2 = WEBRTC_SPL_LSHIFT_W32((int32_t) inreQ7[FRAMESAMPLES/2 - 1 - k], 9); // Q7 -> Q16 tmpInIm2 = WEBRTC_SPL_LSHIFT_W32((int32_t) inimQ7[FRAMESAMPLES/2 - 1 - k], 9); // Q7 -> Q16 xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInRe) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInIm); xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInIm) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInRe); yrQ16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInIm2) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInRe2); yiQ16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInRe2) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInIm2); /* Combine into one vector, z = x + j * y */ outre1Q16[k] = xrQ16 - yiQ16; outre1Q16[FRAMESAMPLES/2 - 1 - k] = xrQ16 + yiQ16; outre2Q16[k] = xiQ16 + yrQ16; outre2Q16[FRAMESAMPLES/2 - 1 - k] = -xiQ16 + yrQ16; } /* Get IDFT */ tmpInRe = WebRtcSpl_MaxAbsValueW32(outre1Q16, 240); tmpInIm = WebRtcSpl_MaxAbsValueW32(outre2Q16, 240); if (tmpInIm>tmpInRe) { tmpInRe = tmpInIm; } sh = WebRtcSpl_NormW32(tmpInRe); sh = sh-24; //if sh becomes >=0, then we should shift sh steps to the left, and the domain will become Q(16+sh) //if sh becomes <0, then we should shift -sh steps to the right, and the domain will become Q(16+sh) //"Fastest" vectors if (sh>=0) { for (k=0; k<240; k++) { inreQ7[k] = (int16_t) WEBRTC_SPL_LSHIFT_W32(outre1Q16[k], sh); //Q(16+sh) inimQ7[k] = (int16_t) WEBRTC_SPL_LSHIFT_W32(outre2Q16[k], sh); //Q(16+sh) } } else { int32_t round = WEBRTC_SPL_LSHIFT_W32((int32_t)1, -sh-1); for (k=0; k<240; k++) { inreQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(outre1Q16[k]+round, -sh); //Q(16+sh) inimQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(outre2Q16[k]+round, -sh); //Q(16+sh) } } WebRtcIsacfix_FftRadix16Fastest(inreQ7, inimQ7, 1); // real call //"Fastest" vectors if (sh>=0) { for (k=0; k<240; k++) { outre1Q16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inreQ7[k], sh); //Q(16+sh) -> Q16 outre2Q16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inimQ7[k], sh); //Q(16+sh) -> Q16 } } else { for (k=0; k<240; k++) { outre1Q16[k] = WEBRTC_SPL_LSHIFT_W32((int32_t)inreQ7[k], -sh); //Q(16+sh) -> Q16 outre2Q16[k] = WEBRTC_SPL_LSHIFT_W32((int32_t)inimQ7[k], -sh); //Q(16+sh) -> Q16 } } /* Divide through by the normalizing constant: */ /* scale all values with 1/240, i.e. with 273 in Q16 */ /* 273/65536 ~= 0.0041656 */ /* 1/240 ~= 0.0041666 */ for (k=0; k<240; k++) { outre1Q16[k] = WEBRTC_SPL_MUL_16_32_RSFT16(273, outre1Q16[k]); outre2Q16[k] = WEBRTC_SPL_MUL_16_32_RSFT16(273, outre2Q16[k]); } /* Demodulate and separate */ factQ11 = 31727; // sqrt(240) in Q11 is round(15.49193338482967*2048) = 31727 for (k = 0; k < FRAMESAMPLES/2; k++) { tmp1rQ14 = WebRtcIsacfix_kCosTab1[k]; tmp1iQ14 = WebRtcIsacfix_kSinTab1[k]; xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, outre1Q16[k]) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, outre2Q16[k]); xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, outre2Q16[k]) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, outre1Q16[k]); xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT11(factQ11, xrQ16); xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT11(factQ11, xiQ16); outre2Q16[k] = xiQ16; outre1Q16[k] = xrQ16; } }
void WebRtcIsacfix_Time2SpecC(int16_t *inre1Q9, int16_t *inre2Q9, int16_t *outreQ7, int16_t *outimQ7) { int k; int32_t tmpreQ16[FRAMESAMPLES/2], tmpimQ16[FRAMESAMPLES/2]; int16_t tmp1rQ14, tmp1iQ14; int32_t xrQ16, xiQ16, yrQ16, yiQ16; int32_t v1Q16, v2Q16; int16_t factQ19, sh; /* Multiply with complex exponentials and combine into one complex vector */ factQ19 = 16921; // 0.5/sqrt(240) in Q19 is round(.5/sqrt(240)*(2^19)) = 16921 for (k = 0; k < FRAMESAMPLES/2; k++) { tmp1rQ14 = WebRtcIsacfix_kCosTab1[k]; tmp1iQ14 = WebRtcIsacfix_kSinTab1[k]; xrQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre1Q9[k]) + WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre2Q9[k]), 7); xiQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre2Q9[k]) - WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre1Q9[k]), 7); tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xrQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16 tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xiQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16 } xrQ16 = WebRtcSpl_MaxAbsValueW32(tmpreQ16, FRAMESAMPLES/2); yrQ16 = WebRtcSpl_MaxAbsValueW32(tmpimQ16, FRAMESAMPLES/2); if (yrQ16>xrQ16) { xrQ16 = yrQ16; } sh = WebRtcSpl_NormW32(xrQ16); sh = sh-24; //if sh becomes >=0, then we should shift sh steps to the left, and the domain will become Q(16+sh) //if sh becomes <0, then we should shift -sh steps to the right, and the domain will become Q(16+sh) //"Fastest" vectors if (sh>=0) { for (k=0; k<FRAMESAMPLES/2; k++) { inre1Q9[k] = (int16_t) WEBRTC_SPL_LSHIFT_W32(tmpreQ16[k], sh); //Q(16+sh) inre2Q9[k] = (int16_t) WEBRTC_SPL_LSHIFT_W32(tmpimQ16[k], sh); //Q(16+sh) } } else { int32_t round = WEBRTC_SPL_LSHIFT_W32((int32_t)1, -sh-1); for (k=0; k<FRAMESAMPLES/2; k++) { inre1Q9[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpreQ16[k]+round, -sh); //Q(16+sh) inre2Q9[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpimQ16[k]+round, -sh); //Q(16+sh) } } /* Get DFT */ WebRtcIsacfix_FftRadix16Fastest(inre1Q9, inre2Q9, -1); // real call //"Fastest" vectors if (sh>=0) { for (k=0; k<FRAMESAMPLES/2; k++) { tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inre1Q9[k], sh); //Q(16+sh) -> Q16 tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inre2Q9[k], sh); //Q(16+sh) -> Q16 } } else { for (k=0; k<FRAMESAMPLES/2; k++) { tmpreQ16[k] = WEBRTC_SPL_LSHIFT_W32((int32_t)inre1Q9[k], -sh); //Q(16+sh) -> Q16 tmpimQ16[k] = WEBRTC_SPL_LSHIFT_W32((int32_t)inre2Q9[k], -sh); //Q(16+sh) -> Q16 } } /* Use symmetry to separate into two complex vectors and center frames in time around zero */ for (k = 0; k < FRAMESAMPLES/4; k++) { xrQ16 = tmpreQ16[k] + tmpreQ16[FRAMESAMPLES/2 - 1 - k]; yiQ16 = -tmpreQ16[k] + tmpreQ16[FRAMESAMPLES/2 - 1 - k]; xiQ16 = tmpimQ16[k] - tmpimQ16[FRAMESAMPLES/2 - 1 - k]; yrQ16 = tmpimQ16[k] + tmpimQ16[FRAMESAMPLES/2 - 1 - k]; tmp1rQ14 = -WebRtcIsacfix_kSinTab2[FRAMESAMPLES/4 - 1 - k]; tmp1iQ14 = WebRtcIsacfix_kSinTab2[k]; v1Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xiQ16); v2Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xiQ16); outreQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(v1Q16, 9); outimQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(v2Q16, 9); v1Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yiQ16); v2Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yiQ16); outreQ7[FRAMESAMPLES/2 - 1 - k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(v1Q16, 9); //CalcLrIntQ(v1Q16, 9); outimQ7[FRAMESAMPLES/2 - 1 - k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(v2Q16, 9); //CalcLrIntQ(v2Q16, 9); } }