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_EnhancerInterface.c
16
17******************************************************************/
18
19#include <string.h>
20
21#include "defines.h"
22#include "constants.h"
23#include "xcorr_coef.h"
24#include "enhancer.h"
25#include "hp_output.h"
26
27
28
29/*----------------------------------------------------------------*
30 * interface for enhancer
31 *---------------------------------------------------------------*/
32
33int WebRtcIlbcfix_EnhancerInterface( /* (o) Estimated lag in end of in[] */
34    int16_t *out,     /* (o) enhanced signal */
35    int16_t *in,      /* (i) unenhanced signal */
36    iLBC_Dec_Inst_t *iLBCdec_inst /* (i) buffers etc */
37                                        ){
38  int iblock;
39  int lag=20, tlag=20;
40  int inLen=iLBCdec_inst->blockl+120;
41  int16_t scale, scale1, plc_blockl;
42  int16_t *enh_buf, *enh_period;
43  int32_t tmp1, tmp2, max, new_blocks;
44  int16_t *enh_bufPtr1;
45  int i, k;
46  int16_t EnChange;
47  int16_t SqrtEnChange;
48  int16_t inc;
49  int16_t win;
50  int16_t *tmpW16ptr;
51  int16_t startPos;
52  int16_t *plc_pred;
53  int16_t *target, *regressor;
54  int16_t max16;
55  int shifts;
56  int32_t ener;
57  int16_t enerSh;
58  int16_t corrSh;
59  int16_t ind, sh;
60  int16_t start, stop;
61  /* Stack based */
62  int16_t totsh[3];
63  int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */
64  int32_t corr32[50];
65  int32_t corrmax[3];
66  int16_t corr16[3];
67  int16_t en16[3];
68  int16_t lagmax[3];
69
70  plc_pred = downsampled; /* Reuse memory since plc_pred[ENH_BLOCKL] and
71                              downsampled are non overlapping */
72  enh_buf=iLBCdec_inst->enh_buf;
73  enh_period=iLBCdec_inst->enh_period;
74
75  /* Copy in the new data into the enhancer buffer */
76  memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl],
77          (ENH_BUFL - iLBCdec_inst->blockl) * sizeof(*enh_buf));
78
79  WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in,
80                        iLBCdec_inst->blockl);
81
82  /* Set variables that are dependent on frame size */
83  if (iLBCdec_inst->mode==30) {
84    plc_blockl=ENH_BLOCKL;
85    new_blocks=3;
86    startPos=320;  /* Start position for enhancement
87                     (640-new_blocks*ENH_BLOCKL-80) */
88  } else {
89    plc_blockl=40;
90    new_blocks=2;
91    startPos=440;  /* Start position for enhancement
92                    (640-new_blocks*ENH_BLOCKL-40) */
93  }
94
95  /* Update the pitch prediction for each enhancer block, move the old ones */
96  memmove(enh_period, &enh_period[new_blocks],
97          (ENH_NBLOCKS_TOT - new_blocks) * sizeof(*enh_period));
98
99  k=WebRtcSpl_DownsampleFast(
100      enh_buf+ENH_BUFL-inLen,    /* Input samples */
101      (int16_t)(inLen+ENH_BUFL_FILTEROVERHEAD),
102      downsampled,
103      (int16_t)WEBRTC_SPL_RSHIFT_W16(inLen, 1),
104      (int16_t*)WebRtcIlbcfix_kLpFiltCoefs,  /* Coefficients in Q12 */
105      FILTERORDER_DS_PLUS1,    /* Length of filter (order-1) */
106      FACTOR_DS,
107      DELAY_DS);
108
109  /* Estimate the pitch in the down sampled domain. */
110  for(iblock = 0; iblock<new_blocks; iblock++){
111
112    /* references */
113    i=60+WEBRTC_SPL_MUL_16_16(iblock,ENH_BLOCKL_HALF);
114    target=downsampled+i;
115    regressor=downsampled+i-10;
116
117    /* scaling */
118    max16=WebRtcSpl_MaxAbsValueW16(&regressor[-50],
119                                   (int16_t)(ENH_BLOCKL_HALF+50-1));
120    shifts = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(max16, max16)) - 25;
121    shifts = WEBRTC_SPL_MAX(0, shifts);
122
123    /* compute cross correlation */
124    WebRtcSpl_CrossCorrelation(corr32, target, regressor,
125                               ENH_BLOCKL_HALF, 50, (int16_t)shifts, -1);
126
127    /* Find 3 highest correlations that should be compared for the
128       highest (corr*corr)/ener */
129
130    for (i=0;i<2;i++) {
131      lagmax[i] = WebRtcSpl_MaxIndexW32(corr32, 50);
132      corrmax[i] = corr32[lagmax[i]];
133      start = lagmax[i] - 2;
134      stop = lagmax[i] + 2;
135      start = WEBRTC_SPL_MAX(0,  start);
136      stop  = WEBRTC_SPL_MIN(49, stop);
137      for (k=start; k<=stop; k++) {
138        corr32[k] = 0;
139      }
140    }
141    lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50);
142    corrmax[2] = corr32[lagmax[2]];
143
144    /* Calculate normalized corr^2 and ener */
145    for (i=0;i<3;i++) {
146      corrSh = 15-WebRtcSpl_GetSizeInBits(corrmax[i]);
147      ener = WebRtcSpl_DotProductWithScale(&regressor[-lagmax[i]],
148                                           &regressor[-lagmax[i]],
149                                           ENH_BLOCKL_HALF, shifts);
150      enerSh = 15-WebRtcSpl_GetSizeInBits(ener);
151      corr16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(corrmax[i], corrSh);
152      corr16[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(corr16[i],
153                                                           corr16[i], 16);
154      en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh);
155      totsh[i] = enerSh - WEBRTC_SPL_LSHIFT_W32(corrSh, 1);
156    }
157
158    /* Compare lagmax[0..3] for the (corr^2)/ener criteria */
159    ind = 0;
160    for (i=1; i<3; i++) {
161      if (totsh[ind] > totsh[i]) {
162        sh = WEBRTC_SPL_MIN(31, totsh[ind]-totsh[i]);
163        if ( WEBRTC_SPL_MUL_16_16(corr16[ind], en16[i]) <
164            WEBRTC_SPL_MUL_16_16_RSFT(corr16[i], en16[ind], sh)) {
165          ind = i;
166        }
167      } else {
168        sh = WEBRTC_SPL_MIN(31, totsh[i]-totsh[ind]);
169        if (WEBRTC_SPL_MUL_16_16_RSFT(corr16[ind], en16[i], sh) <
170            WEBRTC_SPL_MUL_16_16(corr16[i], en16[ind])) {
171          ind = i;
172        }
173      }
174    }
175
176    lag = lagmax[ind] + 10;
177
178    /* Store the estimated lag in the non-downsampled domain */
179    enh_period[ENH_NBLOCKS_TOT-new_blocks+iblock] =
180        (int16_t)WEBRTC_SPL_MUL_16_16(lag, 8);
181
182    /* Store the estimated lag for backward PLC */
183    if (iLBCdec_inst->prev_enh_pl==1) {
184      if (!iblock) {
185        tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
186      }
187    } else {
188      if (iblock==1) {
189        tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
190      }
191    }
192
193    lag = WEBRTC_SPL_MUL_16_16(lag, 2);
194  }
195
196  if ((iLBCdec_inst->prev_enh_pl==1)||(iLBCdec_inst->prev_enh_pl==2)) {
197
198    /* Calculate the best lag of the new frame
199       This is used to interpolate backwards and mix with the PLC'd data
200    */
201
202    /* references */
203    target=in;
204    regressor=in+tlag-1;
205
206    /* scaling */
207    max16=WebRtcSpl_MaxAbsValueW16(regressor, (int16_t)(plc_blockl+3-1));
208    if (max16>5000)
209      shifts=2;
210    else
211      shifts=0;
212
213    /* compute cross correlation */
214    WebRtcSpl_CrossCorrelation(corr32, target, regressor,
215                               plc_blockl, 3, (int16_t)shifts, 1);
216
217    /* find lag */
218    lag=WebRtcSpl_MaxIndexW32(corr32, 3);
219    lag+=tlag-1;
220
221    /* Copy the backward PLC to plc_pred */
222
223    if (iLBCdec_inst->prev_enh_pl==1) {
224      if (lag>plc_blockl) {
225        WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-plc_blockl], plc_blockl);
226      } else {
227        WEBRTC_SPL_MEMCPY_W16(&plc_pred[plc_blockl-lag], in, lag);
228        WEBRTC_SPL_MEMCPY_W16(
229            plc_pred, &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl+lag],
230            (plc_blockl-lag));
231      }
232    } else {
233      int pos;
234
235      pos = plc_blockl;
236
237      while (lag<pos) {
238        WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag);
239        pos = pos - lag;
240      }
241      WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos);
242
243    }
244
245    if (iLBCdec_inst->prev_enh_pl==1) {
246      /* limit energy change
247         if energy in backward PLC is more than 4 times higher than the forward
248         PLC, then reduce the energy in the backward PLC vector:
249         sample 1...len-16 set energy of the to 4 times forward PLC
250         sample len-15..len interpolate between 4 times fw PLC and bw PLC energy
251
252         Note: Compared to floating point code there is a slight change,
253         the window is 16 samples long instead of 10 samples to simplify the
254         calculations
255      */
256
257      max=WebRtcSpl_MaxAbsValueW16(
258          &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], plc_blockl);
259      max16=WebRtcSpl_MaxAbsValueW16(plc_pred, plc_blockl);
260      max = WEBRTC_SPL_MAX(max, max16);
261      scale=22-(int16_t)WebRtcSpl_NormW32(max);
262      scale=WEBRTC_SPL_MAX(scale,0);
263
264      tmp2 = WebRtcSpl_DotProductWithScale(
265          &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
266          &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
267          plc_blockl, scale);
268      tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred,
269                                           plc_blockl, scale);
270
271      /* Check the energy difference */
272      if ((tmp1>0)&&((tmp1>>2)>tmp2)) {
273        /* EnChange is now guaranteed to be <0.5
274           Calculate EnChange=tmp2/tmp1 in Q16
275        */
276
277        scale1=(int16_t)WebRtcSpl_NormW32(tmp1);
278        tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */
279
280        tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1));
281        EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2,
282                                                      (int16_t)tmp1);
283
284        /* Calculate the Sqrt of the energy in Q15 ((14+16)/2) */
285        SqrtEnChange = (int16_t)WebRtcSpl_SqrtFloor(
286            WEBRTC_SPL_LSHIFT_W32((int32_t)EnChange, 14));
287
288
289        /* Multiply first part of vector with 2*SqrtEnChange */
290        WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange,
291                              (int16_t)(plc_blockl-16), 14);
292
293        /* Calculate increase parameter for window part (16 last samples) */
294        /* (1-2*SqrtEnChange)/16 in Q15 */
295        inc=(2048-WEBRTC_SPL_RSHIFT_W16(SqrtEnChange, 3));
296
297        win=0;
298        tmpW16ptr=&plc_pred[plc_blockl-16];
299
300        for (i=16;i>0;i--) {
301          (*tmpW16ptr)=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
302              (*tmpW16ptr), (SqrtEnChange+(win>>1)), 14);
303          /* multiply by (2.0*SqrtEnChange+win) */
304
305          win += inc;
306          tmpW16ptr++;
307        }
308      }
309
310      /* Make the linear interpolation between the forward PLC'd data
311         and the backward PLC'd data (from the new frame)
312      */
313
314      if (plc_blockl==40) {
315        inc=400; /* 1/41 in Q14 */
316      } else { /* plc_blockl==80 */
317        inc=202; /* 1/81 in Q14 */
318      }
319      win=0;
320      enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl];
321      for (i=0; i<plc_blockl; i++) {
322        win+=inc;
323        *enh_bufPtr1 =
324            (int16_t)WEBRTC_SPL_MUL_16_16_RSFT((*enh_bufPtr1), win, 14);
325        *enh_bufPtr1 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
326                (16384-win), plc_pred[plc_blockl-1-i], 14);
327        enh_bufPtr1--;
328      }
329    } else {
330      int16_t *synt = &downsampled[LPC_FILTERORDER];
331
332      enh_bufPtr1=&enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl];
333      WEBRTC_SPL_MEMCPY_W16(enh_bufPtr1, plc_pred, plc_blockl);
334
335      /* Clear fileter memory */
336      WebRtcSpl_MemSetW16(iLBCdec_inst->syntMem, 0, LPC_FILTERORDER);
337      WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemy, 0, 4);
338      WebRtcSpl_MemSetW16(iLBCdec_inst->hpimemx, 0, 2);
339
340      /* Initialize filter memory by filtering through 2 lags */
341      WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], iLBCdec_inst->syntMem,
342                            LPC_FILTERORDER);
343      WebRtcSpl_FilterARFastQ12(
344          enh_bufPtr1,
345          synt,
346          &iLBCdec_inst->old_syntdenum[
347                                       (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
348                                       LPC_FILTERORDER+1, (int16_t)lag);
349
350      WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], &synt[lag-LPC_FILTERORDER],
351                            LPC_FILTERORDER);
352      WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
353                             iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
354                             (int16_t)lag);
355      WebRtcSpl_FilterARFastQ12(
356          enh_bufPtr1, synt,
357          &iLBCdec_inst->old_syntdenum[
358                                       (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
359                                       LPC_FILTERORDER+1, (int16_t)lag);
360
361      WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &synt[lag-LPC_FILTERORDER],
362                            LPC_FILTERORDER);
363      WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
364                             iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
365                             (int16_t)lag);
366    }
367  }
368
369
370  /* Perform enhancement block by block */
371
372  for (iblock = 0; iblock<new_blocks; iblock++) {
373    WebRtcIlbcfix_Enhancer(out+WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL),
374                           enh_buf,
375                           ENH_BUFL,
376                           (int16_t)(WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL)+startPos),
377                           enh_period,
378                           (int16_t*)WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT);
379  }
380
381  return (lag);
382}
383