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