entropy_coding.c revision 23da8622c04ac843f7912dd33b4ad55f41422119
1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
2470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Copyright (c) 2011 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 * entropy_coding.c
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * This file contains all functions used to arithmetically
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * encode the iSAC bistream.
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <stddef.h>
20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "arith_routins.h"
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "spectrum_ar_model_tables.h"
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "pitch_gain_tables.h"
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "pitch_lag_tables.h"
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "entropy_coding.h"
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "lpc_tables.h"
27470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "settings.h"
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "signal_processing_library.h"
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org/*
3123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org * Eenumerations for arguments to functions WebRtcIsacfix_MatrixProduct1()
3223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org * and WebRtcIsacfix_MatrixProduct2().
3323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org*/
3423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
3523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgenum matrix_index_factor {
3623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexFactor1 = 1,
3723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexFactor2 = 2,
3823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexFactor3 = SUBFRAMES,
3923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexFactor4 = LPC_SHAPE_ORDER
4023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org};
4123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
4223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgenum matrix_index_step {
4323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexStep1 = 1,
4423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexStep2 = SUBFRAMES,
4523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTIndexStep3 = LPC_SHAPE_ORDER
4623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org};
4723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
4823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgenum matrixprod_loop_count {
4923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTLoopCount1 = SUBFRAMES,
5023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTLoopCount2 = 2,
5123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTLoopCount3 = LPC_SHAPE_ORDER
5223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org};
5323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
5423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgenum matrix1_shift_value {
5523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTMatrix1_shift0 = 0,
5623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTMatrix1_shift1 = 1,
5723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTMatrix1_shift5 = 5
5823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org};
5923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
6023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgenum matrixprod_init_case {
6123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTInitCase0 = 0,
6223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  kTInitCase1 = 1
6323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org};
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
66470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  This function implements the fix-point correspondant function to lrint.
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  FLP: (WebRtc_Word32)floor(flt+.499999999999)
69470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  FIP: (fixVal+roundVal)>>qDomain
70470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
71470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  where roundVal = 2^(qDomain-1) = 1<<(qDomain-1)
72470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic __inline WebRtc_Word32 CalcLrIntQ(WebRtc_Word32 fixVal, WebRtc_Word16 qDomain) {
75470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 intgr;
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 roundVal;
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  roundVal = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, qDomain-1);
79470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  intgr = WEBRTC_SPL_RSHIFT_W32(fixVal+roundVal, qDomain);
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return intgr;
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
84470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  __inline WebRtc_UWord32 stepwise(WebRtc_Word32 dinQ10) {
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 ind, diQ10, dtQ10;
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  diQ10 = dinQ10;
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (diQ10 < DPMIN_Q10)
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  diQ10 = DPMIN_Q10;
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (diQ10 >= DPMAX_Q10)
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  diQ10 = DPMAX_Q10 - 1;
94470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  dtQ10 = diQ10 - DPMIN_Q10;*/ /* Q10 + Q10 = Q10 */
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* ind = (dtQ10 * 5) >> 10;  */ /* 2^10 / 5 = 0.2 in Q10  */
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Q10 -> Q0 */
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
99470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* return rpointsFIX_Q10[ind];
100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   }
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* logN(x) = logN(2)*log2(x) = 0.6931*log2(x). Output in Q8. */
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* The input argument X to logN(X) is 2^17 times higher than the
106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   input floating point argument Y to log(Y), since the X value
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   is a Q17 value. This can be compensated for after the call, by
108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   subraction a value Z for each Q-step. One Q-step means that
109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   X gets 2 thimes higher, i.e. Z = logN(2)*256 = 0.693147180559*256 =
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   177.445678 should be subtracted (since logN() returns a Q8 value).
111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   For a X value in Q17, the value 177.445678*17 = 3017 should be
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   subtracted */
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic WebRtc_Word16 CalcLogN(WebRtc_Word32 arg) {
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 zeros, log2, frac, logN;
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  zeros=WebRtcSpl_NormU32(arg);
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_LSHIFT_W32(arg, zeros)&0x7FFFFFFF, 23);
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  log2=(WebRtc_Word16)(WEBRTC_SPL_LSHIFT_W32(31-zeros, 8)+frac); // log2(x) in Q8
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  logN=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2,22713,15); //Q8*Q15 log(2) = 0.693147 = 22713 in Q15
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  logN=logN+11; //Scalar compensation which minimizes the (log(x)-logN(x))^2 error over all x.
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return logN;
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  expN(x) = 2^(a*x), where a = log2(e) ~= 1.442695
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Input:  Q8  (WebRtc_Word16)
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Output: Q17 (WebRtc_Word32)
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  a = log2(e) = log2(exp(1)) ~= 1.442695  ==>  a = 23637 in Q14 (1.442688)
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  To this value, 700 is added or subtracted in order to get an average error
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nearer zero, instead of always same-sign.
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic WebRtc_Word32 CalcExpN(WebRtc_Word16 x) {
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 ax, axINT, axFRAC;
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 exp16;
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 exp;
141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (x>=0) {
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    //  ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637-700, 14); //Q8
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axINT = WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axFRAC = ax&0x00FF;
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp16 = WEBRTC_SPL_LSHIFT_W32(1, axINT); //Q0
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axFRAC = axFRAC+256; //Q8
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q0*Q8 = Q8
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp = WEBRTC_SPL_LSHIFT_W32(exp, 9); //Q17
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    //  ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637+700, 14); //Q8
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ax = -ax;
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axINT = 1 + WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axFRAC = 0x00FF - (ax&0x00FF);
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(32768, axINT); //Q15
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    axFRAC = axFRAC+256; //Q8
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q15*Q8 = Q23
160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    exp = WEBRTC_SPL_RSHIFT_W32(exp, 6); //Q17
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return exp;
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* compute correlation from power spectrum */
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void CalcCorrelation(WebRtc_Word32 *PSpecQ12, WebRtc_Word32 *CorrQ7)
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 summ[FRAMESAMPLES/8];
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 diff[FRAMESAMPLES/8];
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sum;
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, n;
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < FRAMESAMPLES/8; k++) {
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    summ[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] + PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5);
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    diff[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] - PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5);
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = 2;
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < FRAMESAMPLES/8; n++)
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += summ[n];
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CorrQ7[0] = sum;
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < AR_ORDER; k += 2) {
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = 0;
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], diff[n]) + 256, 9);
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CorrQ7[k+1] = sum;
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=1; k<AR_ORDER; k+=2) {
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = 0;
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], summ[n]) + 256, 9);
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CorrQ7[k+1] = sum;
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* compute inverse AR power spectrum */
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void CalcInvArSpec(const WebRtc_Word16 *ARCoefQ12,
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          const WebRtc_Word32 gainQ10,
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          WebRtc_Word32 *CurveQ16)
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 CorrQ11[AR_ORDER+1];
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sum, tmpGain;
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 diffQ16[FRAMESAMPLES/8];
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *CS_ptrQ9;
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, n;
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 round, shftVal = 0, sh;
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = 0;
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < AR_ORDER+1; n++)
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]);    /* Q24 */
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16);    /* result in Q8 */
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9);
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if(gainQ10>400000){
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3);
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    round = 32;
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 6;
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpGain = gainQ10;
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    round = 256;
227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 9;
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 1; k < AR_ORDER+1; k++) {
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = 16384;
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = k; n < AR_ORDER+1; n++)
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]);  /* Q24 */
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = WEBRTC_SPL_RSHIFT_W32(sum, 15);
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal);
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7);
238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < FRAMESAMPLES/8; n++)
239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CurveQ16[n] = sum;
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 1; k < AR_ORDER; k += 2) {
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      CurveQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], CorrQ11[k+1]) + 2, 2);
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CS_ptrQ9 = WebRtcIsacfix_kCos[0];
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* If CorrQ11[1] too large we avoid getting overflow in the calculation by shifting */
249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sh=WebRtcSpl_NormW32(CorrQ11[1]);
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (CorrQ11[1]==0) /* Use next correlation */
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh=WebRtcSpl_NormW32(CorrQ11[2]);
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (sh<9)
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 9 - sh;
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 0;
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < FRAMESAMPLES/8; n++)
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2);
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 2; k < AR_ORDER; k += 2) {
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CS_ptrQ9 = WebRtcIsacfix_kCos[k];
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2);
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<FRAMESAMPLES/8; k++) {
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CurveQ16[FRAMESAMPLES/4-1 - k] = CurveQ16[k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal);
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CurveQ16[k] += WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal);
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void CalcRootInvArSpec(const WebRtc_Word16 *ARCoefQ12,
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              const WebRtc_Word32 gainQ10,
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              WebRtc_UWord16 *CurveQ8)
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 CorrQ11[AR_ORDER+1];
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sum, tmpGain;
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 summQ16[FRAMESAMPLES/8];
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 diffQ16[FRAMESAMPLES/8];
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *CS_ptrQ9;
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, n, i;
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 round, shftVal = 0, sh;
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 res, in_sqrt, newRes;
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = 0;
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < AR_ORDER+1; n++)
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]);    /* Q24 */
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16);    /* result in Q8 */
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9);
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if(gainQ10>400000){
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3);
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    round = 32;
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 6;
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpGain = gainQ10;
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    round = 256;
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 9;
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 1; k < AR_ORDER+1; k++) {
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = 16384;
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = k; n < AR_ORDER+1; n++)
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]);  /* Q24 */
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = WEBRTC_SPL_RSHIFT_W32(sum, 15);
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal);
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7);
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < FRAMESAMPLES/8; n++)
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    summQ16[n] = sum;
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 1; k < (AR_ORDER); k += 2) {
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      summQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(CorrQ11[k+1],WebRtcIsacfix_kCos[k][n]) + 2, 2);
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CS_ptrQ9 = WebRtcIsacfix_kCos[0];
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* If CorrQ11[1] too large we avoid getting overflow in the calculation by shifting */
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  sh=WebRtcSpl_NormW32(CorrQ11[1]);
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (CorrQ11[1]==0) /* Use next correlation */
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sh=WebRtcSpl_NormW32(CorrQ11[2]);
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (sh<9)
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 9 - sh;
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shftVal = 0;
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (n = 0; n < FRAMESAMPLES/8; n++)
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2);
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 2; k < AR_ORDER; k += 2) {
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CS_ptrQ9 = WebRtcIsacfix_kCos[k];
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < FRAMESAMPLES/8; n++)
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2);
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  in_sqrt = summQ16[0] + WEBRTC_SPL_LSHIFT_W32(diffQ16[0], shftVal);
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB)  */
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  res = WEBRTC_SPL_LSHIFT_W32(1, WEBRTC_SPL_RSHIFT_W16(WebRtcSpl_GetSizeInBits(in_sqrt), 1));
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < FRAMESAMPLES/8; k++)
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    in_sqrt = summQ16[k] + WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal);
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    i = 10;
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* make in_sqrt positive to prohibit sqrt of negative values */
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(in_sqrt<0)
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      in_sqrt=-in_sqrt;
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1);
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    do
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      res = newRes;
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1);
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } while (newRes != res && i-- > 0);
359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CurveQ8[k] = (WebRtc_Word16)newRes;
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = FRAMESAMPLES/8; k < FRAMESAMPLES/4; k++) {
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    in_sqrt = summQ16[FRAMESAMPLES/4-1 - k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[FRAMESAMPLES/4-1 - k], shftVal);
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    i = 10;
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* make in_sqrt positive to prohibit sqrt of negative values */
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(in_sqrt<0)
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      in_sqrt=-in_sqrt;
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1);
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    do
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      res = newRes;
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1);
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } while (newRes != res && i-- > 0);
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CurveQ8[k] = (WebRtc_Word16)newRes;
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* generate array of dither samples in Q7 */
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void GenerateDitherQ7(WebRtc_Word16 *bufQ7,
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             WebRtc_UWord32 seed,
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             WebRtc_Word16 length,
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             WebRtc_Word16 AvgPitchGain_Q12)
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int   k;
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 dither1_Q7, dither2_Q7, dither_gain_Q14, shft;
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (AvgPitchGain_Q12 < 614)  /* this threshold should be equal to that in decode_spec() */
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k = 0; k < length-2; k += 3)
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* new random unsigned WebRtc_Word32 */
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* fixed-point dither sample between -64 and 64 (Q7) */
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25); // * 128/4294967295
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* new random unsigned WebRtc_Word32 */
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* fixed-point dither sample between -64 and 64 */
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      dither2_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(seed + 16777216, 25);
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 15);
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (shft < 5)
412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k]   = dither1_Q7;
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+1] = dither2_Q7;
415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+2] = 0;
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else if (shft < 10)
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k]   = dither1_Q7;
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+1] = 0;
421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+2] = dither2_Q7;
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k]   = 0;
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+1] = dither1_Q7;
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        bufQ7[k+2] = dither2_Q7;
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    dither_gain_Q14 = (WebRtc_Word16)(22528 - WEBRTC_SPL_MUL(10, AvgPitchGain_Q12));
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* dither on half of the coefficients */
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k = 0; k < length-1; k += 2)
437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* new random unsigned WebRtc_Word32 */
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* fixed-point dither sample between -64 and 64 */
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25);
443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* dither sample is placed in either even or odd index */
445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 1);     /* either 0 or 1 */
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      bufQ7[k + shft] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(dither_gain_Q14, dither1_Q7) + 8192, 14);
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      bufQ7[k + 1 - shft] = 0;
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * function to decode the complex spectrum from the bitstream
458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * returns the total number of bytes in the stream
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comWebRtc_Word16 WebRtcIsacfix_DecodeSpec(Bitstr_dec *streamdata,
461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       WebRtc_Word16 *frQ7,
462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       WebRtc_Word16 *fiQ7,
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       WebRtc_Word16 AvgPitchGain_Q12)
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  data[FRAMESAMPLES];
466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  invARSpec2_Q16[FRAMESAMPLES/4];
467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  ARCoefQ12[AR_ORDER+1];
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  RCQ15[AR_ORDER];
469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  gainQ10;
470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  gain2_Q10;
471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  len;
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int          k;
473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* create dither signal */
475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  GenerateDitherQ7(data, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); /* Dither is output in vector 'Data' */
476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* decode model parameters */
478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (WebRtcIsacfix_DecodeRcCoef(streamdata, RCQ15) < 0)
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12);
483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (WebRtcIsacfix_DecodeGain2(streamdata, &gain2_Q10) < 0)
485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* compute inverse AR power spectrum */
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CalcInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16);
489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* arithmetic decoding of spectrum */
491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* 'data' input and output. Input = Dither */
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  len = WebRtcIsacfix_DecLogisticMulti2(data, streamdata, invARSpec2_Q16, (WebRtc_Word16)FRAMESAMPLES);
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (len<1)
495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* subtract dither and scale down spectral samples with low SNR */
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (AvgPitchGain_Q12 <= 614)
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k = 0; k < FRAMESAMPLES; k += 4)
501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)30, 10),
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2195456, 16));
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10);
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10);
506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10);
507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10);
508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k = 0; k < FRAMESAMPLES; k += 4)
513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)36, 10),
515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                              (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2654208, 16));
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10);
517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10);
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10);
519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10);
520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return len;
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeSpec(const WebRtc_Word16 *fr,
528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             const WebRtc_Word16 *fi,
529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             Bitstr_enc *streamdata,
530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                             WebRtc_Word16 AvgPitchGain_Q12)
531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  dataQ7[FRAMESAMPLES];
533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  PSpec[FRAMESAMPLES/4];
534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES/4];
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  CorrQ7[AR_ORDER+1];
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  CorrQ7_norm[AR_ORDER+1];
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  RCQ15[AR_ORDER];
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  ARCoefQ12[AR_ORDER+1];
539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  gain2_Q10;
540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  val;
541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32  nrg;
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_UWord32 sum;
543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  lft_shft;
544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16  status;
545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int          k, n, j;
546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* create dither_float signal */
549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  GenerateDitherQ7(dataQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12);
550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* add dither and quantize, and compute power spectrum */
552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Vector dataQ7 contains Dither in Q7 */
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < FRAMESAMPLES; k += 4)
554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    val = ((*fr++ + dataQ7[k]   + 64) & 0xFF80) - dataQ7[k]; /* Data = Dither */
556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    dataQ7[k] = val;            /* New value in Data */
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum = WEBRTC_SPL_UMUL(val, val);
558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    val = ((*fi++ + dataQ7[k+1] + 64) & 0xFF80) - dataQ7[k+1]; /* Data = Dither */
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    dataQ7[k+1] = val;            /* New value in Data */
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += WEBRTC_SPL_UMUL(val, val);
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    val = ((*fr++ + dataQ7[k+2] + 64) & 0xFF80) - dataQ7[k+2]; /* Data = Dither */
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    dataQ7[k+2] = val;            /* New value in Data */
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += WEBRTC_SPL_UMUL(val, val);
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    val = ((*fi++ + dataQ7[k+3] + 64) & 0xFF80) - dataQ7[k+3]; /* Data = Dither */
568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    dataQ7[k+3] = val;            /* New value in Data */
569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sum += WEBRTC_SPL_UMUL(val, val);
570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PSpec[k>>2] = WEBRTC_SPL_RSHIFT_U32(sum, 2);
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* compute correlation from power spectrum */
575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CalcCorrelation(PSpec, CorrQ7);
576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find AR coefficients */
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* number of bit shifts to 14-bit normalize CorrQ7[0] (leaving room for sign) */
580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  lft_shft = WebRtcSpl_NormW32(CorrQ7[0]) - 18;
581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (lft_shft > 0) {
583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<AR_ORDER+1; k++)
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      CorrQ7_norm[k] = WEBRTC_SPL_LSHIFT_W32(CorrQ7[k], lft_shft);
585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<AR_ORDER+1; k++)
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      CorrQ7_norm[k] = WEBRTC_SPL_RSHIFT_W32(CorrQ7[k], -lft_shft);
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find RC coefficients */
591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15);
592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize & code RC Coef */
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncodeRcCoef(RCQ15, streamdata);
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* RC -> AR coefficients */
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12);
601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* compute ARCoef' * Corr * ARCoef in Q19 */
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  nrg = 0;
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j = 0; j <= AR_ORDER; j++) {
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n <= j; n++)
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[j-n], ARCoefQ12[n]) + 256, 9)) + 4, 3);
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = j+1; n <= AR_ORDER; n++)
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[n-j], ARCoefQ12[n]) + 256, 9)) + 4, 3);
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (lft_shft > 0)
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    nrg = WEBRTC_SPL_RSHIFT_W32(nrg, lft_shft);
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    nrg = WEBRTC_SPL_LSHIFT_W32(nrg, -lft_shft);
615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if(nrg>131072)
617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES >> 2, nrg);  /* also shifts 31 bits to the left! */
618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain2_Q10 = WEBRTC_SPL_RSHIFT_W32(FRAMESAMPLES, 2);
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize & code gain2_Q10 */
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (WebRtcIsacfix_EncodeGain2(&gain2_Q10, streamdata))
623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* compute inverse AR magnitude spectrum */
626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CalcRootInvArSpec(ARCoefQ12, gain2_Q10, invARSpecQ8);
627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* arithmetic coding of spectrum */
630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, (WebRtc_Word16)FRAMESAMPLES);
631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if ( status )
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return( status );
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Matlab's LAR definition */
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void Rc2LarFix(const WebRtc_Word16 *rcQ15, WebRtc_Word32 *larQ17, WebRtc_Word16 order) {
640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /*
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    This is a piece-wise implemenetation of a rc2lar-function (all values in the comment
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    are Q15 values and  are based on [0 24956/32768 30000/32768 32500/32768], i.e.
645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    [0.76159667968750   0.91552734375000   0.99182128906250]
646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    x0  x1           a                 k              x0(again)         b
648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ==================================================================================
649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    0.00 0.76:   0                  2.625997508581   0                  0
650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    0.76 0.91:   2.000012018559     7.284502668663   0.761596679688    -3.547841027073
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    0.91 0.99:   3.121320351712    31.115835041229   0.915527343750   -25.366077452148
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    0.99 1.00:   5.495270168700   686.663805654056   0.991821289063  -675.552510708011
653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    The implementation is y(x)= a + (x-x0)*k, but this can be simplified to
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    y(x) = a-x0*k + x*k = b + x*k, where b = a-x0*k
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    akx=[0                 2.625997508581   0
659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    2.000012018559     7.284502668663   0.761596679688
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    3.121320351712    31.115835041229   0.915527343750
661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    5.495270168700   686.663805654056   0.991821289063];
662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    b = akx(:,1) - akx(:,3).*akx(:,2)
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    [ 0.0
666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    -3.547841027073
667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    -25.366077452148
668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    -675.552510708011]
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  */
671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k;
673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 rc;
674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 larAbsQ17;
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < order; k++) {
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rc = WEBRTC_SPL_ABS_W16(rcQ15[k]); //Q15
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Calculate larAbsQ17 in Q17 from rc in Q15 */
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rc<24956) {  //0.7615966 in Q15
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // (Q15*Q13)>>11 = Q17
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larAbsQ17 = WEBRTC_SPL_MUL_16_16_RSFT(rc, 21512, 11);
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else if (rc<30000) { //0.91552734375 in Q15
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // Q17 + (Q15*Q12)>>10 = Q17
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larAbsQ17 = -465024 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 29837, 10);
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else if (rc<32500) { //0.99182128906250 in Q15
689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // Q17 + (Q15*Q10)>>8 = Q17
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larAbsQ17 = -3324784 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 31863, 8);
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else  {
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // Q17 + (Q15*Q5)>>3 = Q17
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larAbsQ17 = -88546020 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 21973, 3);
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (rcQ15[k]>0) {
697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larQ17[k] = larAbsQ17;
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else {
699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      larQ17[k] = -larAbsQ17;
700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void Lar2RcFix(const WebRtc_Word32 *larQ17, WebRtc_Word16 *rcQ15,  WebRtc_Word16 order) {
706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /*
708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    This is a piece-wise implemenetation of a lar2rc-function
709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    See comment in Rc2LarFix() about details.
710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  */
711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k;
713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 larAbsQ11;
714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 rc;
715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < order; k++) {
717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    larAbsQ11 = (WebRtc_Word16) WEBRTC_SPL_ABS_W32(WEBRTC_SPL_RSHIFT_W32(larQ17[k]+32,6)); //Q11
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (larAbsQ11<4097) { //2.000012018559 in Q11
721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // Q11*Q16>>12 = Q15
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rc = WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24957, 12);
723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else if (larAbsQ11<6393) { //3.121320351712 in Q11
724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // (Q11*Q17 + Q13)>>13 = Q15
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 17993) + 130738688), 13);
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else if (larAbsQ11<11255) { //5.495270168700 in Q11
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // (Q11*Q19 + Q30)>>15 = Q15
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 16850) + 875329820), 15);
729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else  {
730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      // (Q11*Q24>>16 + Q19)>>4 = Q15
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rc = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24433, 16)) + 515804), 4);
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (larQ17[k]<=0) {
735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rc = -rc;
736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rcQ15[k] = (WebRtc_Word16) rc;  // Q15
739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void Poly2LarFix(WebRtc_Word16 *lowbandQ15,
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 orderLo,
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 *hibandQ15,
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 orderHi,
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 Nsub,
747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word32 *larsQ17) {
748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, n;
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 *outpQ17;
751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 orderTot;
752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 larQ17[MAX_ORDER];   // Size 7+6 is enough
753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  orderTot = (orderLo + orderHi);
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  outpQ17 = larsQ17;
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < Nsub; k++) {
757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Rc2LarFix(lowbandQ15, larQ17, orderLo);
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < orderLo; n++)
761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      outpQ17[n] = larQ17[n]; //Q17
762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Rc2LarFix(hibandQ15, larQ17, orderHi);
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < orderHi; n++)
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      outpQ17[n + orderLo] = larQ17[n]; //Q17;
767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    outpQ17 += orderTot;
769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lowbandQ15 += orderLo;
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    hibandQ15 += orderHi;
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic void Lar2polyFix(WebRtc_Word32 *larsQ17,
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 *lowbandQ15,
777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 orderLo,
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 *hibandQ15,
779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 orderHi,
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                        WebRtc_Word16 Nsub) {
781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, n;
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 orderTot;
784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 *outplQ15, *outphQ15;
785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 *inpQ17;
786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 rcQ15[7+6];
787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  orderTot = (orderLo + orderHi);
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  outplQ15 = lowbandQ15;
790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  outphQ15 = hibandQ15;
791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  inpQ17 = larsQ17;
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < Nsub; k++) {
793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* gains not handled here as in the FLP version */
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Low band */
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Lar2RcFix(&inpQ17[0], rcQ15, orderLo);
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < orderLo; n++)
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      outplQ15[n] = rcQ15[n]; // Refl. coeffs
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* High band */
802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Lar2RcFix(&inpQ17[orderLo], rcQ15, orderHi);
803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n = 0; n < orderHi; n++)
804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      outphQ15[n] = rcQ15[n]; // Refl. coeffs
805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    inpQ17 += orderTot;
807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    outplQ15 += orderLo;
808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    outphQ15 += orderHi;
809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
81223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org/*
81323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgFunction WebRtcIsacfix_MatrixProduct1C() does one form of matrix multiplication.
81423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgIt first shifts input data of one matrix, determines the right indexes for the
81523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgtwo matrixes, multiply them, and write the results into an output buffer.
81623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
81723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgNote that two factors (or, multipliers) determine the initialization values of
81823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgthe variable |matrix1_index| in the code. The relationship is
81923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix1_index| = |matrix1_index_factor1| * |matrix1_index_factor2|, where
82023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix1_index_factor1| is given by the argument while |matrix1_index_factor2|
82123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgis determined by the value of argument |matrix1_index_init_case|;
82223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix1_index_factor2| is the value of the outmost loop counter j (when
82323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix1_index_init_case| is 0), or the value of the middle loop counter k (when
82423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix1_index_init_case| is non-zero).
82523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
82623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org|matrix0_index| is determined the same way.
82723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
82823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgArguments:
82923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0[]:                 matrix0 data in Q15 domain.
83023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix1[]:                 matrix1 data.
83123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix_product[]:          output data (matrix product).
83223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix1_index_factor1:     The first of two factors determining the
83323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                             initialization value of matrix1_index.
83423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0_index_factor1:     The first of two factors determining the
83523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                             initialization value of matrix0_index.
83623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix1_index_init_case:   Case number for selecting the second of two
83723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                             factors determining the initialization value
83823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                             of matrix1_index and matrix0_index.
83923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix1_index_step:        Incremental step for matrix1_index.
84023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0_index_step:        Incremental step for matrix0_index.
84123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  inner_loop_count:          Maximum count of the inner loop.
84223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  mid_loop_count:            Maximum count of the intermediate loop.
84323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  shift:                     Left shift value for matrix1.
84423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org*/
84523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgvoid WebRtcIsacfix_MatrixProduct1C(const int16_t matrix0[],
84623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int32_t matrix1[],
84723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   int32_t matrix_product[],
84823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix1_index_factor1,
84923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix0_index_factor1,
85023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix1_index_init_case,
85123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix1_index_step,
85223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix0_index_step,
85323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int inner_loop_count,
85423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int mid_loop_count,
85523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int shift) {
85623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int j = 0, k = 0, n = 0;
85723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int matrix0_index = 0, matrix1_index = 0, matrix_prod_index = 0;
85823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int* matrix0_index_factor2 = &k;
85923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int* matrix1_index_factor2 = &j;
86023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  if (matrix1_index_init_case != 0) {
86123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix0_index_factor2 = &j;
86223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix1_index_factor2 = &k;
86323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  }
86423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
86523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  for (j = 0; j < SUBFRAMES; j++) {
86623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix_prod_index = mid_loop_count * j;
86723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    for (k = 0; k < mid_loop_count; k++) {
86823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      int32_t sum32 = 0;
86923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix0_index = matrix0_index_factor1 * (*matrix0_index_factor2);
87023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix1_index = matrix1_index_factor1 * (*matrix1_index_factor2);
87123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      for (n = 0; n < inner_loop_count; n++) {
87223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        sum32 += (WEBRTC_SPL_MUL_16_32_RSFT16(matrix0[matrix0_index],
87323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                              matrix1[matrix1_index] << shift));
87423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        matrix0_index += matrix0_index_step;
87523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        matrix1_index += matrix1_index_step;
87623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      }
87723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix_product[matrix_prod_index] = sum32;
87823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix_prod_index++;
87923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    }
88023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  }
88123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org}
88223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
88323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org/*
88423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgFunction WebRtcIsacfix_MatrixProduct2C() returns the product of two matrixes,
88523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgone of which has two columns. It first has to determine the correct index of
88623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgthe first matrix before doing the actual element multiplication.
88723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
88823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgArguments:
88923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0[]:                 A matrix in Q15 domain.
89023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix1[]:                 A matrix in Q21 domain.
89123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix_product[]:          Output data in Q17 domain.
89223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0_index_factor:      A factor determining the initialization value
89323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                             of matrix0_index.
89423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  matrix0_index_step:        Incremental step for matrix0_index.
89523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org*/
89623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.orgvoid WebRtcIsacfix_MatrixProduct2C(const int16_t matrix0[],
89723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int32_t matrix1[],
89823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   int32_t matrix_product[],
89923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix0_index_factor,
90023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   const int matrix0_index_step) {
90123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int j = 0, n = 0;
90223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int matrix1_index = 0, matrix0_index = 0, matrix_prod_index = 0;
90323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  for (j = 0; j < SUBFRAMES; j++) {
90423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    int32_t sum32 = 0, sum32_2 = 0;
90523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix1_index = 0;
90623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix0_index = matrix0_index_factor * j;
90723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    for (n = SUBFRAMES; n > 0; n--) {
90823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sum32 += (WEBRTC_SPL_MUL_16_32_RSFT16(matrix0[matrix0_index],
90923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                            matrix1[matrix1_index]));
91023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sum32_2 += (WEBRTC_SPL_MUL_16_32_RSFT16(matrix0[matrix0_index],
91123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                            matrix1[matrix1_index + 1]));
91223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix1_index += 2;
91323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      matrix0_index += matrix0_index_step;
91423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    }
91523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix_product[matrix_prod_index] = sum32 >> 3;
91623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix_product[matrix_prod_index + 1] = sum32_2 >> 3;
91723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    matrix_prod_index += 2;
91823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  }
91923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org}
92023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeLpc(WebRtc_Word32 *gain_lo_hiQ17,
922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *LPCCoef_loQ15,
923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *LPCCoef_hiQ15,
924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            Bitstr_dec *streamdata,
925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *outmodel) {
926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_GAIN+KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES
928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecodeLpcCoef(streamdata, larsQ17, gain_lo_hiQ17, outmodel);
931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_LPC;
933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES);
935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* decode & dequantize LPC Coef */
940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec *streamdata,
941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                WebRtc_Word32 *LPCCoefQ17,
942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                WebRtc_Word32 *gain_lo_hiQ17,
943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                WebRtc_Word16 *outmodel)
944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int j, k, n;
946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
94723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtc_Word16 pos, pos2, posg, poss;
948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 gainpos;
949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 model;
950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_QQ[KLT_ORDER_SHAPE];
951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN];
952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN];
953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 tmpcoeffs_sQ10[KLT_ORDER_SHAPE];
954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE];
955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_sQ18[KLT_ORDER_SHAPE];
956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sumQQ;
957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 sumQQ16;
958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmp32;
959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of model number */
963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(&model, streamdata, WebRtcIsacfix_kModelCdfPtr, WebRtcIsacfix_kModelInitIndex, 1);
964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return err;
966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of quantization indices */
968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfShapePtr[model], WebRtcIsacfix_kInitIndexShape[model], KLT_ORDER_SHAPE);
969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return err;
971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization levels for coefficients */
972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_SHAPE; k++) {
973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_sQ10[WebRtcIsacfix_kSelIndShape[k]] = WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[model]+WebRtcIsacfix_kOffsetShape[model][k] + index_QQ[k]];
974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfGainPtr[model], WebRtcIsacfix_kInitIndexGain[model], KLT_ORDER_GAIN);
977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
978470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return err;
979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization levels for coefficients */
980470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_GAIN; k++) {
981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[model]+ WebRtcIsacfix_kOffsetGain[model][k] + index_QQ[k]];
982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* inverse KLT  */
986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */  // Transpose matrix!
98823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT1GainQ15[model], tmpcoeffs_gQ17,
98923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs2_gQ21, kTIndexFactor2, kTIndexFactor2,
99023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               kTInitCase0, kTIndexStep1, kTIndexStep1,
99123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               kTLoopCount2, kTLoopCount2, kTMatrix1_shift5);
99223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  poss = 0;
994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j=0; j<SUBFRAMES; j++) {
995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<LPC_SHAPE_ORDER; k++) {
996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      sumQQ = 0;
99723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      pos = LPC_SHAPE_ORDER * j;
99823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      pos2 = LPC_SHAPE_ORDER * k;
999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for (n=0; n<LPC_SHAPE_ORDER; n++) {
1000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        sumQQ += WEBRTC_SPL_MUL_16_16_RSFT(tmpcoeffs_sQ10[pos], WebRtcIsacfix_kT1ShapeQ15[model][pos2], 7); // (Q10*Q15)>>7 = Q18
1001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        pos++;
1002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        pos2++;
1003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
1004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpcoeffs2_sQ18[poss] = sumQQ; //Q18
1005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      poss++;
1006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* right transform */ // Transpose matrix
101023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct2(WebRtcIsacfix_kT2GainQ15[0], tmpcoeffs2_gQ21,
101123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs_gQ17, kTIndexFactor1, kTIndexStep2);
101223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT2ShapeQ15[model],
101323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs2_sQ18, tmpcoeffs_sQ17, kTIndexFactor1, kTIndexFactor1,
101423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTInitCase1, kTIndexStep3, kTIndexStep2, kTLoopCount1, kTLoopCount3,
101523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTMatrix1_shift0);
1016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1017470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* scaling, mean addition, and gain restoration */
1018470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  gainpos = 0;
1019470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  posg = 0;poss = 0;pos=0;
1020470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<SUBFRAMES; k++) {
1021470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* log gains */
1023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
1024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg];
1025470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
1026470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[gainpos] = sumQQ; //Q17
1027470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gainpos++;
1028470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++;
1029470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1030470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
1031470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg];
1032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
1033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[gainpos] = sumQQ; //Q17
1034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gainpos++;
1035470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++;
1036470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* lo band LAR coeffs */
1038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERLO; n++, pos++, poss++) {
1039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16
1040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17
1041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      LPCCoefQ17[pos] = tmp32;
1042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* hi band LAR coeffs */
1045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERHI; n++, pos++, poss++) {
1046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13
1047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17
1048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      LPCCoefQ17[pos] = tmp32;
1049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *outmodel=model;
1054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1055470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1056470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1057470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1058470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* estimate codel length of LPC Coef */
1059470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comstatic int EstCodeLpcCoef(WebRtc_Word32 *LPCCoefQ17,
1060470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          WebRtc_Word32 *gain_lo_hiQ17,
1061470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          WebRtc_Word16 *model,
1062470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          WebRtc_Word32 *sizeQ11,
1063470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          Bitstr_enc *streamdata,
1064470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          ISAC_SaveEncData_t* encData,
1065470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          transcode_obj *transcodingParam) {
1066470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int j, k, n;
1067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 posQQ, pos2QQ, gainpos;
106823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtc_Word16  pos, poss, posg, offsg;
1069470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN], index_sQQ[KLT_ORDER_SHAPE];
1070470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_ovr_gQQ[KLT_ORDER_GAIN], index_ovr_sQQ[KLT_ORDER_SHAPE];
1071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 BitsQQ;
1072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1073470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN];
1074470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN];
1075470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE];
1076470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN];
1077470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_sQ17[KLT_ORDER_SHAPE];
1078470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sumQQ;
1079470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmp32;
1080470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 sumQQ16;
1081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1082470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1083470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* write LAR coefficients to statistics file */
1084470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Save data for creation of multiple bitstreams (and transcoding) */
1085470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (encData != NULL) {
1086470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<KLT_ORDER_GAIN; k++) {
1087470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k];
1088470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1089470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1090470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1091470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* log gains, mean removal and scaling */
1092470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  posg = 0;poss = 0;pos=0; gainpos=0;
1093470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1094470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<SUBFRAMES; k++) {
1095470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* log gains */
1096470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* The input argument X to logN(X) is 2^17 times higher than the
1098470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       input floating point argument Y to log(Y), since the X value
1099470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       is a Q17 value. This can be compensated for after the call, by
1100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subraction a value Z for each Q-step. One Q-step means that
1101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 =
1102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       177.445678 should be subtracted (since logN() returns a Q8 value).
1103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       For a X value in Q17, the value 177.445678*17 = 3017 should be
1104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subtracted */
1105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
1106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
1107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
1108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
1110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
1111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
1112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* lo band LAR coeffs */
1114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERLO; n++, poss++, pos++) {
1115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17
1116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(17203, tmp32<<3); // tmp32 = 2.1*tmp32
1117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpcoeffs_sQ17[poss] = tmp32; //Q17
1118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* hi band LAR coeffs */
1121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERHI; n++, poss++, pos++) {
1122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17
1123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(14746, tmp32<<1); // tmp32 = 0.45*tmp32
1124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpcoeffs_sQ17[poss] = tmp32; //Q17
1125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* KLT  */
1131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */
1133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  offsg = 0;
113423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  posg = 0;
1135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j=0; j<SUBFRAMES; j++) {
113623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    // Q21 = Q6 * Q15
113723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg],
113823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        WebRtcIsacfix_kT1GainQ15[0][0]);
113923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg + 1],
114023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        WebRtcIsacfix_kT1GainQ15[0][2]);
114123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    tmpcoeffs2_gQ21[posg] = sumQQ;
114223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    posg++;
114323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
114423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    // Q21 = Q6 * Q15
114523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg],
114623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        WebRtcIsacfix_kT1GainQ15[0][1]);
114723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg + 1],
114823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org        WebRtcIsacfix_kT1GainQ15[0][3]);
114923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    tmpcoeffs2_gQ21[posg] = sumQQ;
115023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    posg++;
115123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
1152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    offsg += 2;
1153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
115523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT1ShapeQ15[0], tmpcoeffs_sQ17,
115623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs2_sQ17, kTIndexFactor4, kTIndexFactor1, kTInitCase0,
115723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTIndexStep1, kTIndexStep3, kTLoopCount3, kTLoopCount3, kTMatrix1_shift1);
115823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
1159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* right transform */
116023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct2(WebRtcIsacfix_kT2GainQ15[0], tmpcoeffs2_gQ21,
116123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs_gQ17, kTIndexFactor3, kTIndexStep1);
116223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
116323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT2ShapeQ15[0], tmpcoeffs2_sQ17,
116423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs_sQ17, kTIndexFactor1, kTIndexFactor3, kTInitCase1, kTIndexStep3,
116523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTIndexStep1, kTLoopCount1, kTLoopCount3, kTMatrix1_shift1);
1166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize coefficients */
1168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  BitsQQ = 0;
1170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok?
1171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posQQ = WebRtcIsacfix_kSelIndGain[k];
1173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17);
1174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok?
1176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index_gQQ[k] < 0) {
1177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = 0;
1178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) {
1180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k];
1181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_ovr_gQQ[k] = WebRtcIsacfix_kOffsetGain[0][k]+index_gQQ[k];
1183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posQQ = WebRtcIsacfix_kOfLevelsGain[0] + index_ovr_gQQ[k];
1184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Save data for creation of multiple bitstreams */
1186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (encData != NULL) {
1187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k];
1188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* determine number of bits */
1191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ = WebRtcIsacfix_kCodeLenGainQ11[posQQ]; //Q11
1192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    BitsQQ += sumQQ;
1193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_SHAPE; k++) //ATTN: ok?
1196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_sQQ[k] = (WebRtc_Word16)(CalcLrIntQ(tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]], 17) + WebRtcIsacfix_kQuantMinShape[k]); //ATTN: ok?
1198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index_sQQ[k] < 0)
1200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_sQQ[k] = 0;
1201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index_sQQ[k] > WebRtcIsacfix_kMaxIndShape[k])
1202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_sQQ[k] = WebRtcIsacfix_kMaxIndShape[k];
1203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_ovr_sQQ[k] = WebRtcIsacfix_kOffsetShape[0][k]+index_sQQ[k];
1204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posQQ = WebRtcIsacfix_kOfLevelsShape[0] + index_ovr_sQQ[k];
1206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ = WebRtcIsacfix_kCodeLenShapeQ11[posQQ]; //Q11
1207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    BitsQQ += sumQQ;
1208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *model = 0;
1213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *sizeQ11=BitsQQ;
1214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of model number */
1216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, model, WebRtcIsacfix_kModelCdfPtr, 1);
1217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of quantization indices - shape only */
1222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, index_sQQ, WebRtcIsacfix_kCdfShapePtr[0], KLT_ORDER_SHAPE);
1223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Save data for creation of multiple bitstreams */
1228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (encData != NULL) {
1229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<KLT_ORDER_SHAPE; k++)
1230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->LPCindex_s[KLT_ORDER_SHAPE*encData->startIdx + k] = index_sQQ[k];
1232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* save the state of the bitstream object 'streamdata' for the possible bit-rate reduction */
1235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->full         = streamdata->full;
1236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->stream_index = streamdata->stream_index;
1237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->streamval    = streamdata->streamval;
1238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->W_upper      = streamdata->W_upper;
1239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->beforeLastWord     = streamdata->stream[streamdata->stream_index-1];
1240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  transcodingParam->lastWord     = streamdata->stream[streamdata->stream_index];
1241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of index */
1243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN);
1244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization levels for shape coefficients */
1249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_SHAPE; k++) {
1250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]] = WEBRTC_SPL_MUL(128, WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[0]+index_ovr_sQQ[k]]);
1251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* inverse KLT  */
1254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */  // Transpose matrix!
125623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT1ShapeQ15[0], tmpcoeffs_sQ17,
125723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs2_sQ17, kTIndexFactor4, kTIndexFactor4, kTInitCase0,
125823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTIndexStep1, kTIndexStep1, kTLoopCount3, kTLoopCount3, kTMatrix1_shift1);
1259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* right transform */ // Transpose matrix
126123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct1(WebRtcIsacfix_kT2ShapeQ15[0], tmpcoeffs2_sQ17,
126223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs_sQ17, kTIndexFactor1, kTIndexFactor1, kTInitCase1, kTIndexStep3,
126323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      kTIndexStep2, kTLoopCount1, kTLoopCount3, kTMatrix1_shift1);
1264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* scaling, mean addition, and gain restoration */
1266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  poss = 0;pos=0;
1267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<SUBFRAMES; k++) {
1268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* lo band LAR coeffs */
1270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERLO; n++, pos++, poss++) {
1271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16
1272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17
1273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      LPCCoefQ17[pos] = tmp32;
1274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* hi band LAR coeffs */
1277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (n=0; n<ORDERHI; n++, pos++, poss++) {
1278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13
1279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17
1280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      LPCCoefQ17[pos] = tmp32;
1281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  //to update tmpcoeffs_gQ17 to the proper state
1286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_GAIN; k++) {
1287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[0]+index_ovr_gQQ[k]];
1288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization levels for coefficients */
1293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */
1295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  offsg = 0;
1296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  posg = 0;
1297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j=0; j<SUBFRAMES; j++) {
129823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    // (Q15 * Q17) >> (16 - 1) = Q17; Q17 << 4 = Q21.
129923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ = (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][0],
130023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                         tmpcoeffs_gQ17[offsg]) << 1);
130123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][1],
130223da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                          tmpcoeffs_gQ17[offsg + 1]) << 1);
130323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    tmpcoeffs2_gQ21[posg] = WEBRTC_SPL_LSHIFT_W32(sumQQ, 4);
130423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    posg++;
130523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
130623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ = (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][2],
130723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                         tmpcoeffs_gQ17[offsg]) << 1);
130823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][3],
130923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                          tmpcoeffs_gQ17[offsg + 1]) << 1);
131023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    tmpcoeffs2_gQ21[posg] = WEBRTC_SPL_LSHIFT_W32(sumQQ, 4);
131123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org    posg++;
1312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    offsg += 2;
1313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* right transform */ // Transpose matrix
131623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct2(WebRtcIsacfix_kT2GainQ15[0], tmpcoeffs2_gQ21,
131723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs_gQ17, kTIndexFactor1, kTIndexStep2);
1318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* scaling, mean addition, and gain restoration */
1320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  posg = 0;
1321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  gainpos = 0;
1322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<2*SUBFRAMES; k++) {
1323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
1325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ16 += WebRtcIsacfix_kMeansGainQ8[0][posg];
1326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
1327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[gainpos] = sumQQ; //Q17
1328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gainpos++;
1330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pos++;posg++;
1331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EstCodeLpcGain(WebRtc_Word32 *gain_lo_hiQ17,
1337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 Bitstr_enc *streamdata,
1338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 ISAC_SaveEncData_t* encData) {
133923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int j, k;
1340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 posQQ, pos2QQ, gainpos;
134123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtc_Word16 posg;
1342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN];
1343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN];
1345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN];
1346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN];
1347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sumQQ;
1348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* write LAR coefficients to statistics file */
1351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Save data for creation of multiple bitstreams (and transcoding) */
1352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (encData != NULL) {
1353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (k=0; k<KLT_ORDER_GAIN; k++) {
1354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k];
1355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* log gains, mean removal and scaling */
135923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  posg = 0; gainpos = 0;
1360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<SUBFRAMES; k++) {
1362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* log gains */
1363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* The input argument X to logN(X) is 2^17 times higher than the
1365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       input floating point argument Y to log(Y), since the X value
1366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       is a Q17 value. This can be compensated for after the call, by
1367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subraction a value Z for each Q-step. One Q-step means that
1368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 =
1369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       177.445678 should be subtracted (since logN() returns a Q8 value).
1370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       For a X value in Q17, the value 177.445678*17 = 3017 should be
1371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subtracted */
1372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
1373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
1374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
1375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
1377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
1378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
1379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* KLT  */
1383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */
138523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  posg = 0;
1386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j=0; j<SUBFRAMES; j++) {
138723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      // Q21 = Q6 * Q15
138823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[j * 2],
138923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   WebRtcIsacfix_kT1GainQ15[0][0]);
139023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[j * 2 + 1],
139123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                    WebRtcIsacfix_kT1GainQ15[0][2]);
1392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpcoeffs2_gQ21[posg] = sumQQ;
1393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      posg++;
1394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
139523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[j * 2],
139623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   WebRtcIsacfix_kT1GainQ15[0][1]);
139723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[j * 2 + 1],
139823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                    WebRtcIsacfix_kT1GainQ15[0][3]);
139923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs2_gQ21[posg] = sumQQ;
1400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      posg++;
1401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
140323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  /* right transform */
140423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct2(WebRtcIsacfix_kT2GainQ15[0], tmpcoeffs2_gQ21,
140523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs_gQ17, kTIndexFactor3, kTIndexStep1);
140623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org
1407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize coefficients */
1408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok?
1410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posQQ = WebRtcIsacfix_kSelIndGain[k];
1412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17);
1413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok?
1415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index_gQQ[k] < 0) {
1416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = 0;
1417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) {
1419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k];
1420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Save data for creation of multiple bitstreams */
1423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (encData != NULL) {
1424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k];
1425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of index */
1429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN);
1430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeLpc(WebRtc_Word32 *gain_lo_hiQ17,
1439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *LPCCoef_loQ15,
1440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *LPCCoef_hiQ15,
1441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word16 *model,
1442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            WebRtc_Word32 *sizeQ11,
1443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            Bitstr_enc *streamdata,
1444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            ISAC_SaveEncData_t* encData,
1445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            transcode_obj *transcodeParam)
1446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES
1449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  // = (6+12)*6 == 108
1450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Poly2LarFix(LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES, larsQ17);
1452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
145323da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  status = EstCodeLpcCoef(larsQ17, gain_lo_hiQ17, model, sizeQ11,
145423da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                          streamdata, encData, transcodeParam);
1455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (status);
1457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES);
1460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* decode & dequantize RC */
1466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeRcCoef(Bitstr_dec *streamdata, WebRtc_Word16 *RCQ15)
1467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, err;
1469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index[AR_ORDER];
1470470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of quantization indices */
1472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(index, streamdata, WebRtcIsacfix_kRcCdfPtr, WebRtcIsacfix_kRcInitInd, AR_ORDER);
1473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
1474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return err;
1475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization levels for reflection coefficients */
1477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<AR_ORDER; k++)
1478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]);
1480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* quantize & code RC */
1488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeRcCoef(WebRtc_Word16 *RCQ15, Bitstr_enc *streamdata)
1489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k;
1491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index[AR_ORDER];
1492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status;
1493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize reflection coefficients (add noise feedback?) */
1495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<AR_ORDER; k++)
1496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index[k] = WebRtcIsacfix_kRcInitInd[k];
1498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k]])
1500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      while (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k] + 1])
1502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        index[k]++;
1503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
1505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      while (RCQ15[k] < WebRtcIsacfix_kRcBound[--index[k]]) ;
1507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]);
1510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of quantization indices */
1514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, index, WebRtcIsacfix_kRcCdfPtr, AR_ORDER);
1515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */
1517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return status;
1518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* decode & dequantize squared Gain */
1522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeGain2(Bitstr_dec *streamdata, WebRtc_Word32 *gainQ10)
1523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
1525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index;
1526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of quantization index */
1528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(
1529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      &index,
1530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      streamdata,
1531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      WebRtcIsacfix_kGainPtr,
1532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      WebRtcIsacfix_kGainInitInd,
1533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      1);
1534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* error check */
1535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0) {
1536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return err;
1537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization level */
1540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *gainQ10 = WebRtcIsacfix_kGain2Lev[index];
1541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* quantize & code squared Gain */
1548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeGain2(WebRtc_Word32 *gainQ10, Bitstr_enc *streamdata)
1549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index;
1551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization index */
1554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  index = WebRtcIsacfix_kGainInitInd[0];
1555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (*gainQ10 > WebRtcIsacfix_kGain2Bound[index])
1556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while (*gainQ10 > WebRtcIsacfix_kGain2Bound[index + 1])
1558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index++;
1559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
1561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while (*gainQ10 < WebRtcIsacfix_kGain2Bound[--index]) ;
1563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* dequantize */
1566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *gainQ10 = WebRtcIsacfix_kGain2Lev[index];
1567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of quantization index */
1569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, &index, WebRtcIsacfix_kGainPtr, 1);
1570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */
1572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return status;
1573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* code and decode Pitch Gains and Lags functions */
1577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* decode & dequantize Pitch Gains */
1579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodePitchGain(Bitstr_dec *streamdata, WebRtc_Word16 *PitchGains_Q12)
1580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
1582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_comb;
1583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 *pitch_gain_cdf_ptr[1];
1584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of quantization indices */
1586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf;
1587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistBisectMulti(&index_comb, streamdata, pitch_gain_cdf_ptr, WebRtcIsacfix_kCdfTableSizeGain, 1);
1588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* error check, Q_mean_Gain.. tables are of size 144 */
15891617f65eecbd894b17870929a9ffec4d62078d89tina.legrand@webrtc.org  if ((err < 0) || (index_comb < 0) || (index_comb >= 144))
1590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_PITCH_GAIN;
1591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* unquantize back to pitch gains by table look-up */
1593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb];
1594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb];
1595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb];
1596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb];
1597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* quantize & code Pitch Gains */
1603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodePitchGain(WebRtc_Word16 *PitchGains_Q12, Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData)
1604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k,j;
1606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 SQ15[PITCH_SUBFRAMES];
1607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index[3];
1608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index_comb;
1609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 *pitch_gain_cdf_ptr[1];
1610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 CQ17;
1611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* get the approximate arcsine (almost linear)*/
1615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++)
1616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    SQ15[k] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(PitchGains_Q12[k],33,2); //Q15
1617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization index; only for the first three transform coefficients */
1620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<3; k++)
1621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*  transform */
1623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CQ17=0;
1624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (j=0; j<PITCH_SUBFRAMES; j++) {
1625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], SQ15[j],10); // Q17
1626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index[k] = (WebRtc_Word16)((CQ17 + 8192)>>14); // Rounding and scaling with stepsize (=1/0.125=8)
1629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* check that the index is not outside the boundaries of the table */
1631470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index[k] < WebRtcIsacfix_kLowerlimiGain[k]) index[k] = WebRtcIsacfix_kLowerlimiGain[k];
1632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index[k] > WebRtcIsacfix_kUpperlimitGain[k]) index[k] = WebRtcIsacfix_kUpperlimitGain[k];
1633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index[k] -= WebRtcIsacfix_kLowerlimiGain[k];
1634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* calculate unique overall index */
1637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  index_comb = (WebRtc_Word16)(WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[0], index[0]) +
1638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                               WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[1], index[1]) + index[2]);
1639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* unquantize back to pitch gains by table look-up */
1641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  // (Y)
1642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb];
1643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb];
1644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb];
1645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb];
1646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of quantization pitch gains */
1649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf;
1650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, &index_comb, pitch_gain_cdf_ptr, 1);
1651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0) {
1652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Save data for creation of multiple bitstreams */
1656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (encData != NULL) {
1657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    encData->pitchGain_index[encData->startIdx] = index_comb;
1658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Pitch LAG */
1666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1667470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* decode & dequantize Pitch Lags */
1669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodePitchLag(Bitstr_dec *streamdata,
1670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 WebRtc_Word16 *PitchGain_Q12,
1671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 WebRtc_Word16 *PitchLags_Q7)
1672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, err;
1674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index[PITCH_SUBFRAMES];
1675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *mean_val2Q10, *mean_val4Q10;
1676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *lower_limit;
1678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 *init_index;
1679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 *cdf_size;
1680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 **cdf;
1681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 meangainQ12;
1683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 CQ11, CQ10,tmp32a,tmp32b;
1684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 shft,tmp16a,tmp16c;
1685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  meangainQ12=0;
1687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < 4; k++)
1688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    meangainQ12 += PitchGain_Q12[k];
1689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2);  // Get average
1691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* voicing classificiation */
1693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (meangainQ12 <= 819) {                 // mean_gain < 0.2
1694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = -1;        // StepSize=2.0;
1695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrLo;
1696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf_size = WebRtcIsacfix_kPitchLagSizeLo;
1697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo;
1698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo;
1699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitLo;
1700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    init_index = WebRtcIsacfix_kInitIndLo;
1701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else if (meangainQ12 <= 1638) {            // mean_gain < 0.4
1702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = 0;        // StepSize=1.0;
1703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrMid;
1704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf_size = WebRtcIsacfix_kPitchLagSizeMid;
1705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid;
1706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid;
1707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitMid;
1708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    init_index = WebRtcIsacfix_kInitIndMid;
1709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
1710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = 1;        // StepSize=0.5;
1711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrHi;
1712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf_size = WebRtcIsacfix_kPitchLagSizeHi;
1713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi;
1714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi;
1715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitHi;
1716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    init_index = WebRtcIsacfix_kInitIndHi;
1717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of quantization indices */
1720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1);
1721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if ((err<0) || (index[0]<0))  // error check
1722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG;
1723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(index+1, streamdata, cdf+1, init_index, 3);
1725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
1726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG;
1727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */
1730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ11 = ((WebRtc_Word32)index[0] + lower_limit[0]);  // Q0
1731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11
1732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32a =  WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11);
1734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);
1735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLags_Q7[k] = tmp16a;
1736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ10 = mean_val2Q10[index[1]];
1739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32b =  (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10);
1741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5);
1742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLags_Q7[k] += tmp16c;
1743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ10 = mean_val4Q10[index[3]];
1746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32b =  (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10);
1748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5);
1749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLags_Q7[k] += tmp16c;
1750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
1753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* quantize & code Pitch Lags */
1758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodePitchLag(WebRtc_Word16 *PitchLagsQ7,WebRtc_Word16 *PitchGain_Q12,
1759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData)
1760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k, j;
1762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 index[PITCH_SUBFRAMES];
1763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 meangainQ12, CQ17;
1764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 CQ11, CQ10,tmp32a;
1765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *mean_val2Q10,*mean_val4Q10;
1767470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_Word16 *lower_limit, *upper_limit;
1768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  const WebRtc_UWord16 **cdf;
1769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 shft, tmp16a, tmp16b, tmp16c;
1770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmp32b;
1771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* compute mean pitch gain */
1774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  meangainQ12=0;
1775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < 4; k++)
1776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    meangainQ12 += PitchGain_Q12[k];
1777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2);
1779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Save data for creation of multiple bitstreams */
1781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (encData != NULL) {
1782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    encData->meanGain[encData->startIdx] = meangainQ12;
1783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* voicing classificiation */
1786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (meangainQ12 <= 819) {                 // mean_gain < 0.2
1787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = -1;        // StepSize=2.0;
1788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrLo;
1789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo;
1790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo;
1791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitLo;
1792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    upper_limit = WebRtcIsacfix_kUpperLimitLo;
1793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else if (meangainQ12 <= 1638) {            // mean_gain < 0.4
1794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = 0;        // StepSize=1.0;
1795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrMid;
1796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid;
1797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid;
1798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitMid;
1799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    upper_limit = WebRtcIsacfix_kUpperLimitMid;
1800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
1801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    shft = 1;        // StepSize=0.5;
1802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdf = WebRtcIsacfix_kPitchLagPtrHi;
1803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi;
1804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi;
1805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lower_limit = WebRtcIsacfix_kLowerLimitHi;
1806470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    upper_limit = WebRtcIsacfix_kUpperLimitHi;
1807470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1808470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1809470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find quantization index */
1810470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<4; k++)
1811470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
1812470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*  transform */
1813470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CQ17=0;
1814470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (j=0; j<PITCH_SUBFRAMES; j++)
1815470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], PitchLagsQ7[j],2); // Q17
1816470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1817470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CQ17 = WEBRTC_SPL_SHIFT_W32(CQ17,shft); // Scale with StepSize
1818470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1819470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* quantize */
1820470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16b = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(CQ17 + 65536, 17 );
1821470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index[k] =  tmp16b;
1822470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1823470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* check that the index is not outside the boundaries of the table */
1824470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index[k] < lower_limit[k]) index[k] = lower_limit[k];
1825470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index[k] > upper_limit[k]) index[k] = upper_limit[k];
1826470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index[k] -= lower_limit[k];
1827470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1828470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Save data for creation of multiple bitstreams */
1829470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(encData != NULL) {
1830470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      encData->pitchIndex[PITCH_SUBFRAMES*encData->startIdx + k] = index[k];
1831470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1832470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1833470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1834470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */
1835470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ11 = (index[0] + lower_limit[0]);  // Q0
1836470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11
1837470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1838470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1839470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32a =  WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); // Q12
1840470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);// Q7
1841470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLagsQ7[k] = tmp16a;
1842470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1843470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1844470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ10 = mean_val2Q10[index[1]];
1845470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1846470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32b =  (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10);
1847470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7
1848470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLagsQ7[k] += tmp16c;
1849470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1850470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1851470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  CQ10 = mean_val4Q10[index[3]];
1852470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<PITCH_SUBFRAMES; k++) {
1853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp32b =  (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10);
1854470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7
1855470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    PitchLagsQ7[k] += tmp16c;
1856470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1857470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1858470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of quantization pitch lags */
1859470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, index, cdf, PITCH_SUBFRAMES);
1860470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1861470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */
1862470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return status;
1863470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1864470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1865470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1866470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1867470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Routines for inband signaling of bandwitdh estimation */
1868470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Histograms based on uniform distribution of indices */
1869470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* Move global variables later! */
1870470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1871470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1872470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* cdf array for frame length indicator */
1873470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 kFrameLenCdf[4] = {
1874470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  0, 21845, 43690, 65535};
1875470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1876470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* pointer to cdf array for frame length indicator */
1877470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 *kFrameLenCdfPtr[1] = {kFrameLenCdf};
1878470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1879470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* initial cdf index for decoder of frame length indicator */
1880470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 kFrameLenInitIndex[1] = {1};
1881470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1882470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1883470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeFrameLen(Bitstr_dec *streamdata,
1884470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                 WebRtc_Word16 *framesamples)
1885470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1886470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1887470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
1888470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 frame_mode;
1889470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1890470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = 0;
1891470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of frame length [1:30ms,2:60ms] */
1892470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(&frame_mode, streamdata, kFrameLenCdfPtr, kFrameLenInitIndex, 1);
1893470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
1894470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH;
1895470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1896470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  switch(frame_mode) {
1897470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    case 1:
1898470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *framesamples = 480; /* 30ms */
1899470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      break;
1900470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    case 2:
1901470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *framesamples = 960; /* 60ms */
1902470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      break;
1903470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    default:
1904470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      err = -ISAC_DISALLOWED_FRAME_MODE_DECODER;
1905470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1906470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1907470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return err;
1908470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1909470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1910470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1911470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeFrameLen(WebRtc_Word16 framesamples, Bitstr_enc *streamdata) {
1912470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1913470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status;
1914470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 frame_mode;
1915470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1916470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = 0;
1917470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  frame_mode = 0;
1918470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy coding of frame length [1:480 samples,2:960 samples] */
1919470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  switch(framesamples) {
1920470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    case 480:
1921470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      frame_mode = 1;
1922470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      break;
1923470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    case 960:
1924470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      frame_mode = 2;
1925470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      break;
1926470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    default:
1927470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      status = - ISAC_DISALLOWED_FRAME_MODE_ENCODER;
1928470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
1929470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1930470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (status < 0)
1931470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return status;
1932470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1933470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, &frame_mode, kFrameLenCdfPtr, 1);
1934470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1935470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return status;
1936470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1937470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1938470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* cdf array for estimated bandwidth */
1939470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 kBwCdf[25] = {
1940470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  0, 2731, 5461, 8192, 10923, 13653, 16384, 19114, 21845, 24576, 27306, 30037,
1941470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  32768, 35498, 38229, 40959, 43690, 46421, 49151, 51882, 54613, 57343, 60074,
1942470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  62804, 65535};
1943470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1944470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* pointer to cdf array for estimated bandwidth */
1945470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 *kBwCdfPtr[1] = {kBwCdf};
1946470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1947470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* initial cdf index for decoder of estimated bandwidth*/
1948470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comconst WebRtc_UWord16 kBwInitIndex[1] = {7};
1949470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1950470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1951470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec *streamdata, WebRtc_Word16 *BWno) {
1952470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1953470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int err;
1954470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 BWno32;
1955470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1956470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy decoding of sender's BW estimation [0..23] */
1957470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  err = WebRtcIsacfix_DecHistOneStepMulti(&BWno32, streamdata, kBwCdfPtr, kBwInitIndex, 1);
1958470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (err<0)  // error check
1959470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -ISAC_RANGE_ERROR_DECODE_BANDWIDTH;
1960470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *BWno = (WebRtc_Word16)BWno32;
1961470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return err;
1962470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1963470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1964470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1965470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1966470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncodeReceiveBandwidth(WebRtc_Word16 *BWno, Bitstr_enc *streamdata)
1967470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1968470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int status = 0;
1969470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* entropy encoding of receiver's BW estimation [0..23] */
1970470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  status = WebRtcIsacfix_EncHistMulti(streamdata, BWno, kBwCdfPtr, 1);
1971470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1972470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return status;
1973470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1974470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1975470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* estimate codel length of LPC Coef */
1976470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid WebRtcIsacfix_TranscodeLpcCoef(WebRtc_Word32 *gain_lo_hiQ17,
1977470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    WebRtc_Word16 *index_gQQ) {
197823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  int j, k;
1979470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word16 posQQ, pos2QQ;
198023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtc_Word16 posg, offsg, gainpos;
1981470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_gQ6[KLT_ORDER_GAIN];
1982470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN];
1983470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN];
1984470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtc_Word32 sumQQ;
1985470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1986470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1987470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* log gains, mean removal and scaling */
198823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  posg = 0; gainpos=0;
1989470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1990470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<SUBFRAMES; k++) {
1991470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* log gains */
1992470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1993470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* The input argument X to logN(X) is 2^17 times higher than the
1994470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       input floating point argument Y to log(Y), since the X value
1995470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       is a Q17 value. This can be compensated for after the call, by
1996470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subraction a value Z for each Q-step. One Q-step means that
1997470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 =
1998470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       177.445678 should be subtracted (since logN() returns a Q8 value).
1999470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       For a X value in Q17, the value 177.445678*17 = 3017 should be
2000470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       subtracted */
2001470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
2002470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
2003470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
2004470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2005470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8
2006470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4
2007470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posg++; gainpos++;
2008470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2009470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
2010470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2011470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2012470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* KLT  */
2013470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2014470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* left transform */
2015470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  offsg = 0;
2016470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (j=0; j<SUBFRAMES; j++) {
201723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      // Q21 = Q6 * Q15
201823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg],
201923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   WebRtcIsacfix_kT1GainQ15[0][0]);
202023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg + 1],
202123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                    WebRtcIsacfix_kT1GainQ15[0][2]);
2022470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmpcoeffs2_gQ21[posg] = sumQQ;
2023470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      posg++;
2024470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
202523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      // Q21 = Q6 * Q15
202623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ = WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg],
202723da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                   WebRtcIsacfix_kT1GainQ15[0][1]);
202823da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[offsg + 1],
202923da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                                    WebRtcIsacfix_kT1GainQ15[0][3]);
203023da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      tmpcoeffs2_gQ21[posg] = sumQQ;
203123da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org      posg++;
2032470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
2033470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2034470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* right transform */
203523da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org  WebRtcIsacfix_MatrixProduct2(WebRtcIsacfix_kT2GainQ15[0], tmpcoeffs2_gQ21,
203623da8622c04ac843f7912dd33b4ad55f41422119kma@webrtc.org                               tmpcoeffs_gQ17, kTIndexFactor3, kTIndexStep1);
2037470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2038470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* quantize coefficients */
2039470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok?
2040470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
2041470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    posQQ = WebRtcIsacfix_kSelIndGain[k];
2042470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17);
2043470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2044470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok?
2045470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (index_gQQ[k] < 0) {
2046470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = 0;
2047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) {
2049470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k];
2050470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2051470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
2052470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
2053