aboutsummaryrefslogtreecommitdiff
path: root/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c
diff options
context:
space:
mode:
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.c957
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++;
+ }
+ }
+}