diff options
Diffstat (limited to 'src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c')
-rw-r--r-- | src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c | 957 |
1 files changed, 957 insertions, 0 deletions
diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c new file mode 100644 index 0000000000..4be438eb52 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c @@ -0,0 +1,957 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lpc_masking_model.c + * + * LPC analysis and filtering functions + * + */ + +#include "lpc_masking_model.h" + +#include <limits.h> /* For LLONG_MAX and LLONG_MIN. */ +#include "codec.h" +#include "entropy_coding.h" +#include "settings.h" + +/* 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; +} + + + + + +WebRtc_Word16 WebRtcSpl_LevinsonW32_JSK( + WebRtc_Word32 *R, /* (i) Autocorrelation of length >= order+1 */ + WebRtc_Word16 *A, /* (o) A[0..order] LPC coefficients (Q11) */ + WebRtc_Word16 *K, /* (o) K[0...order-1] Reflection coefficients (Q15) */ + WebRtc_Word16 order /* (i) filter order */ + ) { + WebRtc_Word16 i, j; + WebRtc_Word16 R_hi[LEVINSON_MAX_ORDER+1], R_low[LEVINSON_MAX_ORDER+1]; + /* Aurocorr coefficients in high precision */ + WebRtc_Word16 A_hi[LEVINSON_MAX_ORDER+1], A_low[LEVINSON_MAX_ORDER+1]; + /* LPC coefficients in high precicion */ + WebRtc_Word16 A_upd_hi[LEVINSON_MAX_ORDER+1], A_upd_low[LEVINSON_MAX_ORDER+1]; + /* LPC coefficients for next iteration */ + WebRtc_Word16 K_hi, K_low; /* reflection coefficient in high precision */ + WebRtc_Word16 Alpha_hi, Alpha_low, Alpha_exp; /* Prediction gain Alpha in high precision + and with scale factor */ + WebRtc_Word16 tmp_hi, tmp_low; + WebRtc_Word32 temp1W32, temp2W32, temp3W32; + WebRtc_Word16 norm; + + /* Normalize the autocorrelation R[0]...R[order+1] */ + + norm = WebRtcSpl_NormW32(R[0]); + + for (i=order;i>=0;i--) { + temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm); + /* Put R in hi and low format */ + R_hi[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + R_low[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[i], 16)), 1); + } + + /* K = A[1] = -R[1] / R[0] */ + + temp2W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[1],16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_low[1],1); /* R[1] in Q31 */ + temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); /* abs R[1] */ + temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); /* abs(R[1])/R[0] in Q31 */ + /* Put back the sign on R[1] */ + if (temp2W32 > 0) { + temp1W32 = -temp1W32; + } + + /* Put K in hi and low format */ + K_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + K_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)K_hi, 16)), 1); + + /* Store first reflection coefficient */ + K[0] = K_hi; + + temp1W32 = WEBRTC_SPL_RSHIFT_W32(temp1W32, 4); /* A[1] in Q27 */ + + /* Put A[1] in hi and low format */ + A_hi[1] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + A_low[1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[1], 16)), 1); + + /* Alpha = R[0] * (1-K^2) */ + + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) + + WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1); /* temp1W32 = k^2 in Q31 */ + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* Guard against <0 */ + temp1W32 = (WebRtc_Word32)0x7fffffffL - temp1W32; /* temp1W32 = (1 - K[0]*K[0]) in Q31 */ + + /* Store temp1W32 = 1 - K[0]*K[0] on hi and low format */ + tmp_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + /* Calculate Alpha in Q31 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_hi) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_low), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[0], tmp_hi), 15) ), 1); + + /* Normalize Alpha and put it in hi and low format */ + + Alpha_exp = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp); + Alpha_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + Alpha_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)Alpha_hi, 16)), 1); + + /* Perform the iterative calculations in the + Levinson Durbin algorithm */ + + for (i=2; i<=order; i++) + { + + /* ---- + \ + temp1W32 = R[i] + > R[j]*A[i-j] + / + ---- + j=1..i-1 + */ + + temp1W32 = 0; + + for(j=1; j<i; j++) { + /* temp1W32 is in Q31 */ + temp1W32 += (WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_hi[i-j]), 1) + + WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_low[i-j]), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[j], A_hi[i-j]), 15) ), 1)); + } + + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4); + temp1W32 += (WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[i], 16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_low[i], 1)); + + /* K = -temp1W32 / Alpha */ + temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* abs(temp1W32) */ + temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); /* abs(temp1W32)/Alpha */ + + /* Put the sign of temp1W32 back again */ + if (temp1W32 > 0) { + temp3W32 = -temp3W32; + } + + /* Use the Alpha shifts from earlier to denormalize */ + norm = WebRtcSpl_NormW32(temp3W32); + if ((Alpha_exp <= norm)||(temp3W32==0)) { + temp3W32 = WEBRTC_SPL_LSHIFT_W32(temp3W32, Alpha_exp); + } else { + if (temp3W32 > 0) + { + temp3W32 = (WebRtc_Word32)0x7fffffffL; + } else + { + temp3W32 = (WebRtc_Word32)0x80000000L; + } + } + + /* Put K on hi and low format */ + K_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16); + K_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)K_hi, 16)), 1); + + /* Store Reflection coefficient in Q15 */ + K[i-1] = K_hi; + + /* Test for unstable filter. If unstable return 0 and let the + user decide what to do in that case + */ + + if ((WebRtc_Word32)WEBRTC_SPL_ABS_W16(K_hi) > (WebRtc_Word32)32740) { + return(-i); /* Unstable filter */ + } + + /* + Compute updated LPC coefficient: Anew[i] + Anew[j]= A[j] + K*A[i-j] for j=1..i-1 + Anew[i]= K + */ + + for(j=1; j<i; j++) + { + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[j],16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_low[j],1); /* temp1W32 = A[j] in Q27 */ + + temp1W32 += WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(K_hi, A_hi[i-j]) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, A_low[i-j]), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]), 15) ), 1); /* temp1W32 += K*A[i-j] in Q27 */ + + /* Put Anew in hi and low format */ + A_upd_hi[j] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + A_upd_low[j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_upd_hi[j], 16)), 1); + } + + temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4); /* temp3W32 = K in Q27 (Convert from Q31 to Q27) */ + + /* Store Anew in hi and low format */ + A_upd_hi[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16); + A_upd_low[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_upd_hi[i], 16)), 1); + + /* Alpha = Alpha * (1-K^2) */ + + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) + + WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1); /* K*K in Q31 */ + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* Guard against <0 */ + temp1W32 = (WebRtc_Word32)0x7fffffffL - temp1W32; /* 1 - K*K in Q31 */ + + /* Convert 1- K^2 in hi and low format */ + tmp_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + /* Calculate Alpha = Alpha * (1-K^2) in Q31 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_hi) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_low), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_low, tmp_hi), 15)), 1); + + /* Normalize Alpha and store it on hi and low format */ + + norm = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm); + + Alpha_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + Alpha_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)Alpha_hi, 16)), 1); + + /* Update the total nomalization of Alpha */ + Alpha_exp = Alpha_exp + norm; + + /* Update A[] */ + + for(j=1; j<=i; j++) + { + A_hi[j] =A_upd_hi[j]; + A_low[j] =A_upd_low[j]; + } + } + + /* + Set A[0] to 1.0 and store the A[i] i=1...order in Q12 + (Convert from Q27 and use rounding) + */ + + A[0] = 2048; + + for(i=1; i<=order; i++) { + /* temp1W32 in Q27 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[i], 16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_low[i], 1); + /* Round and store upper word */ + A[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(temp1W32+(WebRtc_Word32)32768, 16); + } + return(1); /* Stable filters */ +} + + + + + +/* window */ +/* Matlab generation of floating point code: + * t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid; + * for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end + * All values are multiplyed with 2^21 in fixed point code. + */ +static const WebRtc_Word16 kWindowAutocorr[WINLEN] = { + 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 5, 6, + 8, 10, 12, 14, 17, 20, 24, 28, 33, 38, 43, 49, + 56, 63, 71, 79, 88, 98, 108, 119, 131, 143, 157, 171, + 186, 202, 219, 237, 256, 275, 296, 318, 341, 365, 390, 416, + 444, 472, 502, 533, 566, 600, 635, 671, 709, 748, 789, 831, + 875, 920, 967, 1015, 1065, 1116, 1170, 1224, 1281, 1339, 1399, 1461, + 1525, 1590, 1657, 1726, 1797, 1870, 1945, 2021, 2100, 2181, 2263, 2348, + 2434, 2523, 2614, 2706, 2801, 2898, 2997, 3099, 3202, 3307, 3415, 3525, + 3637, 3751, 3867, 3986, 4106, 4229, 4354, 4481, 4611, 4742, 4876, 5012, + 5150, 5291, 5433, 5578, 5725, 5874, 6025, 6178, 6333, 6490, 6650, 6811, + 6974, 7140, 7307, 7476, 7647, 7820, 7995, 8171, 8349, 8529, 8711, 8894, + 9079, 9265, 9453, 9642, 9833, 10024, 10217, 10412, 10607, 10803, 11000, 11199, + 11398, 11597, 11797, 11998, 12200, 12401, 12603, 12805, 13008, 13210, 13412, 13614, + 13815, 14016, 14216, 14416, 14615, 14813, 15009, 15205, 15399, 15591, 15782, 15971, + 16157, 16342, 16524, 16704, 16881, 17056, 17227, 17395, 17559, 17720, 17877, 18030, + 18179, 18323, 18462, 18597, 18727, 18851, 18970, 19082, 19189, 19290, 19384, 19471, + 19551, 19623, 19689, 19746, 19795, 19835, 19867, 19890, 19904, 19908, 19902, 19886, + 19860, 19823, 19775, 19715, 19644, 19561, 19465, 19357, 19237, 19102, 18955, 18793, + 18618, 18428, 18223, 18004, 17769, 17518, 17252, 16970, 16672, 16357, 16025, 15677, + 15311, 14929, 14529, 14111, 13677, 13225, 12755, 12268, 11764, 11243, 10706, 10152, + 9583, 8998, 8399, 7787, 7162, 6527, 5883, 5231, 4576, 3919, 3265, 2620, + 1990, 1386, 825, 333 +}; + + +/* By using a hearing threshold level in dB of -28 dB (higher value gives more noise), + the H_T_H (in float) can be calculated as: + H_T_H = pow(10.0, 0.05 * (-28.0)) = 0.039810717055350 + In Q19, H_T_H becomes round(0.039810717055350*2^19) ~= 20872, i.e. + H_T_H = 20872/524288.0, and H_T_HQ19 = 20872; +*/ + + +/* The bandwidth expansion vectors are created from: + kPolyVecLo=[0.900000,0.810000,0.729000,0.656100,0.590490,0.531441,0.478297,0.430467,0.387420,0.348678,0.313811,0.282430]; + kPolyVecHi=[0.800000,0.640000,0.512000,0.409600,0.327680,0.262144]; + round(kPolyVecLo*32768) + round(kPolyVecHi*32768) +*/ +static const WebRtc_Word16 kPolyVecLo[12] = { + 29491, 26542, 23888, 21499, 19349, 17414, 15673, 14106, 12695, 11425, 10283, 9255 +}; +static const WebRtc_Word16 kPolyVecHi[6] = { + 26214, 20972, 16777, 13422, 10737, 8590 +}; + +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; + +} + +static const WebRtc_Word16 kMulPitchGain = -25; /* 200/256 in Q5 */ +static const WebRtc_Word16 kChngFactor = 3523; /* log10(2)*10/4*0.4/1.4=log10(2)/1.4= 0.2150 in Q14 */ +static const WebRtc_Word16 kExp2 = 11819; /* 1/log(2) */ +const int kShiftLowerBand = 11; /* Shift value for lower band in Q domain. */ +const int kShiftHigherBand = 12; /* Shift value for higher band in Q domain. */ + +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]; +} + + + +static __inline WebRtc_Word16 exp2_Q10_T(WebRtc_Word16 x) { // Both in and out in Q10 + + WebRtc_Word16 tmp16_1, tmp16_2; + + tmp16_2=(WebRtc_Word16)(0x0400|(x&0x03FF)); + tmp16_1=-(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(x,10); + if(tmp16_1>0) + return (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + else + return (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + +} + + +// Declare function pointers. +AutocorrFix WebRtcIsacfix_AutocorrFix; +CalculateResidualEnergy WebRtcIsacfix_CalculateResidualEnergy; + +/* This routine calculates the residual energy for LPC. + * Formula as shown in comments inside. + */ +int32_t WebRtcIsacfix_CalculateResidualEnergyC(int lpc_order, + int32_t q_val_corr, + int q_val_polynomial, + int16_t* a_polynomial, + int32_t* corr_coeffs, + int* q_val_residual_energy) { + int i = 0, j = 0; + int shift_internal = 0, shift_norm = 0; + int32_t tmp32 = 0, word32_high = 0, word32_low = 0, residual_energy = 0; + int64_t sum64 = 0, sum64_tmp = 0; + + for (i = 0; i <= lpc_order; i++) { + for (j = i; j <= lpc_order; j++) { + /* For the case of i == 0: residual_energy += + * a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i]; + * For the case of i != 0: residual_energy += + * a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i] * 2; + */ + + tmp32 = WEBRTC_SPL_MUL_16_16(a_polynomial[j], a_polynomial[j - i]); + /* tmp32 in Q(q_val_polynomial * 2). */ + if (i != 0) { + tmp32 <<= 1; + } + sum64_tmp = (int64_t)tmp32 * (int64_t)corr_coeffs[i]; + sum64_tmp >>= shift_internal; + + /* Test overflow and sum the result. */ + if(((sum64_tmp > 0 && sum64 > 0) && (LLONG_MAX - sum64 < sum64_tmp)) || + ((sum64_tmp < 0 && sum64 < 0) && (LLONG_MIN - sum64 > sum64_tmp))) { + /* Shift right for overflow. */ + shift_internal += 1; + sum64 >>= 1; + sum64 += sum64_tmp >> 1; + } else { + sum64 += sum64_tmp; + } + } + } + + word32_high = (int32_t)(sum64 >> 32); + word32_low = (int32_t)sum64; + + // Calculate the value of shifting (shift_norm) for the 64-bit sum. + if(word32_high != 0) { + shift_norm = 32 - WebRtcSpl_NormW32(word32_high); + residual_energy = (int32_t)(sum64 >> shift_norm); + } else { + if((word32_low & 0x80000000) != 0) { + shift_norm = 1; + residual_energy = (uint32_t)word32_low >> 1; + } else { + shift_norm = WebRtcSpl_NormW32(word32_low); + residual_energy = word32_low << shift_norm; + shift_norm = -shift_norm; + } + } + + /* Q(q_val_polynomial * 2) * Q(q_val_corr) >> shift_internal >> shift_norm + * = Q(q_val_corr - shift_internal - shift_norm + q_val_polynomial * 2) + */ + *q_val_residual_energy = q_val_corr - shift_internal - shift_norm + + q_val_polynomial * 2; + + return residual_energy; +} + +void WebRtcIsacfix_GetLpcCoef(WebRtc_Word16 *inLoQ0, + WebRtc_Word16 *inHiQ0, + MaskFiltstr_enc *maskdata, + WebRtc_Word16 snrQ10, + const WebRtc_Word16 *pitchGains_Q12, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *lo_coeffQ15, + WebRtc_Word16 *hi_coeffQ15) +{ + int k, n, ii; + int pos1, pos2; + int sh_lo, sh_hi, sh, ssh, shMem; + WebRtc_Word16 varscaleQ14; + + WebRtc_Word16 tmpQQlo, tmpQQhi; + WebRtc_Word32 tmp32; + WebRtc_Word16 tmp16,tmp16b; + + WebRtc_Word16 polyHI[ORDERHI+1]; + WebRtc_Word16 rcQ15_lo[ORDERLO], rcQ15_hi[ORDERHI]; + + + WebRtc_Word16 DataLoQ6[WINLEN], DataHiQ6[WINLEN]; + WebRtc_Word32 corrloQQ[ORDERLO+2]; + WebRtc_Word32 corrhiQQ[ORDERHI+1]; + WebRtc_Word32 corrlo2QQ[ORDERLO+1]; + WebRtc_Word16 scale; + WebRtc_Word16 QdomLO, QdomHI, newQdomHI, newQdomLO; + + WebRtc_Word32 res_nrgQQ; + WebRtc_Word32 sqrt_nrg; + + /* less-noise-at-low-frequencies factor */ + WebRtc_Word16 aaQ14; + + /* Multiplication with 1/sqrt(12) ~= 0.28901734104046 can be done by convertion to + Q15, i.e. round(0.28901734104046*32768) = 9471, and use 9471/32768.0 ~= 0.289032 + */ + WebRtc_Word16 snrq; + int shft; + + WebRtc_Word16 tmp16a; + WebRtc_Word32 tmp32a, tmp32b, tmp32c; + + WebRtc_Word16 a_LOQ11[ORDERLO+1]; + WebRtc_Word16 k_vecloQ15[ORDERLO]; + WebRtc_Word16 a_HIQ12[ORDERHI+1]; + WebRtc_Word16 k_vechiQ15[ORDERHI]; + + WebRtc_Word16 stab; + + snrq=snrQ10; + + /* SNR= C * 2 ^ (D * snrq) ; C=0.289, D=0.05*log2(10)=0.166 (~=172 in Q10)*/ + tmp16 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(snrq, 172, 10); // Q10 + tmp16b = exp2_Q10_T(tmp16); // Q10 + snrq = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 285, 10); // Q10 + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsacfix_GetVars(inLoQ0, pitchGains_Q12, &(maskdata->OldEnergy), &varscaleQ14); + + /* less-noise-at-low-frequencies factor */ + /* Calculation of 0.35 * (0.5 + 0.5 * varscale) in fixpoint: + With 0.35 in Q16 (0.35 ~= 22938/65536.0 = 0.3500061) and varscaleQ14 in Q14, + we get Q16*Q14>>16 = Q14 + */ + aaQ14 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32( + (WEBRTC_SPL_MUL_16_16(22938, (8192 + WEBRTC_SPL_RSHIFT_W32(varscaleQ14, 1))) + + ((WebRtc_Word32)32768)), 16); + + /* Calculate tmp = (1.0 + aa*aa); in Q12 */ + tmp16 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(aaQ14, aaQ14, 15); //Q14*Q14>>15 = Q13 + tmpQQlo = 4096 + WEBRTC_SPL_RSHIFT_W16(tmp16, 1); // Q12 + Q13>>1 = Q12 + + /* Calculate tmp = (1.0+aa) * (1.0+aa); */ + tmp16 = 8192 + WEBRTC_SPL_RSHIFT_W16(aaQ14, 1); // 1+a in Q13 + tmpQQhi = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(tmp16, tmp16, 14); //Q13*Q13>>14 = Q12 + + /* replace data in buffer by new look-ahead data */ + for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) { + maskdata->DataBufferLoQ0[pos1 + WINLEN - QLOOKAHEAD] = inLoQ0[pos1]; + } + + for (k = 0; k < SUBFRAMES; k++) { + + /* Update input buffer and multiply signal with window */ + for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { + maskdata->DataBufferLoQ0[pos1] = maskdata->DataBufferLoQ0[pos1 + UPDATE/2]; + maskdata->DataBufferHiQ0[pos1] = maskdata->DataBufferHiQ0[pos1 + UPDATE/2]; + DataLoQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferLoQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + DataHiQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferHiQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + } + pos2 = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16(k, UPDATE)/2); + for (n = 0; n < UPDATE/2; n++, pos1++) { + maskdata->DataBufferLoQ0[pos1] = inLoQ0[QLOOKAHEAD + pos2]; + maskdata->DataBufferHiQ0[pos1] = inHiQ0[pos2++]; + DataLoQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferLoQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + DataHiQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferHiQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + } + + /* Get correlation coefficients */ + /* The highest absolute value measured inside DataLo in the test set + For DataHi, corresponding value was 160. + + This means that it should be possible to represent the input values + to WebRtcSpl_AutoCorrelation() as Q6 values (since 307*2^6 = + 19648). Of course, Q0 will also work, but due to the low energy in + DataLo and DataHi, the outputted autocorrelation will be more accurate + and mimic the floating point code better, by being in an high as possible + Q-domain. + */ + + WebRtcIsacfix_AutocorrFix(corrloQQ,DataLoQ6,WINLEN, ORDERLO+1, &scale); + QdomLO = 12-scale; // QdomLO is the Q-domain of corrloQQ + sh_lo = WebRtcSpl_NormW32(corrloQQ[0]); + QdomLO += sh_lo; + for (ii=0; ii<ORDERLO+2; ii++) { + corrloQQ[ii] = WEBRTC_SPL_LSHIFT_W32(corrloQQ[ii], sh_lo); + } + /* It is investigated whether it was possible to use 16 bits for the + 32-bit vector corrloQQ, but it didn't work. */ + + WebRtcIsacfix_AutocorrFix(corrhiQQ,DataHiQ6,WINLEN, ORDERHI, &scale); + + QdomHI = 12-scale; // QdomHI is the Q-domain of corrhiQQ + sh_hi = WebRtcSpl_NormW32(corrhiQQ[0]); + QdomHI += sh_hi; + for (ii=0; ii<ORDERHI+1; ii++) { + corrhiQQ[ii] = WEBRTC_SPL_LSHIFT_W32(corrhiQQ[ii], sh_hi); + } + + /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */ + + /* Calculate corrlo2[0] = tmpQQlo * corrlo[0] - 2.0*tmpQQlo * corrlo[1];*/ + corrlo2QQ[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[0]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5) + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, corrloQQ[1]), 2); // 2*Q(14+QdomLO-16)>>3 = Q(QdomLO-2)>>2 = Q(QdomLO-5) + + /* Calculate corrlo2[n] = tmpQQlo * corrlo[n] - tmpQQlo * (corrlo[n-1] + corrlo[n+1]);*/ + for (n = 1; n <= ORDERLO; n++) { + + tmp32 = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n-1], 1) + WEBRTC_SPL_RSHIFT_W32(corrloQQ[n+1], 1); // Q(QdomLO-1) + corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[n]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5) + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, tmp32), 2); // Q(14+QdomLO-1-16)>>2 = Q(QdomLO-3)>>2 = Q(QdomLO-5) + + } + QdomLO -= 5; + + /* Calculate corrhi[n] = tmpQQhi * corrhi[n]; */ + for (n = 0; n <= ORDERHI; n++) { + corrhiQQ[n] = WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQhi, corrhiQQ[n]); // Q(12+QdomHI-16) = Q(QdomHI-4) + } + QdomHI -= 4; + + /* add white noise floor */ + /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) */ + /* Calculate corrlo2[0] += 9.5367431640625e-7; and + corrhi[0] += 9.5367431640625e-7, where the constant is 1/2^20 */ + + tmp32 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32) 1, QdomLO-20); + corrlo2QQ[0] += tmp32; + tmp32 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32) 1, QdomHI-20); + corrhiQQ[0] += tmp32; + + /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) before the following + code segment, where we want to make sure we get a 1-bit margin */ + for (n = 0; n <= ORDERLO; n++) { + corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(corrlo2QQ[n], 1); // Make sure we have a 1-bit margin + } + QdomLO -= 1; // Now, corrlo2QQ is in Q(QdomLO), with a 1-bit margin + + for (n = 0; n <= ORDERHI; n++) { + corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], 1); // Make sure we have a 1-bit margin + } + QdomHI -= 1; // Now, corrhiQQ is in Q(QdomHI), with a 1-bit margin + + + newQdomLO = QdomLO; + + for (n = 0; n <= ORDERLO; n++) { + WebRtc_Word32 tmp, tmpB, tmpCorr; + WebRtc_Word16 alpha=328; //0.01 in Q15 + WebRtc_Word16 beta=324; //(1-0.01)*0.01=0.0099 in Q15 + WebRtc_Word16 gamma=32440; //(1-0.01)=0.99 in Q15 + + if (maskdata->CorrBufLoQQ[n] != 0) { + shMem=WebRtcSpl_NormW32(maskdata->CorrBufLoQQ[n]); + sh = QdomLO - maskdata->CorrBufLoQdom[n]; + if (sh<=shMem) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], sh); // Get CorrBufLoQQ to same domain as corrlo2 + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp); + } else if ((sh-shMem)<7){ + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufLoQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, (sh-shMem)), tmp); // Shift alpha the number of times required to get tmp in QdomLO + } else { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, 6), tmp); // Shift alpha as much as possible without overflow the number of times required to get tmp in QdomHI + tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], sh-shMem-6); + tmp = tmp + tmpCorr; + maskdata->CorrBufLoQQ[n] = tmp; + newQdomLO = QdomLO-(sh-shMem-6); + maskdata->CorrBufLoQdom[n] = newQdomLO; + } + } else + tmp = 0; + + tmp = tmp + corrlo2QQ[n]; + + maskdata->CorrBufLoQQ[n] = tmp; + maskdata->CorrBufLoQdom[n] = QdomLO; + + tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp); + tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, corrlo2QQ[n]); + corrlo2QQ[n] = tmp + tmpB; + } + if( newQdomLO!=QdomLO) { + for (n = 0; n <= ORDERLO; n++) { + if (maskdata->CorrBufLoQdom[n] != newQdomLO) + corrloQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], maskdata->CorrBufLoQdom[n]-newQdomLO); + } + QdomLO = newQdomLO; + } + + + newQdomHI = QdomHI; + + for (n = 0; n <= ORDERHI; n++) { + WebRtc_Word32 tmp, tmpB, tmpCorr; + WebRtc_Word16 alpha=328; //0.01 in Q15 + WebRtc_Word16 beta=324; //(1-0.01)*0.01=0.0099 in Q15 + WebRtc_Word16 gamma=32440; //(1-0.01)=0.99 in Q1 + if (maskdata->CorrBufHiQQ[n] != 0) { + shMem=WebRtcSpl_NormW32(maskdata->CorrBufHiQQ[n]); + sh = QdomHI - maskdata->CorrBufHiQdom[n]; + if (sh<=shMem) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], sh); // Get CorrBufHiQQ to same domain as corrhi + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp); + tmpCorr = corrhiQQ[n]; + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } else if ((sh-shMem)<7) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, (sh-shMem)), tmp); // Shift alpha the number of times required to get tmp in QdomHI + tmpCorr = corrhiQQ[n]; + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } else { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, 6), tmp); // Shift alpha as much as possible without overflow the number of times required to get tmp in QdomHI + tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], sh-shMem-6); + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + newQdomHI = QdomHI-(sh-shMem-6); + maskdata->CorrBufHiQdom[n] = newQdomHI; + } + } else { + tmp = corrhiQQ[n]; + tmpCorr = tmp; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } + + tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp); + tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, tmpCorr); + corrhiQQ[n] = tmp + tmpB; + } + + if( newQdomHI!=QdomHI) { + for (n = 0; n <= ORDERHI; n++) { + if (maskdata->CorrBufHiQdom[n] != newQdomHI) + corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], maskdata->CorrBufHiQdom[n]-newQdomHI); + } + QdomHI = newQdomHI; + } + + stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, ORDERLO); + + if (stab<0) { // If unstable use lower order + a_LOQ11[0]=2048; + for (n = 1; n <= ORDERLO; n++) { + a_LOQ11[n]=0; + } + + stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, 8); + } + + + WebRtcSpl_LevinsonDurbin(corrhiQQ, a_HIQ12, k_vechiQ15, ORDERHI); + + /* bandwidth expansion */ + for (n = 1; n <= ORDERLO; n++) { + a_LOQ11[n] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT_WITH_FIXROUND(kPolyVecLo[n-1], a_LOQ11[n]); + } + + + polyHI[0] = a_HIQ12[0]; + for (n = 1; n <= ORDERHI; n++) { + a_HIQ12[n] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT_WITH_FIXROUND(kPolyVecHi[n-1], a_HIQ12[n]); + polyHI[n] = a_HIQ12[n]; + } + + /* Normalize the corrlo2 vector */ + sh = WebRtcSpl_NormW32(corrlo2QQ[0]); + for (n = 0; n <= ORDERLO; n++) { + corrlo2QQ[n] = WEBRTC_SPL_LSHIFT_W32(corrlo2QQ[n], sh); + } + QdomLO += sh; /* Now, corrlo2QQ is still in Q(QdomLO) */ + + + /* residual energy */ + + sh_lo = 31; + res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERLO, QdomLO, + kShiftLowerBand, a_LOQ11, corrlo2QQ, &sh_lo); + + /* Convert to reflection coefficients */ + WebRtcSpl_AToK_JSK(a_LOQ11, ORDERLO, rcQ15_lo); + + if (sh_lo & 0x0001) { + res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1); + sh_lo-=1; + } + + + if( res_nrgQQ > 0 ) + { + sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ); + + /* add hearing threshold and compute the gain */ + /* lo_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */ + + + //tmp32a=WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, H_T_HQ19, 17); // Q14 + tmp32a=WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) varscaleQ14,1); // H_T_HQ19=65536 (16-17=-1) ssh= WEBRTC_SPL_RSHIFT_W16(sh_lo, 1); // sqrt_nrg is in Qssh + ssh= WEBRTC_SPL_RSHIFT_W16(sh_lo, 1); // sqrt_nrg is in Qssh + sh = ssh - 14; + tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh + tmp32c = sqrt_nrg + tmp32b; // Qssh (denominator) + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, snrq, 0); //Q24 (numerator) + + sh = WebRtcSpl_NormW32(tmp32c); + shft = 16 - sh; + tmp16a = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft) (denominator) + + tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft) + sh = ssh-shft-7; + *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh); // Gains in Q17 + } + else + { + *gain_lo_hiQ17 = 100; //(WebRtc_Word32)WEBRTC_SPL_LSHIFT_W32( (WebRtc_Word32)1, 17); // Gains in Q17 + } + gain_lo_hiQ17++; + + /* copy coefficients to output array */ + for (n = 0; n < ORDERLO; n++) { + *lo_coeffQ15 = (WebRtc_Word16) (rcQ15_lo[n]); + lo_coeffQ15++; + } + /* residual energy */ + sh_hi = 31; + res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERHI, QdomHI, + kShiftHigherBand, a_HIQ12, corrhiQQ, &sh_hi); + + /* Convert to reflection coefficients */ + WebRtcSpl_LpcToReflCoef(polyHI, ORDERHI, rcQ15_hi); + + if (sh_hi & 0x0001) { + res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1); + sh_hi-=1; + } + + + if( res_nrgQQ > 0 ) + { + sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ); + + + /* add hearing threshold and compute the gain */ + /* hi_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */ + + //tmp32a=WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, H_T_HQ19, 17); // Q14 + tmp32a=WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) varscaleQ14,1); // H_T_HQ19=65536 (16-17=-1) + + ssh= WEBRTC_SPL_RSHIFT_W32(sh_hi, 1); // sqrt_nrg is in Qssh + sh = ssh - 14; + tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh + tmp32c = sqrt_nrg + tmp32b; // Qssh (denominator) + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, snrq, 0); //Q24 (numerator) + + sh = WebRtcSpl_NormW32(tmp32c); + shft = 16 - sh; + tmp16a = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft) (denominator) + + tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft) + sh = ssh-shft-7; + *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh); // Gains in Q17 + } + else + { + *gain_lo_hiQ17 = 100; //(WebRtc_Word32)WEBRTC_SPL_LSHIFT_W32( (WebRtc_Word32)1, 17); // Gains in Q17 + } + gain_lo_hiQ17++; + + + /* copy coefficients to output array */ + for (n = 0; n < ORDERHI; n++) { + *hi_coeffQ15 = rcQ15_hi[n]; + hi_coeffQ15++; + } + } +} |