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