2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
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.
11 /******************************************************************
13 iLBC Speech Coder ANSI-C Source Code
15 WebRtcIlbcfix_EnhancerInterface.c
17 ******************************************************************/
22 #include "constants.h"
23 #include "xcorr_coef.h"
25 #include "hp_output.h"
29 /*----------------------------------------------------------------*
30 * interface for enhancer
31 *---------------------------------------------------------------*/
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 */
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;
53 int16_t *target, *regressor;
63 int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */
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;
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));
79 WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in,
80 iLBCdec_inst->blockl);
82 /* Set variables that are dependent on frame size */
83 if (iLBCdec_inst->mode==30) {
84 plc_blockl=ENH_BLOCKL;
86 startPos=320; /* Start position for enhancement
87 (640-new_blocks*ENH_BLOCKL-80) */
91 startPos=440; /* Start position for enhancement
92 (640-new_blocks*ENH_BLOCKL-40) */
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));
99 k=WebRtcSpl_DownsampleFast(
100 enh_buf+ENH_BUFL-inLen, /* Input samples */
101 (int16_t)(inLen+ENH_BUFL_FILTEROVERHEAD),
103 (int16_t)(inLen / 2),
104 (int16_t*)WebRtcIlbcfix_kLpFiltCoefs, /* Coefficients in Q12 */
105 FILTERORDER_DS_PLUS1, /* Length of filter (order-1) */
109 /* Estimate the pitch in the down sampled domain. */
110 for(iblock = 0; iblock<new_blocks; iblock++){
113 i=60+WEBRTC_SPL_MUL_16_16(iblock,ENH_BLOCKL_HALF);
114 target=downsampled+i;
115 regressor=downsampled+i-10;
118 max16=WebRtcSpl_MaxAbsValueW16(®ressor[-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);
123 /* compute cross correlation */
124 WebRtcSpl_CrossCorrelation(corr32, target, regressor,
125 ENH_BLOCKL_HALF, 50, (int16_t)shifts, -1);
127 /* Find 3 highest correlations that should be compared for the
128 highest (corr*corr)/ener */
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++) {
141 lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50);
142 corrmax[2] = corr32[lagmax[2]];
144 /* Calculate normalized corr^2 and ener */
146 corrSh = 15-WebRtcSpl_GetSizeInBits(corrmax[i]);
147 ener = WebRtcSpl_DotProductWithScale(®ressor[-lagmax[i]],
148 ®ressor[-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],
154 en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh);
155 totsh[i] = enerSh - WEBRTC_SPL_LSHIFT_W32(corrSh, 1);
158 /* Compare lagmax[0..3] for the (corr^2)/ener criteria */
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)) {
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])) {
176 lag = lagmax[ind] + 10;
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);
182 /* Store the estimated lag for backward PLC */
183 if (iLBCdec_inst->prev_enh_pl==1) {
185 tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
189 tlag = WEBRTC_SPL_MUL_16_16(lag, 2);
193 lag = WEBRTC_SPL_MUL_16_16(lag, 2);
196 if ((iLBCdec_inst->prev_enh_pl==1)||(iLBCdec_inst->prev_enh_pl==2)) {
198 /* Calculate the best lag of the new frame
199 This is used to interpolate backwards and mix with the PLC'd data
207 max16=WebRtcSpl_MaxAbsValueW16(regressor, (int16_t)(plc_blockl+3-1));
213 /* compute cross correlation */
214 WebRtcSpl_CrossCorrelation(corr32, target, regressor,
215 plc_blockl, 3, (int16_t)shifts, 1);
218 lag=WebRtcSpl_MaxIndexW32(corr32, 3);
221 /* Copy the backward PLC to plc_pred */
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);
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],
238 WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag);
241 WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos);
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
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
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);
264 tmp2 = WebRtcSpl_DotProductWithScale(
265 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
266 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl],
268 tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred,
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
277 scale1=(int16_t)WebRtcSpl_NormW32(tmp1);
278 tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */
280 tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1));
281 EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2,
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));
289 /* Multiply first part of vector with 2*SqrtEnChange */
290 WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange,
291 (int16_t)(plc_blockl-16), 14);
293 /* Calculate increase parameter for window part (16 last samples) */
294 /* (1-2*SqrtEnChange)/16 in Q15 */
295 inc = 2048 - (SqrtEnChange >> 3);
298 tmpW16ptr=&plc_pred[plc_blockl-16];
301 (*tmpW16ptr)=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
302 (*tmpW16ptr), (SqrtEnChange+(win>>1)), 14);
303 /* multiply by (2.0*SqrtEnChange+win) */
310 /* Make the linear interpolation between the forward PLC'd data
311 and the backward PLC'd data (from the new frame)
314 if (plc_blockl==40) {
315 inc=400; /* 1/41 in Q14 */
316 } else { /* plc_blockl==80 */
317 inc=202; /* 1/81 in Q14 */
320 enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl];
321 for (i=0; i<plc_blockl; i++) {
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);
330 int16_t *synt = &downsampled[LPC_FILTERORDER];
332 enh_bufPtr1=&enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl];
333 WEBRTC_SPL_MEMCPY_W16(enh_bufPtr1, plc_pred, plc_blockl);
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);
340 /* Initialize filter memory by filtering through 2 lags */
341 WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], iLBCdec_inst->syntMem,
343 WebRtcSpl_FilterARFastQ12(
346 &iLBCdec_inst->old_syntdenum[
347 (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
348 LPC_FILTERORDER+1, (int16_t)lag);
350 WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], &synt[lag-LPC_FILTERORDER],
352 WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
353 iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
355 WebRtcSpl_FilterARFastQ12(
357 &iLBCdec_inst->old_syntdenum[
358 (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)],
359 LPC_FILTERORDER+1, (int16_t)lag);
361 WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &synt[lag-LPC_FILTERORDER],
363 WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
364 iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
370 /* Perform enhancement block by block */
372 for (iblock = 0; iblock<new_blocks; iblock++) {
373 WebRtcIlbcfix_Enhancer(out+WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL),
376 (int16_t)(WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL)+startPos),
378 (int16_t*)WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT);