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(®ressor[-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