decode_plc.c revision f045e4da43e671ae511aa1d9b6ef2968256a745d
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
1780946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgstatic void LinearResampler( int16_t *in, int16_t *out, int16_t lenIn, int16_t lenOut )
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
180bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org  int32_t n = (lenIn - 1) * RESAMP_RES;
1810946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t resOut, i, j, relativePos, diff; /* */
1820946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t udiff;
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( lenIn == lenOut )
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16( out, in, lenIn );
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return;
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1900946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  resOut = WebRtcSpl_DivW32W16ResW16( n, (int16_t)(lenOut-1) );
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  out[0] = in[0];
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( i = 1, j = 0, relativePos = 0; i < lenOut; i++ )
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    relativePos += resOut;
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while( relativePos > RESAMP_RES )
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      j++;
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      relativePos -= RESAMP_RES;
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* an overflow may happen and the differce in sample values may
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * require more than 16 bits. We like to avoid 32 bit arithmatic
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * as much as possible */
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (in[ j ] > 0) && (in[j + 1] < 0) )
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
2100946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      udiff = (uint16_t)(in[ j ] - in[j + 1]);
2110946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org      out[ i ] = in[ j ] - (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT);
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( (in[j] < 0) && (in[j+1] > 0) )
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
2170946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        udiff = (uint16_t)( in[j + 1] - in[ j ] );
2180946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        out[ i ] = in[ j ] + (uint16_t)( ((int32_t)( udiff * relativePos )) >> RESAMP_RES_BIT);
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        diff = in[ j + 1 ] - in[ j ];
223f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        out[i] = in[j] + (int16_t)(diff * relativePos >> RESAMP_RES_BIT);
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2330946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgint16_t WebRtcIsacfix_DecodePlcImpl(int16_t *signal_out16,
234eb544460e47140d494dddf1217a698a1dcf4dee0pbos@webrtc.org                                    IsacFixDecoderInstance *ISACdec_obj,
2350946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                    int16_t *current_framesamples )
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int subframecnt;
2380946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t len = 0;
239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2400946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t* Vector_Word16_1;
2410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t  Vector_Word16_Extended_1[FRAMESAMPLES_HALF + NOISE_FILTER_LEN];
2420946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t* Vector_Word16_2;
2430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t  Vector_Word16_Extended_2[FRAMESAMPLES_HALF + NOISE_FILTER_LEN];
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t Vector_Word32_1[FRAMESAMPLES_HALF];
2460946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t Vector_Word32_2[FRAMESAMPLES_HALF];
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs
2490946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2510946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t pitchLags_Q7[PITCH_SUBFRAMES];
2520946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t pitchGains_Q12[PITCH_SUBFRAMES];
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2540946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t tmp_1, tmp_2;
2550946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t tmp32a, tmp32b;
2560946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t gainQ13;
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2580946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t myDecayRate;
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ---------- PLC variables ------------ */
2610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t lag0, i, k, noiseIndex;
2620946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t stretchPitchLP[PITCH_MAX_LAG + 10], stretchPitchLP1[PITCH_MAX_LAG + 10];
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2640946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t gain_lo_hiQ17[2*SUBFRAMES];
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2660946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t nLP, pLP, wNoisyLP, wPriodicLP, tmp16, minIdx;
2670946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t nHP, pHP, wNoisyHP, wPriodicHP, corr, minCorr, maxCoeff;
2680946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t noise1, rshift;
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2710946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t ltpGain, pitchGain, myVoiceIndicator, myAbs, maxAbs;
2720946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int32_t varIn, varOut, logVarIn, logVarOut, Q, logMaxAbs;
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int rightShiftIn, rightShiftOut;
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ------------------------------------- */
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  myDecayRate = (DECAY_RATE);
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Vector_Word16_1 = &Vector_Word16_Extended_1[NOISE_FILTER_LEN];
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  Vector_Word16_2 = &Vector_Word16_Extended_2[NOISE_FILTER_LEN];
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ----- Simply Copy Previous LPC parameters ------ */
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( subframecnt = 0; subframecnt < SUBFRAMES; subframecnt++ )
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* lower Band */
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16(&lofilt_coefQ15[ subframecnt * ORDERLO ],
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          (ISACdec_obj->plcstr_obj).lofilt_coefQ15, ORDERLO);
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[2*subframecnt] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0];
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Upper Band */
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_SPL_MEMCPY_W16(&hifilt_coefQ15[ subframecnt * ORDERHI ],
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          (ISACdec_obj->plcstr_obj).hifilt_coefQ15, ORDERHI);
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    gain_lo_hiQ17[2*subframecnt + 1] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1];
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
301f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org  lag0 = ((ISACdec_obj->plcstr_obj.lastPitchLag_Q7 + 64) >> 7) + 1;
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).used != PLC_WAS_USED )
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).pitchCycles = 0;
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).lastPitchLP =
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &((ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0]);
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    minCorr = WEBRTC_SPL_WORD32_MAX;
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
312f045e4da43e671ae511aa1d9b6ef2968256a745dPeter Kasting    if ((FRAMESAMPLES_HALF - 10) > 2 * lag0)
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      minIdx = 11;
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0; i < 21; i++ )
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        corr = 0;
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        for( k = 0; k < lag0; k++ )
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
3206e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org          corr = WebRtcSpl_AddSatW32(corr, WEBRTC_SPL_ABS_W32(
3211b21a579028998e717c35e320cd1d6258b2b650dbjornv@webrtc.org              WebRtcSpl_SubSatW16(
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  (ISACdec_obj->plcstr_obj).lastPitchLP[k],
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                  (ISACdec_obj->plcstr_obj).prevPitchInvIn[
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      FRAMESAMPLES_HALF - 2*lag0 - 10 + i + k ] ) ) );
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( corr < minCorr )
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          minCorr = corr;
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          minIdx = i;
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).prevPitchLP =
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          &( (ISACdec_obj->plcstr_obj).prevPitchInvIn[
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              FRAMESAMPLES_HALF - lag0*2 - 10 + minIdx] );
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).prevPitchLP =
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).lastPitchLP;
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    pitchGain = (ISACdec_obj->plcstr_obj).lastPitchGain_Q12;
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_AutoCorrelation(
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0],
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        lag0, 0, &varIn, &rightShiftIn);
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtcSpl_AutoCorrelation(
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevPitchInvOut[PITCH_MAX_LAG + 10 - lag0],
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        lag0, 0, &varOut, &rightShiftOut);
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    maxAbs = 0;
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i< lag0; i++)
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      myAbs = WEBRTC_SPL_ABS_W16(
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).prevPitchInvOut[
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              PITCH_MAX_LAG + 10 - lag0 + i] );
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      maxAbs = (myAbs > maxAbs)? myAbs:maxAbs;
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
3580946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarIn = log2_Q8_T( (uint32_t)( varIn ) ) +
3590946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int32_t)(rightShiftIn << 8);
3600946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarOut = log2_Q8_T( (uint32_t)( varOut ) ) +
3610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int32_t)(rightShiftOut << 8);
3620946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logMaxAbs = log2_Q8_T( (uint32_t)( maxAbs ) );
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3640946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    ltpGain = (int16_t)(logVarOut - logVarIn);
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Q = 2 * logMaxAbs - ( logVarOut - 1512 );
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /*
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * ---
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * We are computing sqrt( (VarIn/lag0) / var( noise ) )
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * var( noise ) is almost 256. we have already computed log2( VarIn ) in Q8
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * so we actually compute 2^( 0.5*(log2( VarIn ) - log2( lag0 ) - log2( var(noise ) )  ).
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * Note that put log function is in Q8 but the exponential function is in Q10.
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * --
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     */
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3760946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    logVarIn -= log2_Q8_T( (uint32_t)( lag0 ) );
3770946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp16 = (int16_t)((logVarIn<<1) - (4<<10) );
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rightShiftIn = 0;
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( tmp16 > 4096 )
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 -= 4096;
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 = exp2_Q10_T( tmp16 );
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 >>= 6;
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      tmp16 = exp2_Q10_T( tmp16 )>>10;
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).std = tmp16 - 4;
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (ltpGain < 110) || (ltpGain > 230) )
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( ltpGain < 100 && (pitchGain < 1800) )
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = WEBRTC_SPL_WORD16_MAX;
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = ((ltpGain < 110) && (Q < 800)
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       )? WEBRTC_SPL_WORD16_MAX:0;
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX -
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).A;
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( (pitchGain < 450) || (pitchGain > 1600) )
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).A = ((pitchGain < 450)
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       )? WEBRTC_SPL_WORD16_MAX:0;
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX -
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).A;
412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      else
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        myVoiceIndicator = ltpGain * 2 + pitchGain;
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        MemshipValQ15( myVoiceIndicator,
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                       &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B );
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
423470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myVoiceIndicator = ltpGain * 16 + pitchGain * 2 + (pitchGain >> 8);
424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    MemshipValQ15( myVoiceIndicator,
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B );
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
429470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).stretchLag = lag0;
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).pitchIndex = 0;
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myDecayRate = (DECAY_RATE<<2);
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).B < 1000 )
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    myDecayRate += (DECAY_RATE<<3);
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ------------ reconstructing the residual signal ------------------ */
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP,
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                   stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* inverse pitch filter */
448470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  pitchLags_Q7[0] = pitchLags_Q7[1] = pitchLags_Q7[2] = pitchLags_Q7[3] =
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      ((ISACdec_obj->plcstr_obj).stretchLag<<7);
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  pitchGains_Q12[3] = ( (ISACdec_obj->plcstr_obj).lastPitchGain_Q12);
452f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[2] = (int16_t)(pitchGains_Q12[3] * 1010 >> 10);
453f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[1] = (int16_t)(pitchGains_Q12[2] * 1010 >> 10);
454f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  pitchGains_Q12[0] = (int16_t)(pitchGains_Q12[1] * 1010 >> 10);
455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* most of the time either B or A are zero so seperating */
458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if( (ISACdec_obj->plcstr_obj).B == 0 )
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < FRAMESAMPLES_HALF; i++ )
461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* --- Low Pass                                             */
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
465f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
466470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
467470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* --- Highpass                                              */
468470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
469470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
470f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
471470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
473470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 1; i < NOISE_FILTER_LEN; i++ )
474470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
475470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
476470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
477f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_Extended_1[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
480470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).seed );
481f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      Vector_Word16_Extended_2[i] = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
482470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
483470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    plc_filterma_Fast(Vector_Word16_1, Vector_Word16_Extended_1,
484470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF -
4850946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                                                NOISE_FILTER_LEN], (int16_t) NOISE_FILTER_LEN,
4860946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int16_t) FRAMESAMPLES_HALF, (int16_t)(5),
4870946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (ISACdec_obj->plcstr_obj).decayCoeffNoise, (int16_t)(6));
488470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
489470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    maxCoeff = WebRtcSpl_MaxAbsValueW32(
490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &(ISACdec_obj->plcstr_obj).prevHP[
491470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN], NOISE_FILTER_LEN );
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    rshift = 0;
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while( maxCoeff > WEBRTC_SPL_WORD16_MAX )
495470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
496a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      maxCoeff >>= 1;
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      rshift++;
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < NOISE_FILTER_LEN; i++ ) {
500a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org      Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] =(int16_t)(
501a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org          ISACdec_obj->plcstr_obj.prevHP[PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN +
502a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org                                         i] >> rshift);
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (ISACdec_obj->plcstr_obj).decayCoeffNoise = plc_filterma_Fast(
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_2,
506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_Extended_2,
507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        &Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN],
5080946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) NOISE_FILTER_LEN,
5090946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) FRAMESAMPLES_HALF,
5100946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) (5),
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffNoise,
5120946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        (int16_t) (7) );
513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for( i = 0; i < FRAMESAMPLES_HALF; i++ )
515d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      Vector_Word32_2[i] = Vector_Word16_Extended_2[i] << rshift;
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_1 = Vector_Word16_Extended_1;
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  else
520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if( (ISACdec_obj->plcstr_obj).A == 0 )
522470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
523470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* ------ Periodic Vector ---                                */
524470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ )
525470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
526470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Lowpass                                               */
527f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        pLP = (int16_t)(stretchPitchLP[ISACdec_obj->plcstr_obj.pitchIndex] *
528f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
529470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
530470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
5310946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
532470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffPriodic,
533470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 -
534470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).stretchLag +
535470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).pitchIndex] );
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate);
539470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 )
540470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0;
541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
542470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).pitchIndex++;
543470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
544470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).pitchIndex ==
545470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag )
546470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
547470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchIndex = 0;
548470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchCycles++;
549470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
550470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) )
551470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
552470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1;
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          else
555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0;
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).stretchLag = (
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                  )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag;
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
563470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP,
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler( (ISACdec_obj->plcstr_obj).prevPitchLP,
567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
569470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          switch( (ISACdec_obj->plcstr_obj).pitchCycles )
570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
571470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 1:
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
5750946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
5760946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k]* 3 +
5770946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k])>>2);
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
580470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 2:
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
5850946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
5860946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k] +
5870946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k] )>>1);
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
591470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 3:
592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
594470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
5950946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((stretchPitchLP[k] +
5960946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                                       (int32_t)stretchPitchLP1[k]*3 )>>2);
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
599470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
601470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
602470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 )
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            myDecayRate += 35; //(myDecayRate>>1);
605470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).pitchCycles = 0;
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
610470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Sum the noisy and periodic signals  ------ */
611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word16_1[i] = pLP;
612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Vector_Word32_2[i] = pHP;
613470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
614470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
615470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
616470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
617470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ )
618470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
619470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
621470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).seed );
622470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
623f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org        noise1 = (ISACdec_obj->plcstr_obj.seed >> 10) - 16;
624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
625f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        nLP = (int16_t)((int16_t)(noise1 * ISACdec_obj->plcstr_obj.std) *
626f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffNoise >> 15);
627470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
628470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
629470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND(
630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).seed );
631f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org        noise1 = (ISACdec_obj->plcstr_obj.seed >> 11) - 8;
632470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6330946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        nHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffNoise,
6350946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org            (int32_t)(noise1*(ISACdec_obj->plcstr_obj).std) );
636470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffNoise -= (myDecayRate);
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffNoise < 0 )
640470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffNoise = 0;
641470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
642470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Periodic Vector ---                                */
643470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Lowpass                                               */
644f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        pLP = (int16_t)(stretchPitchLP[ISACdec_obj->plcstr_obj.pitchIndex] *
645f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker            ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
646470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- Highpass                                              */
6480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        pHP = (int32_t)WEBRTC_SPL_MUL_16_32_RSFT15(
649470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).decayCoeffPriodic,
650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 -
651470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).stretchLag +
652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                             (ISACdec_obj->plcstr_obj).pitchIndex] );
653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
654470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* --- lower the muliplier (more decay at next sample) --- */
655470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate);
656470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 )
657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
658470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0;
659470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
660470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Weighting the noisy and periodic vectors -------   */
662f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        wNoisyLP = (int16_t)(ISACdec_obj->plcstr_obj.A * nLP >> 15);
6630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        wNoisyHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15(
664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).A, (nHP) ) );
665470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
666f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        wPriodicLP = (int16_t)(ISACdec_obj->plcstr_obj.B * pLP >> 15);
6670946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org        wPriodicHP = (int32_t)(WEBRTC_SPL_MUL_16_32_RSFT15(
668470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).B, pHP));
669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
670470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (ISACdec_obj->plcstr_obj).pitchIndex++;
671470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
672470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if((ISACdec_obj->plcstr_obj).pitchIndex ==
673470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           (ISACdec_obj->plcstr_obj).stretchLag)
674470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
675470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchIndex = 0;
676470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).pitchCycles++;
677470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
678470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) )
679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1;
680470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          else
681470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).stretchLag = lag0;
682470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
683470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          (ISACdec_obj->plcstr_obj).stretchLag = (
684470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG
685470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                  )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag;
686470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler(
687470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              (ISACdec_obj->plcstr_obj).lastPitchLP,
688470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
689470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
690470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          LinearResampler((ISACdec_obj->plcstr_obj).prevPitchLP,
691470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                          stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag );
692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
693470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          switch((ISACdec_obj->plcstr_obj).pitchCycles)
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 1:
696470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
697470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
6990946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
7000946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k]* 3 +
7010946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k] )>>2);
702470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
703470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
704470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
705470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 2:
706470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
707470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
708470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
7090946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)((
7100946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP[k] +
7110946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                      (int32_t)stretchPitchLP1[k])>>1);
712470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
713470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
714470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
715470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            case 3:
716470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              {
717470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ )
718470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                {
7190946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                  stretchPitchLP[k] = (int16_t)(
720470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                      (stretchPitchLP[k] +
7210946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                       (int32_t)stretchPitchLP1[k]*3 )>>2);
722470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                }
723470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                break;
724470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              }
725470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
726470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
727470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 )
728470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          {
729470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            myDecayRate += 55; //(myDecayRate>>1);
730470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (ISACdec_obj->plcstr_obj).pitchCycles = 0;
731470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          }
732470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
733470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
734470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* ------ Sum the noisy and periodic signals  ------ */
7356e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org        Vector_Word16_1[i] = WebRtcSpl_AddSatW16(wNoisyLP, wPriodicLP);
7366e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org        Vector_Word32_2[i] = WebRtcSpl_AddSatW32(wNoisyHP, wPriodicHP);
737470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
738470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
739470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
740470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* ----------------- residual signal is reconstructed ------------------ */
741470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
742470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  k = (ISACdec_obj->plcstr_obj).pitchIndex;
743470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* --- Write one pitch cycle for recovery block --- */
744470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
745470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for( i = 0; i < RECOVERY_OVERLAP; i++ )
746470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
747f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker    ISACdec_obj->plcstr_obj.overlapLP[i] = (int16_t)(
748f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker        stretchPitchLP[k] * ISACdec_obj->plcstr_obj.decayCoeffPriodic >> 15);
749470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    k = ( k < ((ISACdec_obj->plcstr_obj).stretchLag - 1) )? (k+1):0;
750470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
751470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
752470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 = (ISACdec_obj->plcstr_obj).stretchLag << 7;
753470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
754470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
755470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* --- Inverse Pitch Filter --- */
756470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2,
757470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                            &ISACdec_obj->pitchfiltstr_obj, pitchLags_Q7, pitchGains_Q12, 4);
758470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
759470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* reduce gain to compensate for pitch enhancer */
760470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* gain = 1.0f - 0.45f * AvgPitchGain; */
761f2822edf611ff187eab61abccd9edb2edac4ba64Bjorn Volcker  tmp32a = ISACdec_obj->plcstr_obj.AvgPitchGain_Q12 * 29;  // Q18
762470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  tmp32b = 262144 - tmp32a;  // Q18
7630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  gainQ13 = (int16_t) (tmp32b >> 5); // Q13
764470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
765470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* perceptual post-filtering (using normalized lattice filter) */
766470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = 0; k < FRAMESAMPLES_HALF; k++)
767bc2bb34419021fb3be4f87eb062cf0a9ed52675abjornv@webrtc.org    Vector_Word32_1[k] = (Vector_Word16_2[k] * gainQ13) << 3;  // Q25
768470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
769470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
770470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_NormLatticeFilterAr(ORDERLO,
771470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0,
772470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1);
773470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
774470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_NormLatticeFilterAr(ORDERHI,
775470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0,
776470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                    Vector_Word32_2, hifilt_coefQ15, gain_lo_hiQ17, 1, Vector_Word16_2);
777470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
778470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* recombine the 2 bands */
779470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
780470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Form the polyphase signals, and compensate for DC offset */
781470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k=0;k<FRAMESAMPLES_HALF;k++)
782470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
783470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Construct a new upper channel signal*/
7840946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp_1 = (int16_t)WebRtcSpl_SatW32ToW16(
7850946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                           ((int32_t)Vector_Word16_1[k]+Vector_Word16_2[k] + 1));
786470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Construct a new lower channel signal*/
7870946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    tmp_2 = (int16_t)WebRtcSpl_SatW32ToW16(
7880946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                           ((int32_t)Vector_Word16_1[k]-Vector_Word16_2[k]));
789470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_1[k] = tmp_1;
790470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    Vector_Word16_2[k] = tmp_2;
791470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
792470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
793470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
794470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1,
795470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                  Vector_Word16_2, signal_out16, &ISACdec_obj->postfiltbankstr_obj);
796470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
797470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  (ISACdec_obj->plcstr_obj).used = PLC_WAS_USED;
798470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  *current_framesamples = 480;
799470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
800470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return len;
801470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
802