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(®ressor[-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(®ressor[-lagmax[i]],
147 ®ressor[-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