1/*
2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11/******************************************************************
12
13 iLBC Speech Coder ANSI-C Source Code
14
15 WebRtcIlbcfix_DoThePlc.c
16
17******************************************************************/
18
19#include "defines.h"
20#include "constants.h"
21#include "comp_corr.h"
22#include "bw_expand.h"
23
24/*----------------------------------------------------------------*
25 *  Packet loss concealment routine. Conceals a residual signal
26 *  and LP parameters. If no packet loss, update state.
27 *---------------------------------------------------------------*/
28
29void WebRtcIlbcfix_DoThePlc(
30    int16_t *PLCresidual,  /* (o) concealed residual */
31    int16_t *PLClpc,    /* (o) concealed LP parameters */
32    int16_t PLI,     /* (i) packet loss indicator
33                                                           0 - no PL, 1 = PL */
34    int16_t *decresidual,  /* (i) decoded residual */
35    int16_t *lpc,    /* (i) decoded LPC (only used for no PL) */
36    int16_t inlag,    /* (i) pitch lag */
37    iLBC_Dec_Inst_t *iLBCdec_inst
38    /* (i/o) decoder instance */
39                            ){
40  int16_t i, pick;
41  int32_t cross, ener, cross_comp, ener_comp = 0;
42  int32_t measure, maxMeasure, energy;
43  int16_t max, crossSquareMax, crossSquare;
44  int16_t j, lag, tmp1, tmp2, randlag;
45  int16_t shift1, shift2, shift3, shiftMax;
46  int16_t scale3;
47  int16_t corrLen;
48  int32_t tmpW32, tmp2W32;
49  int16_t use_gain;
50  int16_t tot_gain;
51  int16_t max_perSquare;
52  int16_t scale1, scale2;
53  int16_t totscale;
54  int32_t nom;
55  int16_t denom;
56  int16_t pitchfact;
57  int16_t use_lag;
58  int ind;
59  int16_t randvec[BLOCKL_MAX];
60
61  /* Packet Loss */
62  if (PLI == 1) {
63
64    (*iLBCdec_inst).consPLICount += 1;
65
66    /* if previous frame not lost,
67       determine pitch pred. gain */
68
69    if (iLBCdec_inst->prevPLI != 1) {
70
71      /* Maximum 60 samples are correlated, preserve as high accuracy
72         as possible without getting overflow */
73      max = WebRtcSpl_MaxAbsValueW16((*iLBCdec_inst).prevResidual, (int16_t)iLBCdec_inst->blockl);
74      scale3 = (WebRtcSpl_GetSizeInBits(max)<<1) - 25;
75      if (scale3 < 0) {
76        scale3 = 0;
77      }
78
79      /* Store scale for use when interpolating between the
80       * concealment and the received packet */
81      iLBCdec_inst->prevScale = scale3;
82
83      /* Search around the previous lag +/-3 to find the
84         best pitch period */
85      lag = inlag - 3;
86
87      /* Guard against getting outside the frame */
88      corrLen = WEBRTC_SPL_MIN(60, iLBCdec_inst->blockl-(inlag+3));
89
90      WebRtcIlbcfix_CompCorr( &cross, &ener,
91                              iLBCdec_inst->prevResidual, lag, iLBCdec_inst->blockl, corrLen, scale3);
92
93      /* Normalize and store cross^2 and the number of shifts */
94      shiftMax = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross))-15;
95      crossSquareMax = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(WEBRTC_SPL_SHIFT_W32(cross, -shiftMax),
96                                                                WEBRTC_SPL_SHIFT_W32(cross, -shiftMax), 15);
97
98      for (j=inlag-2;j<=inlag+3;j++) {
99        WebRtcIlbcfix_CompCorr( &cross_comp, &ener_comp,
100                                iLBCdec_inst->prevResidual, j, iLBCdec_inst->blockl, corrLen, scale3);
101
102        /* Use the criteria (corr*corr)/energy to compare if
103           this lag is better or not. To avoid the division,
104           do a cross multiplication */
105        shift1 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(cross_comp))-15;
106        crossSquare = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1),
107                                                               WEBRTC_SPL_SHIFT_W32(cross_comp, -shift1), 15);
108
109        shift2 = WebRtcSpl_GetSizeInBits(ener)-15;
110        measure = WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_SHIFT_W32(ener, -shift2),
111                                       crossSquare);
112
113        shift3 = WebRtcSpl_GetSizeInBits(ener_comp)-15;
114        maxMeasure = WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_SHIFT_W32(ener_comp, -shift3),
115                                          crossSquareMax);
116
117        /* Calculate shift value, so that the two measures can
118           be put in the same Q domain */
119        if(((shiftMax<<1)+shift3) > ((shift1<<1)+shift2)) {
120          tmp1 = WEBRTC_SPL_MIN(31, (shiftMax<<1)+shift3-(shift1<<1)-shift2);
121          tmp2 = 0;
122        } else {
123          tmp1 = 0;
124          tmp2 = WEBRTC_SPL_MIN(31, (shift1<<1)+shift2-(shiftMax<<1)-shift3);
125        }
126
127        if ((measure>>tmp1) > (maxMeasure>>tmp2)) {
128          /* New lag is better => record lag, measure and domain */
129          lag = j;
130          crossSquareMax = crossSquare;
131          cross = cross_comp;
132          shiftMax = shift1;
133          ener = ener_comp;
134        }
135      }
136
137      /* Calculate the periodicity for the lag with the maximum correlation.
138
139         Definition of the periodicity:
140         abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2)))
141
142         Work in the Square domain to simplify the calculations
143         max_perSquare is less than 1 (in Q15)
144      */
145      tmp2W32=WebRtcSpl_DotProductWithScale(&iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen],
146                                            &iLBCdec_inst->prevResidual[iLBCdec_inst->blockl-corrLen],
147                                            corrLen, scale3);
148
149      if ((tmp2W32>0)&&(ener_comp>0)) {
150        /* norm energies to int16_t, compute the product of the energies and
151           use the upper int16_t as the denominator */
152
153        scale1=(int16_t)WebRtcSpl_NormW32(tmp2W32)-16;
154        tmp1=(int16_t)WEBRTC_SPL_SHIFT_W32(tmp2W32, scale1);
155
156        scale2=(int16_t)WebRtcSpl_NormW32(ener)-16;
157        tmp2=(int16_t)WEBRTC_SPL_SHIFT_W32(ener, scale2);
158        denom=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp1, tmp2, 16); /* denom in Q(scale1+scale2-16) */
159
160        /* Square the cross correlation and norm it such that max_perSquare
161           will be in Q15 after the division */
162
163        totscale = scale1+scale2-1;
164        tmp1 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, (totscale>>1));
165        tmp2 = (int16_t)WEBRTC_SPL_SHIFT_W32(cross, totscale-(totscale>>1));
166
167        nom = WEBRTC_SPL_MUL_16_16(tmp1, tmp2);
168        max_perSquare = (int16_t)WebRtcSpl_DivW32W16(nom, denom);
169
170      } else {
171        max_perSquare = 0;
172      }
173    }
174
175    /* previous frame lost, use recorded lag and gain */
176
177    else {
178      lag = iLBCdec_inst->prevLag;
179      max_perSquare = iLBCdec_inst->perSquare;
180    }
181
182    /* Attenuate signal and scale down pitch pred gain if
183       several frames lost consecutively */
184
185    use_gain = 32767;   /* 1.0 in Q15 */
186
187    if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>320) {
188      use_gain = 29491;  /* 0.9 in Q15 */
189    } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>640) {
190      use_gain = 22938;  /* 0.7 in Q15 */
191    } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>960) {
192      use_gain = 16384;  /* 0.5 in Q15 */
193    } else if (iLBCdec_inst->consPLICount*iLBCdec_inst->blockl>1280) {
194      use_gain = 0;   /* 0.0 in Q15 */
195    }
196
197    /* Compute mixing factor of picth repeatition and noise:
198       for max_per>0.7 set periodicity to 1.0
199       0.4<max_per<0.7 set periodicity to (maxper-0.4)/0.7-0.4)
200       max_per<0.4 set periodicity to 0.0
201    */
202
203    if (max_perSquare>7868) { /* periodicity > 0.7  (0.7^4=0.2401 in Q15) */
204      pitchfact = 32767;
205    } else if (max_perSquare>839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */
206      /* find best index and interpolate from that */
207      ind = 5;
208      while ((max_perSquare<WebRtcIlbcfix_kPlcPerSqr[ind])&&(ind>0)) {
209        ind--;
210      }
211      /* pitch fact is approximated by first order */
212      tmpW32 = (int32_t)WebRtcIlbcfix_kPlcPitchFact[ind] +
213          WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIlbcfix_kPlcPfSlope[ind], (max_perSquare-WebRtcIlbcfix_kPlcPerSqr[ind]), 11);
214
215      pitchfact = (int16_t)WEBRTC_SPL_MIN(tmpW32, 32767); /* guard against overflow */
216
217    } else { /* periodicity < 0.4 */
218      pitchfact = 0;
219    }
220
221    /* avoid repetition of same pitch cycle (buzzyness) */
222    use_lag = lag;
223    if (lag<80) {
224      use_lag = 2*lag;
225    }
226
227    /* compute concealed residual */
228    energy = 0;
229
230    for (i=0; i<iLBCdec_inst->blockl; i++) {
231
232      /* noise component -  52 < randlagFIX < 117 */
233      iLBCdec_inst->seed = (int16_t)(WEBRTC_SPL_MUL_16_16(iLBCdec_inst->seed, 31821)+(int32_t)13849);
234      randlag = 53 + (int16_t)(iLBCdec_inst->seed & 63);
235
236      pick = i - randlag;
237
238      if (pick < 0) {
239        randvec[i] = iLBCdec_inst->prevResidual[iLBCdec_inst->blockl+pick];
240      } else {
241        randvec[i] = iLBCdec_inst->prevResidual[pick];
242      }
243
244      /* pitch repeatition component */
245      pick = i - use_lag;
246
247      if (pick < 0) {
248        PLCresidual[i] = iLBCdec_inst->prevResidual[iLBCdec_inst->blockl+pick];
249      } else {
250        PLCresidual[i] = PLCresidual[pick];
251      }
252
253      /* Attinuate total gain for each 10 ms */
254      if (i<80) {
255        tot_gain=use_gain;
256      } else if (i<160) {
257        tot_gain=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(31130, use_gain, 15); /* 0.95*use_gain */
258      } else {
259        tot_gain=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(29491, use_gain, 15); /* 0.9*use_gain */
260      }
261
262
263      /* mix noise and pitch repeatition */
264
265      PLCresidual[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tot_gain,
266                                                                (int16_t)WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16(pitchfact, PLCresidual[i]) +
267                                                                                                       WEBRTC_SPL_MUL_16_16((32767-pitchfact), randvec[i]) + 16384),
268                                                                                                      15),
269                                                                15);
270
271      /* Shifting down the result one step extra to ensure that no overflow
272         will occur */
273      energy += WEBRTC_SPL_MUL_16_16_RSFT(PLCresidual[i],
274                                          PLCresidual[i], (iLBCdec_inst->prevScale+1));
275
276    }
277
278    /* less than 30 dB, use only noise */
279    if (energy < (WEBRTC_SPL_SHIFT_W32(((int32_t)iLBCdec_inst->blockl*900),-(iLBCdec_inst->prevScale+1)))) {
280      energy = 0;
281      for (i=0; i<iLBCdec_inst->blockl; i++) {
282        PLCresidual[i] = randvec[i];
283      }
284    }
285
286    /* use the old LPC */
287    WEBRTC_SPL_MEMCPY_W16(PLClpc, (*iLBCdec_inst).prevLpc, LPC_FILTERORDER+1);
288
289    /* Update state in case there are multiple frame losses */
290    iLBCdec_inst->prevLag = lag;
291    iLBCdec_inst->perSquare = max_perSquare;
292  }
293
294  /* no packet loss, copy input */
295
296  else {
297    WEBRTC_SPL_MEMCPY_W16(PLCresidual, decresidual, iLBCdec_inst->blockl);
298    WEBRTC_SPL_MEMCPY_W16(PLClpc, lpc, (LPC_FILTERORDER+1));
299    iLBCdec_inst->consPLICount = 0;
300  }
301
302  /* update state */
303  iLBCdec_inst->prevPLI = PLI;
304  WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevLpc, PLClpc, (LPC_FILTERORDER+1));
305  WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->prevResidual, PLCresidual, iLBCdec_inst->blockl);
306
307  return;
308}
309