Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_coding / codecs / ilbc / enhancer_interface.c
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
33 int 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 }