1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
2173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * lpc_masking_model.c
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * LPC analysis and filtering functions
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
182d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org#include "lpc_masking_model.h"
19173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org
202d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org#include <limits.h>  /* For LLONG_MAX and LLONG_MIN. */
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "codec.h"
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "entropy_coding.h"
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "settings.h"
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* The conversion is implemented by the step-down algorithm */
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid WebRtcSpl_AToK_JSK(
270946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *a16, /* Q11 */
280946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t useOrder,
290946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *k16  /* Q15 */
30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        )
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int m, k;
330946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32[MAX_AR_MODEL_ORDER];
340946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32b;
350946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp_inv_denum32;
360946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp_inv_denum16;
37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
383ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  k16[useOrder-1] = a16[useOrder] << 4;  // Q11<<4 => Q15
39470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (m=useOrder-1; m>0; m--) {
41bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    // (1 - k^2) in Q30
42bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    tmp_inv_denum32 = 1073741823 - k16[m] * k16[m];
43a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    tmp_inv_denum16 = (int16_t)(tmp_inv_denum32 >> 15);  // (1 - k^2) in Q15.
44470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=1; k<=m; k++) {
46d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      tmp32b = (a16[k] << 16) - ((k16[m] * a16[m - k + 1]) << 1);
47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
48470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32[k] = WebRtcSpl_DivW32W16(tmp32b, tmp_inv_denum16); //Q27/Q15 = Q12
49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=1; k<m; k++) {
52a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      a16[k] = (int16_t)(tmp32[k] >> 1);  // Q12>>1 => Q11
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
54470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
55470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32[m] = WEBRTC_SPL_SAT(4092, tmp32[m], -4092);
56d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    k16[m - 1] = (int16_t)(tmp32[m] << 3);  // Q12<<3 => Q15
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return;
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
660946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgint16_t WebRtcSpl_LevinsonW32_JSK(
670946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int32_t *R,  /* (i) Autocorrelation of length >= order+1 */
680946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *A,  /* (o) A[0..order] LPC coefficients (Q11) */
690946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *K,  /* (o) K[0...order-1] Reflection coefficients (Q15) */
700946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t order /* (i) filter order */
71470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                        ) {
720946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t i, j;
730946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t R_hi[LEVINSON_MAX_ORDER+1], R_low[LEVINSON_MAX_ORDER+1];
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Aurocorr coefficients in high precision */
750946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t A_hi[LEVINSON_MAX_ORDER+1], A_low[LEVINSON_MAX_ORDER+1];
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* LPC coefficients in high precicion */
770946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t A_upd_hi[LEVINSON_MAX_ORDER+1], A_upd_low[LEVINSON_MAX_ORDER+1];
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* LPC coefficients for next iteration */
790946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t K_hi, K_low;      /* reflection coefficient in high precision */
800946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t Alpha_hi, Alpha_low, Alpha_exp; /* Prediction gain Alpha in high precision
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                   and with scale factor */
820946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp_hi, tmp_low;
830946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t temp1W32, temp2W32, temp3W32;
840946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t norm;
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Normalize the autocorrelation R[0]...R[order+1] */
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  norm = WebRtcSpl_NormW32(R[0]);
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (i=order;i>=0;i--) {
91d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    temp1W32 = R[i] << norm;
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Put R in hi and low format */
93a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    R_hi[i] = (int16_t)(temp1W32 >> 16);
94a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* K = A[1] = -R[1] / R[0] */
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
99d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker  temp2W32 = (R_hi[1] << 16) + (R_low[1] << 1);  /* R[1] in Q31      */
100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  temp3W32  = WEBRTC_SPL_ABS_W32(temp2W32);      /* abs R[1]         */
101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  temp1W32  = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); /* abs(R[1])/R[0] in Q31 */
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Put back the sign on R[1] */
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (temp2W32 > 0) {
104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    temp1W32 = -temp1W32;
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Put K in hi and low format */
108a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  K_hi = (int16_t)(temp1W32 >> 16);
109a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Store first reflection coefficient */
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  K[0] = K_hi;
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
114a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  temp1W32 >>= 4;  /* A[1] in Q27. */
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Put A[1] in hi and low format */
117a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  A_hi[1] = (int16_t)(temp1W32 >> 16);
118a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /*  Alpha = R[0] * (1-K^2) */
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
122a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  temp1W32  = (((K_hi * K_low) >> 14) + K_hi * K_hi) << 1;  /* = k^2 in Q31 */
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32);    /* Guard against <0 */
1250946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  temp1W32 = (int32_t)0x7fffffffL - temp1W32;    /* temp1W32 = (1 - K[0]*K[0]) in Q31 */
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Store temp1W32 = 1 - K[0]*K[0] on hi and low format */
128a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  tmp_hi = (int16_t)(temp1W32 >> 16);
129a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculate Alpha in Q31 */
132a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  temp1W32 = (R_hi[0] * tmp_hi + ((R_hi[0] * tmp_low) >> 15) +
133a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      ((R_low[0] * tmp_hi) >> 15)) << 1;
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Normalize Alpha and put it in hi and low format */
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Alpha_exp = WebRtcSpl_NormW32(temp1W32);
138d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker  temp1W32 <<= Alpha_exp;
139a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  Alpha_hi = (int16_t)(temp1W32 >> 16);
140a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi<< 16)) >> 1);
141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Perform the iterative calculations in the
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     Levinson Durbin algorithm */
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (i=2; i<=order; i++)
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*                    ----
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          \
150a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org        temp1W32 =  R[i] + > R[j]*A[i-j]
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          /
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          ----
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          j=1..i-1
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    */
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    temp1W32 = 0;
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for(j=1; j<i; j++) {
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* temp1W32 is in Q31 */
160a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      temp1W32 += ((R_hi[j] * A_hi[i - j]) << 1) +
161a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          ((((R_hi[j] * A_low[i - j]) >> 15) +
162a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org              ((R_low[j] * A_hi[i - j]) >> 15)) << 1);
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
165d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    temp1W32 <<= 4;
166d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    temp1W32 += (R_hi[i] << 16) + (R_low[i] << 1);
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* K = -temp1W32 / Alpha */
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32);      /* abs(temp1W32) */
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); /* abs(temp1W32)/Alpha */
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Put the sign of temp1W32 back again */
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (temp1W32 > 0) {
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      temp3W32 = -temp3W32;
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Use the Alpha shifts from earlier to denormalize */
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    norm = WebRtcSpl_NormW32(temp3W32);
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((Alpha_exp <= norm)||(temp3W32==0)) {
180d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      temp3W32 <<= Alpha_exp;
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else {
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (temp3W32 > 0)
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
1840946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        temp3W32 = (int32_t)0x7fffffffL;
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
1870946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        temp3W32 = (int32_t)0x80000000L;
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Put K on hi and low format */
192a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    K_hi = (int16_t)(temp3W32 >> 16);
193a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Store Reflection coefficient in Q15 */
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    K[i-1] = K_hi;
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Test for unstable filter. If unstable return 0 and let the
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       user decide what to do in that case
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    */
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2020946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    if ((int32_t)WEBRTC_SPL_ABS_W16(K_hi) > (int32_t)32740) {
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      return(-i); /* Unstable filter */
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      Compute updated LPC coefficient: Anew[i]
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      Anew[j]= A[j] + K*A[i-j]   for j=1..i-1
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      Anew[i]= K
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    */
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for(j=1; j<i; j++)
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
214d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      temp1W32 = (A_hi[j] << 16) + (A_low[j] << 1);  // temp1W32 = A[j] in Q27
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
216a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      temp1W32 += (K_hi * A_hi[i - j] + ((K_hi * A_low[i - j]) >> 15) +
217a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          ((K_low * A_hi[i - j]) >> 15)) << 1;  // temp1W32 += K*A[i-j] in Q27.
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* Put Anew in hi and low format */
220a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
221a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      A_upd_low[j] = (int16_t)((temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
224a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    temp3W32 >>= 4;  /* temp3W32 = K in Q27 (Convert from Q31 to Q27) */
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Store Anew in hi and low format */
227a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
228a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    A_upd_low[i] = (int16_t)((temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*  Alpha = Alpha * (1-K^2) */
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
232a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    temp1W32 = (((K_hi * K_low) >> 14) + K_hi * K_hi) << 1;  /* K*K in Q31 */
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32);      /* Guard against <0 */
2350946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    temp1W32 = (int32_t)0x7fffffffL - temp1W32;      /* 1 - K*K  in Q31 */
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Convert 1- K^2 in hi and low format */
238a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    tmp_hi = (int16_t)(temp1W32 >> 16);
239a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate Alpha = Alpha * (1-K^2) in Q31 */
242a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    temp1W32 = (Alpha_hi * tmp_hi + ((Alpha_hi * tmp_low) >> 15) +
243a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org        ((Alpha_low * tmp_hi) >> 15)) << 1;
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Normalize Alpha and store it on hi and low format */
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    norm = WebRtcSpl_NormW32(temp1W32);
248d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    temp1W32 <<= norm;
249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
250a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    Alpha_hi = (int16_t)(temp1W32 >> 16);
251a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Update the total nomalization of Alpha */
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Alpha_exp = Alpha_exp + norm;
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Update A[] */
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for(j=1; j<=i; j++)
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      A_hi[j] =A_upd_hi[j];
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      A_low[j] =A_upd_low[j];
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /*
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Set A[0] to 1.0 and store the A[i] i=1...order in Q12
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (Convert from Q27 and use rounding)
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  */
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  A[0] = 2048;
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for(i=1; i<=order; i++) {
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* temp1W32 in Q27 */
274d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    temp1W32 = (A_hi[i] << 16) + (A_low[i] << 1);
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Round and store upper word */
276a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    A[i] = (int16_t)((temp1W32 + 32768) >> 16);
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return(1); /* Stable filters */
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* window */
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Matlab generation of floating point code:
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid;
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * All values are multiplyed with 2^21 in fixed point code.
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
2910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kWindowAutocorr[WINLEN] = {
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  0,     0,     0,     0,     0,     1,     1,     2,     2,     3,     5,     6,
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  8,    10,    12,    14,    17,    20,    24,    28,    33,    38,    43,    49,
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  56,    63,    71,    79,    88,    98,   108,   119,   131,   143,   157,   171,
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  186,   202,   219,   237,   256,   275,   296,   318,   341,   365,   390,   416,
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  444,   472,   502,   533,   566,   600,   635,   671,   709,   748,   789,   831,
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  875,   920,   967,  1015,  1065,  1116,  1170,  1224,  1281,  1339,  1399,  1461,
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  1525,  1590,  1657,  1726,  1797,  1870,  1945,  2021,  2100,  2181,  2263,  2348,
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  2434,  2523,  2614,  2706,  2801,  2898,  2997,  3099,  3202,  3307,  3415,  3525,
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  3637,  3751,  3867,  3986,  4106,  4229,  4354,  4481,  4611,  4742,  4876,  5012,
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  5150,  5291,  5433,  5578,  5725,  5874,  6025,  6178,  6333,  6490,  6650,  6811,
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  6974,  7140,  7307,  7476,  7647,  7820,  7995,  8171,  8349,  8529,  8711,  8894,
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  9079,  9265,  9453,  9642,  9833, 10024, 10217, 10412, 10607, 10803, 11000, 11199,
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  11398, 11597, 11797, 11998, 12200, 12401, 12603, 12805, 13008, 13210, 13412, 13614,
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  13815, 14016, 14216, 14416, 14615, 14813, 15009, 15205, 15399, 15591, 15782, 15971,
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  16157, 16342, 16524, 16704, 16881, 17056, 17227, 17395, 17559, 17720, 17877, 18030,
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  18179, 18323, 18462, 18597, 18727, 18851, 18970, 19082, 19189, 19290, 19384, 19471,
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  19551, 19623, 19689, 19746, 19795, 19835, 19867, 19890, 19904, 19908, 19902, 19886,
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  19860, 19823, 19775, 19715, 19644, 19561, 19465, 19357, 19237, 19102, 18955, 18793,
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  18618, 18428, 18223, 18004, 17769, 17518, 17252, 16970, 16672, 16357, 16025, 15677,
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  15311, 14929, 14529, 14111, 13677, 13225, 12755, 12268, 11764, 11243, 10706, 10152,
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  9583,  8998,  8399,  7787,  7162,  6527,  5883,  5231,  4576,  3919,  3265,  2620,
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  1990,  1386,   825,   333
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com};
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* By using a hearing threshold level in dB of -28 dB (higher value gives more noise),
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   the H_T_H (in float) can be calculated as:
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   H_T_H = pow(10.0, 0.05 * (-28.0)) = 0.039810717055350
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   In Q19, H_T_H becomes round(0.039810717055350*2^19) ~= 20872, i.e.
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   H_T_H = 20872/524288.0, and H_T_HQ19 = 20872;
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* The bandwidth expansion vectors are created from:
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   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];
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   kPolyVecHi=[0.800000,0.640000,0.512000,0.409600,0.327680,0.262144];
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   round(kPolyVecLo*32768)
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   round(kPolyVecHi*32768)
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
3310946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kPolyVecLo[12] = {
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  29491, 26542, 23888, 21499, 19349, 17414, 15673, 14106, 12695, 11425, 10283, 9255
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com};
3340946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kPolyVecHi[6] = {
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  26214, 20972, 16777, 13422, 10737, 8590
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com};
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3380946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic __inline int32_t log2_Q8_LPC( uint32_t x ) {
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3403ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  int32_t zeros;
3410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t frac;
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  zeros=WebRtcSpl_NormU32(x);
344a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23);
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* log2(x) */
3473ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  return ((31 - zeros) << 8) + frac;
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3500946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kMulPitchGain = -25; /* 200/256 in Q5 */
3510946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kChngFactor = 3523; /* log10(2)*10/4*0.4/1.4=log10(2)/1.4= 0.2150 in Q14 */
3520946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic const int16_t kExp2 = 11819; /* 1/log(2) */
353173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.orgconst int kShiftLowerBand = 11;  /* Shift value for lower band in Q domain. */
354173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.orgconst int kShiftHigherBand = 12;  /* Shift value for higher band in Q domain. */
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3560946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgvoid WebRtcIsacfix_GetVars(const int16_t *input, const int16_t *pitchGains_Q12,
3570946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                           uint32_t *oldEnergy, int16_t *varscale)
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k;
3600946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t nrgQ[4];
3610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t nrgQlog[4];
3620946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16, chng1, chng2, chng3, chng4, tmp, chngQ, oldNrgQlog, pgQ, pg3;
3630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t expPg32;
3640946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t expPg, divVal;
3650946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16_1, tmp16_2;
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculate energies of first and second frame halfs */
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nrgQ[0]=0;
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES/4 + QLOOKAHEAD) / 2; k++) {
370bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    nrgQ[0] += (uint32_t)(input[k] * input[k]);
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nrgQ[1]=0;
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for ( ; k < (FRAMESAMPLES/2 + QLOOKAHEAD) / 2; k++) {
374bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    nrgQ[1] += (uint32_t)(input[k] * input[k]);
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nrgQ[2]=0;
377bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org  for ( ; k < (FRAMESAMPLES * 3 / 4 + QLOOKAHEAD) / 2; k++) {
378bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    nrgQ[2] += (uint32_t)(input[k] * input[k]);
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nrgQ[3]=0;
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) {
382bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    nrgQ[3] += (uint32_t)(input[k] * input[k]);
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for ( k=0; k<4; k++) {
3860946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    nrgQlog[k] = (int16_t)log2_Q8_LPC(nrgQ[k]); /* log2(nrgQ) */
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
3880946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  oldNrgQlog = (int16_t)log2_Q8_LPC(*oldEnergy);
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculate average level change */
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  chng1 = WEBRTC_SPL_ABS_W16(nrgQlog[3]-nrgQlog[2]);
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  chng2 = WEBRTC_SPL_ABS_W16(nrgQlog[2]-nrgQlog[1]);
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  chng3 = WEBRTC_SPL_ABS_W16(nrgQlog[1]-nrgQlog[0]);
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  chng4 = WEBRTC_SPL_ABS_W16(nrgQlog[0]-oldNrgQlog);
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  tmp = chng1+chng2+chng3+chng4;
396f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  chngQ = (int16_t)(tmp * kChngFactor >> 10);  /* Q12 */
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  chngQ += 2926; /* + 1.0/1.4 in Q12 */
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Find average pitch gain */
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  pgQ = 0;
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<4; k++)
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pgQ += pitchGains_Q12[k];
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
406f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pg3 = (int16_t)(pgQ * pgQ >> 11);  // pgQ in Q(12+2)=Q14. Q14*Q14>>11 => Q17
407f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pg3 = (int16_t)(pgQ * pg3 >> 13);  /* Q14*Q17>>13 =>Q18  */
408f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  /* kMulPitchGain = -25 = -200 in Q-3. */
409f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pg3 = (int16_t)(pg3 * kMulPitchGain >> 5);  // Q10
4100946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  tmp16=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,pg3,13);/* Q13*Q10>>13 => Q10*/
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (tmp16<0) {
412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16_2 = (0x0400 | (tmp16 & 0x03FF));
413f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org    tmp16_1 = ((uint16_t)(tmp16 ^ 0xFFFF) >> 10) - 3;  /* Gives result in Q14 */
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (tmp16_1<0)
4153ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org      expPg = -(tmp16_2 << -tmp16_1);
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
417f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      expPg = -(tmp16_2 >> tmp16_1);
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else
4190946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    expPg = (int16_t) -16384; /* 1 in Q14, since 2^0=1 */
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4213ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  expPg32 = (int32_t)expPg << 8;  /* Q22 */
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  divVal = WebRtcSpl_DivW32W16ResW16(expPg32, chngQ); /* Q22/Q12=Q10 */
423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4240946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  tmp16=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,divVal,13);/* Q13*Q10>>13 => Q10*/
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (tmp16<0) {
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16_2 = (0x0400 | (tmp16 & 0x03FF));
427f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org    tmp16_1 = ((uint16_t)(tmp16 ^ 0xFFFF) >> 10) - 3;  /* Gives result in Q14 */
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (tmp16_1<0)
4293ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org      expPg = tmp16_2 << -tmp16_1;
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
431f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      expPg = tmp16_2 >> tmp16_1;
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else
4330946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    expPg = (int16_t) 16384; /* 1 in Q14, since 2^0=1 */
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *varscale = expPg-1;
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *oldEnergy = nrgQ[3];
437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic __inline int16_t  exp2_Q10_T(int16_t x) { // Both in and out in Q10
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16_1, tmp16_2;
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  tmp16_2=(int16_t)(0x0400|(x&0x03FF));
446f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org  tmp16_1 = -(x >> 10);
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if(tmp16_1>0)
448f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org    return tmp16_2 >> tmp16_1;
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
4503ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org    return tmp16_2 << -tmp16_1;
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
454e8482f0e9ff1e9733719f58b4dd6c5d6d776a93akma@webrtc.org
455e8482f0e9ff1e9733719f58b4dd6c5d6d776a93akma@webrtc.org// Declare function pointers.
456e8482f0e9ff1e9733719f58b4dd6c5d6d776a93akma@webrtc.orgAutocorrFix WebRtcIsacfix_AutocorrFix;
457e8482f0e9ff1e9733719f58b4dd6c5d6d776a93akma@webrtc.orgCalculateResidualEnergy WebRtcIsacfix_CalculateResidualEnergy;
458e8482f0e9ff1e9733719f58b4dd6c5d6d776a93akma@webrtc.org
459173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org/* This routine calculates the residual energy for LPC.
460173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org * Formula as shown in comments inside.
461173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org */
462a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.orgint32_t WebRtcIsacfix_CalculateResidualEnergyC(int lpc_order,
463a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.org                                               int32_t q_val_corr,
464a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.org                                               int q_val_polynomial,
465a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.org                                               int16_t* a_polynomial,
466a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.org                                               int32_t* corr_coeffs,
467a15ea4965ef07f6aa074339f206383028e3b8898kma@webrtc.org                                               int* q_val_residual_energy) {
4682d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  int i = 0, j = 0;
4692d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  int shift_internal = 0, shift_norm = 0;
4702d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  int32_t tmp32 = 0, word32_high = 0, word32_low = 0, residual_energy = 0;
4712d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  int64_t sum64 = 0, sum64_tmp = 0;
4722d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org
4732d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  for (i = 0; i <= lpc_order; i++) {
4742d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    for (j = i; j <= lpc_order; j++) {
4752d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      /* For the case of i == 0: residual_energy +=
4762d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org       *    a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i];
4772d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org       * For the case of i != 0: residual_energy +=
4782d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org       *    a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i] * 2;
479173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org       */
480173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org
481bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org      tmp32 = a_polynomial[j] * a_polynomial[j - i];
4822d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org                                   /* tmp32 in Q(q_val_polynomial * 2). */
4832d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      if (i != 0) {
484173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org        tmp32 <<= 1;
485173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org      }
4862d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      sum64_tmp = (int64_t)tmp32 * (int64_t)corr_coeffs[i];
4872d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      sum64_tmp >>= shift_internal;
4882d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org
4892d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      /* Test overflow and sum the result. */
4902d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      if(((sum64_tmp > 0 && sum64 > 0) && (LLONG_MAX - sum64 < sum64_tmp)) ||
4912d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org         ((sum64_tmp < 0 && sum64 < 0) && (LLONG_MIN - sum64 > sum64_tmp))) {
4922d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        /* Shift right for overflow. */
4932d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        shift_internal += 1;
4942d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        sum64 >>= 1;
4952d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        sum64 += sum64_tmp >> 1;
4962d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      } else {
4972d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        sum64 += sum64_tmp;
498173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org      }
4992d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    }
5002d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  }
501173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org
5022d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  word32_high = (int32_t)(sum64 >> 32);
5032d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  word32_low = (int32_t)sum64;
5042d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org
5052d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  // Calculate the value of shifting (shift_norm) for the 64-bit sum.
5062d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  if(word32_high != 0) {
5072d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    shift_norm = 32 - WebRtcSpl_NormW32(word32_high);
5082d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    residual_energy = (int32_t)(sum64 >> shift_norm);
5092d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  } else {
510620a2563d0798eb0fac486814f9166c298d45b20kma@webrtc.org    if((word32_low & 0x80000000) != 0) {
5112d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      shift_norm = 1;
512620a2563d0798eb0fac486814f9166c298d45b20kma@webrtc.org      residual_energy = (uint32_t)word32_low >> 1;
5132d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    } else {
5142d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      shift_norm = WebRtcSpl_NormW32(word32_low);
5152d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      residual_energy = word32_low << shift_norm;
5162d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org      shift_norm = -shift_norm;
517173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org    }
518173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  }
5192d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org
5202d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  /* Q(q_val_polynomial * 2) * Q(q_val_corr) >> shift_internal >> shift_norm
5212d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org   *   = Q(q_val_corr - shift_internal - shift_norm + q_val_polynomial * 2)
5222d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org   */
5232d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org  *q_val_residual_energy = q_val_corr - shift_internal - shift_norm
5242d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org                           + q_val_polynomial * 2;
5252d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org
526173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  return residual_energy;
527173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org}
528173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org
5290946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgvoid WebRtcIsacfix_GetLpcCoef(int16_t *inLoQ0,
5300946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              int16_t *inHiQ0,
531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              MaskFiltstr_enc *maskdata,
5320946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              int16_t snrQ10,
5330946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              const int16_t *pitchGains_Q12,
5340946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              int32_t *gain_lo_hiQ17,
5350946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              int16_t *lo_coeffQ15,
5360946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                              int16_t *hi_coeffQ15)
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
538173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  int k, n, ii;
539173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  int pos1, pos2;
540173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  int sh_lo, sh_hi, sh, ssh, shMem;
5410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t varscaleQ14;
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmpQQlo, tmpQQhi;
5440946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32;
5450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16,tmp16b;
546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5470946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t polyHI[ORDERHI+1];
5480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t rcQ15_lo[ORDERLO], rcQ15_hi[ORDERHI];
549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5510946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t DataLoQ6[WINLEN], DataHiQ6[WINLEN];
5520946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t corrloQQ[ORDERLO+2];
5530946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t corrhiQQ[ORDERHI+1];
5540946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t corrlo2QQ[ORDERLO+1];
5550946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t scale;
5560946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t QdomLO, QdomHI, newQdomHI, newQdomLO;
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5580946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t res_nrgQQ;
5590946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t sqrt_nrg;
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* less-noise-at-low-frequencies factor */
5620946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t aaQ14;
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Multiplication with 1/sqrt(12) ~= 0.28901734104046 can be done by convertion to
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     Q15, i.e. round(0.28901734104046*32768) = 9471, and use 9471/32768.0 ~= 0.289032
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  */
5670946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t snrq;
568173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org  int shft;
569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5700946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16a;
5710946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32a, tmp32b, tmp32c;
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5730946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t a_LOQ11[ORDERLO+1];
5740946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t k_vecloQ15[ORDERLO];
5750946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t a_HIQ12[ORDERHI+1];
5760946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t k_vechiQ15[ORDERHI];
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5780946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t stab;
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  snrq=snrQ10;
581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* SNR= C * 2 ^ (D * snrq) ; C=0.289, D=0.05*log2(10)=0.166 (~=172 in Q10)*/
583f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  tmp16 = (int16_t)(snrq * 172 >> 10);  // Q10
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  tmp16b = exp2_Q10_T(tmp16); // Q10
585f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  snrq = (int16_t)(tmp16b * 285 >> 10);  // Q10
586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* change quallevel depending on pitch gains and level fluctuations */
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_GetVars(inLoQ0, pitchGains_Q12, &(maskdata->OldEnergy), &varscaleQ14);
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* less-noise-at-low-frequencies factor */
591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculation of 0.35 * (0.5 + 0.5 * varscale) in fixpoint:
592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     With 0.35 in Q16 (0.35 ~= 22938/65536.0 = 0.3500061) and varscaleQ14 in Q14,
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     we get Q16*Q14>>16 = Q14
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  */
595a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  aaQ14 = (int16_t)((22938 * (8192 + (varscaleQ14 >> 1)) + 32768) >> 16);
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculate tmp = (1.0 + aa*aa); in Q12 */
598f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  tmp16 = (int16_t)(aaQ14 * aaQ14 >> 15);  // Q14*Q14>>15 = Q13
599f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org  tmpQQlo = 4096 + (tmp16 >> 1);  // Q12 + Q13>>1 = Q12.
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Calculate tmp = (1.0+aa) * (1.0+aa); */
602f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org  tmp16 = 8192 + (aaQ14 >> 1);  // 1+a in Q13.
603f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  tmpQQhi = (int16_t)(tmp16 * tmp16 >> 14);  // Q13*Q13>>14 = Q12
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* replace data in buffer by new look-ahead data */
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) {
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    maskdata->DataBufferLoQ0[pos1 + WINLEN - QLOOKAHEAD] = inLoQ0[pos1];
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < SUBFRAMES; k++) {
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Update input buffer and multiply signal with window */
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) {
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->DataBufferLoQ0[pos1] = maskdata->DataBufferLoQ0[pos1 + UPDATE/2];
615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->DataBufferHiQ0[pos1] = maskdata->DataBufferHiQ0[pos1 + UPDATE/2];
616f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      DataLoQ6[pos1] = (int16_t)(maskdata->DataBufferLoQ0[pos1] *
617f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker          kWindowAutocorr[pos1] >> 15);  // Q0*Q21>>15 = Q6
618f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      DataHiQ6[pos1] = (int16_t)(maskdata->DataBufferHiQ0[pos1] *
619f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker          kWindowAutocorr[pos1] >> 15);  // Q0*Q21>>15 = Q6
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
621bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    pos2 = (int16_t)(k * UPDATE / 2);
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < UPDATE/2; n++, pos1++) {
623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->DataBufferLoQ0[pos1] = inLoQ0[QLOOKAHEAD + pos2];
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->DataBufferHiQ0[pos1] = inHiQ0[pos2++];
625f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      DataLoQ6[pos1] = (int16_t)(maskdata->DataBufferLoQ0[pos1] *
626f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker          kWindowAutocorr[pos1] >> 15);  // Q0*Q21>>15 = Q6
627f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      DataHiQ6[pos1] = (int16_t)(maskdata->DataBufferHiQ0[pos1] *
628f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker          kWindowAutocorr[pos1] >> 15);  // Q0*Q21>>15 = Q6
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Get correlation coefficients */
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* The highest absolute value measured inside DataLo in the test set
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       For DataHi, corresponding value was 160.
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       This means that it should be possible to represent the input values
636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       to WebRtcSpl_AutoCorrelation() as Q6 values (since 307*2^6 =
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       19648). Of course, Q0 will also work, but due to the low energy in
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       DataLo and DataHi, the outputted autocorrelation will be more accurate
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       and mimic the floating point code better, by being in an high as possible
640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       Q-domain.
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    */
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcIsacfix_AutocorrFix(corrloQQ,DataLoQ6,WINLEN, ORDERLO+1, &scale);
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomLO = 12-scale; // QdomLO is the Q-domain of corrloQQ
645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh_lo = WebRtcSpl_NormW32(corrloQQ[0]);
646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomLO += sh_lo;
647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (ii=0; ii<ORDERLO+2; ii++) {
648d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      corrloQQ[ii] <<= sh_lo;
649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* It is investigated whether it was possible to use 16 bits for the
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       32-bit vector corrloQQ, but it didn't work. */
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcIsacfix_AutocorrFix(corrhiQQ,DataHiQ6,WINLEN, ORDERHI, &scale);
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomHI = 12-scale; // QdomHI is the Q-domain of corrhiQQ
656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh_hi = WebRtcSpl_NormW32(corrhiQQ[0]);
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomHI += sh_hi;
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (ii=0; ii<ORDERHI+1; ii++) {
659d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      corrhiQQ[ii] <<= sh_hi;
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */
663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate corrlo2[0] = tmpQQlo * corrlo[0] - 2.0*tmpQQlo * corrlo[1];*/
665a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    // |corrlo2QQ| in Q(QdomLO-5).
666a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    corrlo2QQ[0] = (WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[0]) >> 1) -
667a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org        (WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, corrloQQ[1]) >> 2);
668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate corrlo2[n] = tmpQQlo * corrlo[n] - tmpQQlo * (corrlo[n-1] + corrlo[n+1]);*/
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 1; n <= ORDERLO; n++) {
671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
672a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      tmp32 = (corrloQQ[n - 1] >> 1) + (corrloQQ[n + 1] >> 1);  // Q(QdomLO-1).
673a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      corrlo2QQ[n] = (WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[n]) >> 1) -
674a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          (WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, tmp32) >> 2);
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomLO -= 5;
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate corrhi[n] = tmpQQhi * corrhi[n]; */
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERHI; n++) {
680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      corrhiQQ[n] = WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQhi, corrhiQQ[n]); // Q(12+QdomHI-16) = Q(QdomHI-4)
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomHI -= 4;
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* add white noise floor */
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) */
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate corrlo2[0] += 9.5367431640625e-7; and
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       corrhi[0]  += 9.5367431640625e-7, where the constant is 1/2^20 */
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6890946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t) 1, QdomLO-20);
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    corrlo2QQ[0] += tmp32;
6910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t) 1, QdomHI-20);
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    corrhiQQ[0]  += tmp32;
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) before the following
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       code segment, where we want to make sure we get a 1-bit margin */
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERLO; n++) {
697a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      corrlo2QQ[n] >>= 1;  // Make sure we have a 1-bit margin.
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomLO -= 1; // Now, corrlo2QQ is in Q(QdomLO), with a 1-bit margin
700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERHI; n++) {
702a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      corrhiQQ[n] >>= 1;  // Make sure we have a 1-bit margin.
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomHI -= 1; // Now, corrhiQQ is in Q(QdomHI), with a 1-bit margin
705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    newQdomLO = QdomLO;
708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERLO; n++) {
7100946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int32_t tmp, tmpB, tmpCorr;
7110946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t alpha=328; //0.01 in Q15
7120946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t beta=324; //(1-0.01)*0.01=0.0099 in Q15
7130946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t gamma=32440; //(1-0.01)=0.99 in Q15
714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (maskdata->CorrBufLoQQ[n] != 0) {
716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        shMem=WebRtcSpl_NormW32(maskdata->CorrBufLoQQ[n]);
717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        sh = QdomLO - maskdata->CorrBufLoQdom[n];
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (sh<=shMem) {
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], sh); // Get CorrBufLoQQ to same domain as corrlo2
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp);
721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        } else if ((sh-shMem)<7){
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufLoQQ as much as possible
7233ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // Shift |alpha| the number of times required to get |tmp| in QdomLO.
7243ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << (sh - shMem), tmp);
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        } else {
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible
7273ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // Shift |alpha| as much as possible without overflow the number of
7283ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // times required to get |tmp| in QdomLO.
7293ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << 6, tmp);
730a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          tmpCorr = corrloQQ[n] >> (sh - shMem - 6);
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = tmp + tmpCorr;
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufLoQQ[n] = tmp;
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          newQdomLO = QdomLO-(sh-shMem-6);
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufLoQdom[n] = newQdomLO;
735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        tmp = 0;
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp = tmp + corrlo2QQ[n];
740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->CorrBufLoQQ[n] = tmp;
742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maskdata->CorrBufLoQdom[n] = QdomLO;
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp);
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, corrlo2QQ[n]);
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      corrlo2QQ[n] = tmp + tmpB;
747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( newQdomLO!=QdomLO) {
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for (n = 0; n <= ORDERLO; n++) {
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (maskdata->CorrBufLoQdom[n] != newQdomLO)
751a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          corrloQQ[n] >>= maskdata->CorrBufLoQdom[n] - newQdomLO;
752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      QdomLO = newQdomLO;
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    newQdomHI = QdomHI;
758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERHI; n++) {
7600946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int32_t tmp, tmpB, tmpCorr;
7610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t alpha=328; //0.01 in Q15
7620946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t beta=324; //(1-0.01)*0.01=0.0099 in Q15
7630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      int16_t gamma=32440; //(1-0.01)=0.99 in Q1
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (maskdata->CorrBufHiQQ[n] != 0) {
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        shMem=WebRtcSpl_NormW32(maskdata->CorrBufHiQQ[n]);
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        sh = QdomHI - maskdata->CorrBufHiQdom[n];
767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (sh<=shMem) {
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], sh); // Get CorrBufHiQQ to same domain as corrhi
769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp);
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmpCorr = corrhiQQ[n];
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = tmp + tmpCorr;
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQQ[n] = tmp;
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQdom[n] = QdomHI;
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        } else if ((sh-shMem)<7) {
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible
7763ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // Shift |alpha| the number of times required to get |tmp| in QdomHI.
7773ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << (sh - shMem), tmp);
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmpCorr = corrhiQQ[n];
779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = tmp + tmpCorr;
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQQ[n] = tmp;
781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQdom[n] = QdomHI;
782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        } else {
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible
7843ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // Shift |alpha| as much as possible without overflow the number of
7853ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          // times required to get |tmp| in QdomHI.
7863ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org          tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << 6, tmp);
787a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          tmpCorr = corrhiQQ[n] >> (sh - shMem - 6);
788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          tmp = tmp + tmpCorr;
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQQ[n] = tmp;
790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          newQdomHI = QdomHI-(sh-shMem-6);
791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          maskdata->CorrBufHiQdom[n] = newQdomHI;
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        tmp = corrhiQQ[n];
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        tmpCorr = tmp;
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        maskdata->CorrBufHiQQ[n] = tmp;
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        maskdata->CorrBufHiQdom[n] = QdomHI;
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp);
801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, tmpCorr);
802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      corrhiQQ[n] = tmp + tmpB;
803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( newQdomHI!=QdomHI) {
806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for (n = 0; n <= ORDERHI; n++) {
807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (maskdata->CorrBufHiQdom[n] != newQdomHI)
808a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          corrhiQQ[n] >>= maskdata->CorrBufHiQdom[n] - newQdomHI;
809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      QdomHI = newQdomHI;
811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, ORDERLO);
814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (stab<0) {  // If unstable use lower order
816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      a_LOQ11[0]=2048;
817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for (n = 1; n <= ORDERLO; n++) {
818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        a_LOQ11[n]=0;
819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, 8);
822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_LevinsonDurbin(corrhiQQ,  a_HIQ12,  k_vechiQ15, ORDERHI);
826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* bandwidth expansion */
828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 1; n <= ORDERLO; n++) {
829bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org      a_LOQ11[n] = (int16_t)((kPolyVecLo[n - 1] * a_LOQ11[n] + (1 << 14)) >>
830bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org          15);
831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    polyHI[0] = a_HIQ12[0];
835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 1; n <= ORDERHI; n++) {
836bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org      a_HIQ12[n] = (int16_t)(((int32_t)(kPolyVecHi[n - 1] * a_HIQ12[n]) +
837bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org        (1 << 14)) >> 15);
838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      polyHI[n] = a_HIQ12[n];
839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Normalize the corrlo2 vector */
842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh = WebRtcSpl_NormW32(corrlo2QQ[0]);
843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= ORDERLO; n++) {
844d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      corrlo2QQ[n] <<= sh;
845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    QdomLO += sh; /* Now, corrlo2QQ is still in Q(QdomLO) */
847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* residual energy */
850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh_lo = 31;
8522d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERLO, QdomLO,
8532d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        kShiftLowerBand, a_LOQ11, corrlo2QQ, &sh_lo);
854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
855173538faa35c01e1b861767212a79c02a9253dd7kma@webrtc.org    /* Convert to reflection coefficients */
856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_AToK_JSK(a_LOQ11, ORDERLO, rcQ15_lo);
857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (sh_lo & 0x0001) {
859a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      res_nrgQQ >>= 1;
860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh_lo-=1;
861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( res_nrgQQ > 0 )
865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ);
867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* add hearing threshold and compute the gain */
869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* lo_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */
870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
871f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      tmp32a = varscaleQ14 >> 1;  // H_T_HQ19=65536 (16-17=-1)
872f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      ssh = sh_lo >> 1;  // sqrt_nrg is in Qssh.
873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = ssh - 14;
874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh
875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32c = sqrt_nrg + tmp32b;  // Qssh  (denominator)
876f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      tmp32a = varscaleQ14 * snrq;  // Q24 (numerator)
877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = WebRtcSpl_NormW32(tmp32c);
879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      shft = 16 - sh;
8800946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      tmp16a = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft)  (denominator)
881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft)
883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = ssh-shft-7;
884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh);  // Gains in Q17
885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
888d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      *gain_lo_hiQ17 = 100;  // Gains in Q17
889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17++;
891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* copy coefficients to output array */
893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < ORDERLO; n++) {
8940946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      *lo_coeffQ15 = (int16_t) (rcQ15_lo[n]);
895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      lo_coeffQ15++;
896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* residual energy */
898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh_hi = 31;
8992d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org    res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERHI, QdomHI,
9002d4c4ae55388d98350683b7b53b0f1273d65bff6kma@webrtc.org        kShiftHigherBand, a_HIQ12, corrhiQQ, &sh_hi);
901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Convert to reflection coefficients */
903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_LpcToReflCoef(polyHI, ORDERHI, rcQ15_hi);
904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (sh_hi & 0x0001) {
906a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      res_nrgQQ >>= 1;
907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh_hi-=1;
908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( res_nrgQQ > 0 )
912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ);
914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* add hearing threshold and compute the gain */
917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* hi_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */
918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
919a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      tmp32a = varscaleQ14 >> 1;  // H_T_HQ19=65536 (16-17=-1)
920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
921a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      ssh = sh_hi >> 1;  // |sqrt_nrg| is in Qssh.
922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = ssh - 14;
923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh
924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32c = sqrt_nrg + tmp32b;  // Qssh  (denominator)
925f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      tmp32a = varscaleQ14 * snrq;  // Q24 (numerator)
926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = WebRtcSpl_NormW32(tmp32c);
928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      shft = 16 - sh;
9290946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      tmp16a = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft)  (denominator)
930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft)
932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sh = ssh-shft-7;
933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh);  // Gains in Q17
934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
937d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      *gain_lo_hiQ17 = 100;  // Gains in Q17
938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17++;
940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* copy coefficients to output array */
943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < ORDERHI; n++) {
944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *hi_coeffQ15 = rcQ15_hi[n];
945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      hi_coeffQ15++;
946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
949