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 * decode_plc.c
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Packet Loss Concealment.
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <string.h>
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "settings.h"
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "entropy_coding.h"
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "pitch_estimator.h"
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "bandwidth_estimator.h"
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "structs.h"
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "codec.h"
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
27470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#define NO_OF_PRIMES 8
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#define NOISE_FILTER_LEN 30
30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * function to decode the bitstream
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * returns the total number of bytes in the stream
34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
360946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic int16_t plc_filterma_Fast(
370946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *In,  /* (i)   Vector to be filtered. InOut[-orderCoef+1]
38470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           to InOut[-1] contains state */
390946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *Out,  /* (o)   Filtered vector */
400946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t *B,   /* (i)   The filter coefficients (in Q0) */
410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t Blen,  /* (i)   Number of B coefficients */
420946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t len,   /* (i)  Number of samples to be filtered */
430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t reduceDecay,
440946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t decay,
450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    int16_t rshift )
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int i, j;
480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t o;
49d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker  int32_t lim = (1 << (15 + rshift)) - 1;
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (i = 0; i < len; i++)
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
53e4b6064f8e6b0b448f070155b1b6c4b6788107dfpbos@webrtc.org    const int16_t *b_ptr = &B[0];
54e4b6064f8e6b0b448f070155b1b6c4b6788107dfpbos@webrtc.org    const int16_t *x_ptr = &In[i];
55470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
560946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    o = (int32_t)0;
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (j = 0;j < Blen; j++)
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
60bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org      o = WebRtcSpl_AddSatW32(o, *b_ptr * *x_ptr);
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      b_ptr++;
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      x_ptr--;
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* to round off correctly */
666e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org    o = WebRtcSpl_AddSatW32(o, 1 << (rshift - 1));
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* saturate according to the domain of the filter coefficients */
690946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    o = WEBRTC_SPL_SAT((int32_t)lim, o, (int32_t)-lim);
70470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
710946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    /* o should be in the range of int16_t */
72a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    o >>= rshift;
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* decay the output signal; this is specific to plc */
75f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker    *Out++ = (int16_t)((int16_t)o * decay >> 15);
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* change the decay */
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    decay -= reduceDecay;
79470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( decay < 0 )
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      decay = 0;
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return( decay );
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
84470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
920946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic __inline int32_t log2_Q8_T( uint32_t x ) {
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
943ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  int32_t zeros;
950946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t frac;
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  zeros=WebRtcSpl_NormU32(x);
98a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org  frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23);
99470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1003ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  /* log2(magn(i)) */
1013ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org  return ((31 - zeros) << 8) + frac;
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1040946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic __inline int16_t  exp2_Q10_T(int16_t x) { // Both in and out in Q10
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1060946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp16_1, tmp16_2;
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1080946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  tmp16_2=(int16_t)(0x0400|(x&0x03FF));
109f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org  tmp16_1 = -(x >> 10);
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if(tmp16_1>0)
111f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org    return tmp16_2 >> tmp16_1;
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
1133ea35fdb1b3bc50e98b0fee03d274dce76fbdd55bjornv@webrtc.org    return tmp16_2 << -tmp16_1;
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  This is a fixed-point version of the above code with limLow = 700 and limHigh = 5000,
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  hard-coded. The values 700 and 5000 were experimentally obtained.
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  The function implements membership values for two sets. The mebership functions are
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  of second orders corresponding to half-bell-shapped pulses.
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
1250946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic void MemshipValQ15( int16_t in, int16_t *A, int16_t *B )
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1270946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t x;
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  in -= 700;    /* translate the lowLim to 0, limHigh = 5000 - 700, M = 2150 */
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( in <= 2150 )
132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( in > 0 )
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* b = in^2 / (2 * M^2), a = 1 - b in Q0.
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         We have to compute in Q15 */
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* x = in / 2150 {in Q15} = x * 15.2409 {in Q15} =
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         x*15 + (x*983)/(2^12); note that 983/2^12 = 0.23999     */
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      /* we are sure that x is in the range of int16_t            */
142f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      x = (int16_t)(in * 15 + (in * 983 >> 12));
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* b = x^2 / 2 {in Q15} so a shift of 16 is required to
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         be in correct domain and one more for the division by 2 */
145a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      *B = (int16_t)((x * x + 0x00010000) >> 17);
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *A = WEBRTC_SPL_WORD16_MAX - *B;
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *B = 0;
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *A = WEBRTC_SPL_WORD16_MAX;
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( in < 4300 )
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* This is a mirror case of the above */
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      in = 4300 - in;
160f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker      x = (int16_t)(in * 15 + (in * 983 >> 12));
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* b = x^2 / 2 {in Q15} so a shift of 16 is required to
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         be in correct domain and one more for the division by 2 */
163a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      *A = (int16_t)((x * x + 0x00010000) >> 17);
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *B = WEBRTC_SPL_WORD16_MAX - *A;
165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *A = 0;
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *B = WEBRTC_SPL_WORD16_MAX;
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
178728d9037c016c01295177fa700fc7927f0bb80bbPeter Kastingstatic void LinearResampler(int16_t* in,
179728d9037c016c01295177fa700fc7927f0bb80bbPeter Kasting                            int16_t* out,
180dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                            size_t lenIn,
181dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                            size_t lenOut)
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
183dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  size_t n = (lenIn - 1) * RESAMP_RES;
184dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  int16_t resOut, relativePos, diff; /* */
185dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  size_t i, j;
1860946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t udiff;
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( lenIn == lenOut )
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16( out, in, lenIn );
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return;
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
194dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  resOut = WebRtcSpl_DivW32W16ResW16( (int32_t)n, (int16_t)(lenOut-1) );
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  out[0] = in[0];
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( i = 1, j = 0, relativePos = 0; i < lenOut; i++ )
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    relativePos += resOut;
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while( relativePos > RESAMP_RES )
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      j++;
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      relativePos -= RESAMP_RES;
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* an overflow may happen and the differce in sample values may
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * require more than 16 bits. We like to avoid 32 bit arithmatic
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * as much as possible */
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (in[ j ] > 0) && (in[j + 1] < 0) )
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2140946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      udiff = (uint16_t)(in[ j ] - in[j + 1]);
2150946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      out[ i ] = in[ j ] - (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT);
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( (in[j] < 0) && (in[j+1] > 0) )
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
2210946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        udiff = (uint16_t)( in[j + 1] - in[ j ] );
2220946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        out[ i ] = in[ j ] + (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT);
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        diff = in[ j + 1 ] - in[ j ];
227f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        out[i] = in[j] + (int16_t)(diff * relativePos >> RESAMP_RES_BIT);
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
237728d9037c016c01295177fa700fc7927f0bb80bbPeter Kastingvoid WebRtcIsacfix_DecodePlcImpl(int16_t *signal_out16,
238728d9037c016c01295177fa700fc7927f0bb80bbPeter Kasting                                 IsacFixDecoderInstance *ISACdec_obj,
239dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting                                 size_t *current_framesamples )
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int subframecnt;
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t* Vector_Word16_1;
2440946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t  Vector_Word16_Extended_1[FRAMESAMPLES_HALF + NOISE_FILTER_LEN];
2450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t* Vector_Word16_2;
2460946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t  Vector_Word16_Extended_2[FRAMESAMPLES_HALF + NOISE_FILTER_LEN];
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t Vector_Word32_1[FRAMESAMPLES_HALF];
2490946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t Vector_Word32_2[FRAMESAMPLES_HALF];
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2510946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs
2520946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2540946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t pitchLags_Q7[PITCH_SUBFRAMES];
2550946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t pitchGains_Q12[PITCH_SUBFRAMES];
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2570946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp_1, tmp_2;
2580946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32a, tmp32b;
2590946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t gainQ13;
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t myDecayRate;
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ---------- PLC variables ------------ */
264dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  size_t lag0, i, k;
265dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  int16_t noiseIndex;
2660946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t stretchPitchLP[PITCH_MAX_LAG + 10], stretchPitchLP1[PITCH_MAX_LAG + 10];
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2680946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t gain_lo_hiQ17[2*SUBFRAMES];
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
270dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  int16_t nLP, pLP, wNoisyLP, wPriodicLP, tmp16;
271dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  size_t minIdx;
2720946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t nHP, pHP, wNoisyHP, wPriodicHP, corr, minCorr, maxCoeff;
2730946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t noise1, rshift;
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2760946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t ltpGain, pitchGain, myVoiceIndicator, myAbs, maxAbs;
2770946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t varIn, varOut, logVarIn, logVarOut, Q, logMaxAbs;
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int rightShiftIn, rightShiftOut;
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ------------------------------------- */
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  myDecayRate = (DECAY_RATE);
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Vector_Word16_1 = &Vector_Word16_Extended_1[NOISE_FILTER_LEN];
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Vector_Word16_2 = &Vector_Word16_Extended_2[NOISE_FILTER_LEN];
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ----- Simply Copy Previous LPC parameters ------ */
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( subframecnt = 0; subframecnt < SUBFRAMES; subframecnt++ )
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* lower Band */
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16(&lofilt_coefQ15[ subframecnt * ORDERLO ],
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          (ISACdec_obj->plcstr_obj).lofilt_coefQ15, ORDERLO);
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[2*subframecnt] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0];
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Upper Band */
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16(&hifilt_coefQ15[ subframecnt * ORDERHI ],
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          (ISACdec_obj->plcstr_obj).hifilt_coefQ15, ORDERHI);
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[2*subframecnt + 1] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1];
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
306dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  lag0 = (size_t)(((ISACdec_obj->plcstr_obj.lastPitchLag_Q7 + 64) >> 7) + 1);
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).used != PLC_WAS_USED )
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).pitchCycles = 0;
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).lastPitchLP =
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &((ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0]);
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    minCorr = WEBRTC_SPL_WORD32_MAX;
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
317f045e4da43e671ae511aa1d9b6ef2968256a745dPeter Kasting    if ((FRAMESAMPLES_HALF - 10) > 2 * lag0)
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      minIdx = 11;
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0; i < 21; i++ )
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        corr = 0;
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        for( k = 0; k < lag0; k++ )
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3256e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org          corr = WebRtcSpl_AddSatW32(corr, WEBRTC_SPL_ABS_W32(
3261b21a579028998e717c35e320cd1d6258b2b650dbjornv@webrtc.org              WebRtcSpl_SubSatW16(
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  (ISACdec_obj->plcstr_obj).lastPitchLP[k],
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  (ISACdec_obj->plcstr_obj).prevPitchInvIn[
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      FRAMESAMPLES_HALF - 2*lag0 - 10 + i + k ] ) ) );
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( corr < minCorr )
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          minCorr = corr;
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          minIdx = i;
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).prevPitchLP =
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          &( (ISACdec_obj->plcstr_obj).prevPitchInvIn[
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              FRAMESAMPLES_HALF - lag0*2 - 10 + minIdx] );
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).prevPitchLP =
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).lastPitchLP;
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pitchGain = (ISACdec_obj->plcstr_obj).lastPitchGain_Q12;
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_AutoCorrelation(
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0],
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        lag0, 0, &varIn, &rightShiftIn);
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_AutoCorrelation(
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevPitchInvOut[PITCH_MAX_LAG + 10 - lag0],
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        lag0, 0, &varOut, &rightShiftOut);
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    maxAbs = 0;
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i< lag0; i++)
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      myAbs = WEBRTC_SPL_ABS_W16(
359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).prevPitchInvOut[
360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              PITCH_MAX_LAG + 10 - lag0 + i] );
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maxAbs = (myAbs > maxAbs)? myAbs:maxAbs;
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarIn = log2_Q8_T( (uint32_t)( varIn ) ) +
3640946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int32_t)(rightShiftIn << 8);
3650946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarOut = log2_Q8_T( (uint32_t)( varOut ) ) +
3660946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int32_t)(rightShiftOut << 8);
3670946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logMaxAbs = log2_Q8_T( (uint32_t)( maxAbs ) );
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3690946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    ltpGain = (int16_t)(logVarOut - logVarIn);
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Q = 2 * logMaxAbs - ( logVarOut - 1512 );
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * ---
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * We are computing sqrt( (VarIn/lag0) / var( noise ) )
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * var( noise ) is almost 256. we have already computed log2( VarIn ) in Q8
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * so we actually compute 2^( 0.5*(log2( VarIn ) - log2( lag0 ) - log2( var(noise ) )  ).
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * Note that put log function is in Q8 but the exponential function is in Q10.
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * --
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     */
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3810946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarIn -= log2_Q8_T( (uint32_t)( lag0 ) );
3820946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp16 = (int16_t)((logVarIn<<1) - (4<<10) );
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rightShiftIn = 0;
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( tmp16 > 4096 )
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 -= 4096;
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 = exp2_Q10_T( tmp16 );
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 >>= 6;
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 = exp2_Q10_T( tmp16 )>>10;
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).std = tmp16 - 4;
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (ltpGain < 110) || (ltpGain > 230) )
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( ltpGain < 100 && (pitchGain < 1800) )
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = WEBRTC_SPL_WORD16_MAX;
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = ((ltpGain < 110) && (Q < 800)
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       )? WEBRTC_SPL_WORD16_MAX:0;
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX -
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).A;
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( (pitchGain < 450) || (pitchGain > 1600) )
412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = ((pitchGain < 450)
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       )? WEBRTC_SPL_WORD16_MAX:0;
415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX -
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).A;
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        myVoiceIndicator = ltpGain * 2 + pitchGain;
421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        MemshipValQ15( myVoiceIndicator,
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B );
423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myVoiceIndicator = ltpGain * 16 + pitchGain * 2 + (pitchGain >> 8);
429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    MemshipValQ15( myVoiceIndicator,
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B );
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).stretchLag = lag0;
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).pitchIndex = 0;
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myDecayRate = (DECAY_RATE<<2);
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).B < 1000 )
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myDecayRate += (DECAY_RATE<<3);
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ------------ reconstructing the residual signal ------------------ */
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP,
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* inverse pitch filter */
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  pitchLags_Q7[0] = pitchLags_Q7[1] = pitchLags_Q7[2] = pitchLags_Q7[3] =
455b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting      (int16_t)((ISACdec_obj->plcstr_obj).stretchLag<<7);
456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  pitchGains_Q12[3] = ( (ISACdec_obj->plcstr_obj).lastPitchGain_Q12);
457f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[2] = (int16_t)(pitchGains_Q12[3] * 1010 >> 10);
458f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[1] = (int16_t)(pitchGains_Q12[2] * 1010 >> 10);
459f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[0] = (int16_t)(pitchGains_Q12[1] * 1010 >> 10);
460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* most of the time either B or A are zero so seperating */
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).B == 0 )
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
465470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < FRAMESAMPLES_HALF; i++ )
466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* --- Low Pass                                             */
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
470f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* --- Highpass                                              */
473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
475f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 1; i < NOISE_FILTER_LEN; i++ )
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
481470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
482f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_Extended_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
485470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
486f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_Extended_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    plc_filterma_Fast(Vector_Word16_1, Vector_Word16_Extended_1,
489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF -
4900946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                                                NOISE_FILTER_LEN], (int16_t) NOISE_FILTER_LEN,
4910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int16_t) FRAMESAMPLES_HALF, (int16_t)(5),
4920946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (ISACdec_obj->plcstr_obj).decayCoeffNoise, (int16_t)(6));
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    maxCoeff = WebRtcSpl_MaxAbsValueW32(
495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevHP[
496470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN], NOISE_FILTER_LEN );
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rshift = 0;
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while( maxCoeff > WEBRTC_SPL_WORD16_MAX )
500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
501a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      maxCoeff >>= 1;
502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rshift++;
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < NOISE_FILTER_LEN; i++ ) {
505a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] =(int16_t)(
506a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          ISACdec_obj->plcstr_obj.prevHP[PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN +
507a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org                                         i] >> rshift);
508470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).decayCoeffNoise = plc_filterma_Fast(
510470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_2,
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_Extended_2,
512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN],
5130946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) NOISE_FILTER_LEN,
5140946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) FRAMESAMPLES_HALF,
5150946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) (5),
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffNoise,
5170946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) (7) );
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < FRAMESAMPLES_HALF; i++ )
520d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      Vector_Word32_2[i] = Vector_Word16_Extended_2[i] << rshift;
521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_1 = Vector_Word16_Extended_1;
523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (ISACdec_obj->plcstr_obj).A == 0 )
527470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
528470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* ------ Periodic Vector ---                                */
529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ )
530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
531470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Lowpass                                               */
532f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        pLP = (int16_t)(stretchPitchLP[ISACdec_obj->plcstr_obj.pitchIndex] *
533f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
5360946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffPriodic,
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 -
539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).stretchLag +
540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).pitchIndex] );
541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate);
544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 )
545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0;
546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).pitchIndex++;
548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).pitchIndex ==
550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag )
551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchIndex = 0;
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchCycles++;
554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) )
556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1;
558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          else
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0;
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).stretchLag = (
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                  )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag;
567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP,
569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler( (ISACdec_obj->plcstr_obj).prevPitchLP,
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          switch( (ISACdec_obj->plcstr_obj).pitchCycles )
575470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 1:
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
5800946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
5810946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k]* 3 +
5820946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k])>>2);
583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 2:
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
5900946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
5910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k] +
5920946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k] )>>1);
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 3:
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
6000946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((stretchPitchLP[k] +
6010946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                                       (int32_t)stretchPitchLP1[k]*3 )>>2);
602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 )
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            myDecayRate += 35; //(myDecayRate>>1);
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).pitchCycles = 0;
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Sum the noisy and periodic signals  ------ */
616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_1[i] = pLP;
617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word32_2[i] = pHP;
618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ )
623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
625470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
626470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).seed );
627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
628f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org        noise1 = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
630f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        nLP = (int16_t)((int16_t)(noise1 * ISACdec_obj->plcstr_obj.std) *
631f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffNoise >> 15);
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
633470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
635470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).seed );
636f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org        noise1 = (ISACdec_obj->plcstr_obj.seed >> 11) - 8;
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6380946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        nHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffNoise,
6400946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org            (int32_t)(noise1*(ISACdec_obj->plcstr_obj).std) );
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffNoise -= (myDecayRate);
644470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffNoise < 0 )
645470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffNoise = 0;
646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Periodic Vector ---                                */
648470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Lowpass                                               */
649f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        pLP = (int16_t)(stretchPitchLP[ISACdec_obj->plcstr_obj.pitchIndex] *
650f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
6530946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffPriodic,
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 -
656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).stretchLag +
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).pitchIndex] );
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate);
661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 )
662470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
663470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0;
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
666470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Weighting the noisy and periodic vectors -------   */
667f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        wNoisyLP = (int16_t)(ISACdec_obj->plcstr_obj.A * nLP >> 15);
6680946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        wNoisyHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15(
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).A, (nHP) ) );
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
671f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        wPriodicLP = (int16_t)(ISACdec_obj->plcstr_obj.B * pLP >> 15);
6720946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        wPriodicHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15(
673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).B, pHP));
674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).pitchIndex++;
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if((ISACdec_obj->plcstr_obj).pitchIndex ==
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           (ISACdec_obj->plcstr_obj).stretchLag)
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchIndex = 0;
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchCycles++;
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) )
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1;
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          else
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0;
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).stretchLag = (
689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                  )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag;
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler(
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).lastPitchLP,
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler((ISACdec_obj->plcstr_obj).prevPitchLP,
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          switch((ISACdec_obj->plcstr_obj).pitchCycles)
699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
700470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 1:
701470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
7040946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
7050946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k]* 3 +
7060946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k] )>>2);
707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
709470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 2:
711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
7140946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
7150946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k] +
7160946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k])>>1);
717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
719470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 3:
721470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
7240946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)(
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      (stretchPitchLP[k] +
7260946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                       (int32_t)stretchPitchLP1[k]*3 )>>2);
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 )
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            myDecayRate += 55; //(myDecayRate>>1);
735470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).pitchCycles = 0;
736470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Sum the noisy and periodic signals  ------ */
7406e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org        Vector_Word16_1[i] = WebRtcSpl_AddSatW16(wNoisyLP, wPriodicLP);
7416e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org        Vector_Word32_2[i] = WebRtcSpl_AddSatW32(wNoisyHP, wPriodicHP);
742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ----------------- residual signal is reconstructed ------------------ */
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
747470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  k = (ISACdec_obj->plcstr_obj).pitchIndex;
748470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* --- Write one pitch cycle for recovery block --- */
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( i = 0; i < RECOVERY_OVERLAP; i++ )
751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
752f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker    ISACdec_obj->plcstr_obj.overlapLP[i] = (int16_t)(
753f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        stretchPitchLP[k] * ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    k = ( k < ((ISACdec_obj->plcstr_obj).stretchLag - 1) )? (k+1):0;
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
757b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting  (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 =
758b7e5054414ff524f9db81dab7917729b8c4c8bcbPeter Kasting      (int16_t)((ISACdec_obj->plcstr_obj).stretchLag << 7);
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
761470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* --- Inverse Pitch Filter --- */
762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2,
763470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            &ISACdec_obj->pitchfiltstr_obj, pitchLags_Q7, pitchGains_Q12, 4);
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* reduce gain to compensate for pitch enhancer */
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* gain = 1.0f - 0.45f * AvgPitchGain; */
767f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  tmp32a = ISACdec_obj->plcstr_obj.AvgPitchGain_Q12 * 29;  // Q18
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  tmp32b = 262144 - tmp32a;  // Q18
7690946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  gainQ13 = (int16_t) (tmp32b >> 5); // Q13
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* perceptual post-filtering (using normalized lattice filter) */
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < FRAMESAMPLES_HALF; k++)
773bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    Vector_Word32_1[k] = (Vector_Word16_2[k] * gainQ13) << 3;  // Q25
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_NormLatticeFilterAr(ORDERLO,
777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0,
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1);
779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_NormLatticeFilterAr(ORDERHI,
781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0,
782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    Vector_Word32_2, hifilt_coefQ15, gain_lo_hiQ17, 1, Vector_Word16_2);
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
784470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* recombine the 2 bands */
785470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Form the polyphase signals, and compensate for DC offset */
787470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0;k<FRAMESAMPLES_HALF;k++)
788470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Construct a new upper channel signal*/
7900946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp_1 = (int16_t)WebRtcSpl_SatW32ToW16(
7910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                           ((int32_t)Vector_Word16_1[k]+Vector_Word16_2[k] + 1));
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Construct a new lower channel signal*/
7930946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp_2 = (int16_t)WebRtcSpl_SatW32ToW16(
7940946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                           ((int32_t)Vector_Word16_1[k]-Vector_Word16_2[k]));
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_1[k] = tmp_1;
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_2[k] = tmp_2;
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1,
801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                  Vector_Word16_2, signal_out16, &ISACdec_obj->postfiltbankstr_obj);
802470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
803470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  (ISACdec_obj->plcstr_obj).used = PLC_WAS_USED;
804470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *current_framesamples = 480;
805470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
806