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 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 */ 37 ){ 38 int iblock; 39 int lag=20, tlag=20; 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; 44 int16_t *enh_bufPtr1; 45 int i, k; 46 int16_t EnChange; 47 int16_t SqrtEnChange; 48 int16_t inc; 49 int16_t win; 50 int16_t *tmpW16ptr; 51 int16_t startPos; 52 int16_t *plc_pred; 53 int16_t *target, *regressor; 54 int16_t max16; 55 int shifts; 56 int32_t ener; 57 int16_t enerSh; 58 int16_t corrSh; 59 int16_t ind, sh; 60 int16_t start, stop; 61 /* Stack based */ 62 int16_t totsh[3]; 63 int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */ 64 int32_t corr32[50]; 65 int32_t corrmax[3]; 66 int16_t corr16[3]; 67 int16_t en16[3]; 68 int16_t lagmax[3]; 69 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; 74 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)); 78 79 WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in, 80 iLBCdec_inst->blockl); 81 82 /* Set variables that are dependent on frame size */ 83 if (iLBCdec_inst->mode==30) { 84 plc_blockl=ENH_BLOCKL; 85 new_blocks=3; 86 startPos=320; /* Start position for enhancement 87 (640-new_blocks*ENH_BLOCKL-80) */ 88 } else { 89 plc_blockl=40; 90 new_blocks=2; 91 startPos=440; /* Start position for enhancement 92 (640-new_blocks*ENH_BLOCKL-40) */ 93 } 94 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)); 98 99 k=WebRtcSpl_DownsampleFast( 100 enh_buf+ENH_BUFL-inLen, /* Input samples */ 101 (int16_t)(inLen+ENH_BUFL_FILTEROVERHEAD), 102 downsampled, 103 (int16_t)WEBRTC_SPL_RSHIFT_W16(inLen, 1), 104 (int16_t*)WebRtcIlbcfix_kLpFiltCoefs, /* Coefficients in Q12 */ 105 FILTERORDER_DS_PLUS1, /* Length of filter (order-1) */ 106 FACTOR_DS, 107 DELAY_DS); 108 109 /* Estimate the pitch in the down sampled domain. */ 110 for(iblock = 0; iblock<new_blocks; iblock++){ 111 112 /* references */ 113 i=60+WEBRTC_SPL_MUL_16_16(iblock,ENH_BLOCKL_HALF); 114 target=downsampled+i; 115 regressor=downsampled+i-10; 116 117 /* scaling */ 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); 122 123 /* compute cross correlation */ 124 WebRtcSpl_CrossCorrelation(corr32, target, regressor, 125 ENH_BLOCKL_HALF, 50, (int16_t)shifts, -1); 126 127 /* Find 3 highest correlations that should be compared for the 128 highest (corr*corr)/ener */ 129 130 for (i=0;i<2;i++) { 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++) { 138 corr32[k] = 0; 139 } 140 } 141 lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50); 142 corrmax[2] = corr32[lagmax[2]]; 143 144 /* Calculate normalized corr^2 and ener */ 145 for (i=0;i<3;i++) { 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], 153 corr16[i], 16); 154 en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh); 155 totsh[i] = enerSh - WEBRTC_SPL_LSHIFT_W32(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 ( WEBRTC_SPL_MUL_16_16(corr16[ind], en16[i]) < 164 WEBRTC_SPL_MUL_16_16_RSFT(corr16[i], en16[ind], sh)) { 165 ind = i; 166 } 167 } else { 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])) { 171 ind = i; 172 } 173 } 174 } 175 176 lag = lagmax[ind] + 10; 177 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); 181 182 /* Store the estimated lag for backward PLC */ 183 if (iLBCdec_inst->prev_enh_pl==1) { 184 if (!iblock) { 185 tlag = WEBRTC_SPL_MUL_16_16(lag, 2); 186 } 187 } else { 188 if (iblock==1) { 189 tlag = WEBRTC_SPL_MUL_16_16(lag, 2); 190 } 191 } 192 193 lag = WEBRTC_SPL_MUL_16_16(lag, 2); 194 } 195 196 if ((iLBCdec_inst->prev_enh_pl==1)||(iLBCdec_inst->prev_enh_pl==2)) { 197 198 /* Calculate the best lag of the new frame 199 This is used to interpolate backwards and mix with the PLC'd data 200 */ 201 202 /* references */ 203 target=in; 204 regressor=in+tlag-1; 205 206 /* scaling */ 207 max16=WebRtcSpl_MaxAbsValueW16(regressor, (int16_t)(plc_blockl+3-1)); 208 if (max16>5000) 209 shifts=2; 210 else 211 shifts=0; 212 213 /* compute cross correlation */ 214 WebRtcSpl_CrossCorrelation(corr32, target, regressor, 215 plc_blockl, 3, (int16_t)shifts, 1); 216 217 /* find lag */ 218 lag=WebRtcSpl_MaxIndexW32(corr32, 3); 219 lag+=tlag-1; 220 221 /* Copy the backward PLC to plc_pred */ 222 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); 226 } else { 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], 230 (plc_blockl-lag)); 231 } 232 } else { 233 int pos; 234 235 pos = plc_blockl; 236 237 while (lag<pos) { 238 WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag); 239 pos = pos - lag; 240 } 241 WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos); 242 243 } 244 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 251 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 254 calculations 255 */ 256 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); 263 264 tmp2 = WebRtcSpl_DotProductWithScale( 265 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], 266 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], 267 plc_blockl, scale); 268 tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred, 269 plc_blockl, scale); 270 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 275 */ 276 277 scale1=(int16_t)WebRtcSpl_NormW32(tmp1); 278 tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */ 279 280 tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1)); 281 EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2, 282 (int16_t)tmp1); 283 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)); 287 288 289 /* Multiply first part of vector with 2*SqrtEnChange */ 290 WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange, 291 (int16_t)(plc_blockl-16), 14); 292 293 /* Calculate increase parameter for window part (16 last samples) */ 294 /* (1-2*SqrtEnChange)/16 in Q15 */ 295 inc=(2048-WEBRTC_SPL_RSHIFT_W16(SqrtEnChange, 3)); 296 297 win=0; 298 tmpW16ptr=&plc_pred[plc_blockl-16]; 299 300 for (i=16;i>0;i--) { 301 (*tmpW16ptr)=(int16_t)WEBRTC_SPL_MUL_16_16_RSFT( 302 (*tmpW16ptr), (SqrtEnChange+(win>>1)), 14); 303 /* multiply by (2.0*SqrtEnChange+win) */ 304 305 win += inc; 306 tmpW16ptr++; 307 } 308 } 309 310 /* Make the linear interpolation between the forward PLC'd data 311 and the backward PLC'd data (from the new frame) 312 */ 313 314 if (plc_blockl==40) { 315 inc=400; /* 1/41 in Q14 */ 316 } else { /* plc_blockl==80 */ 317 inc=202; /* 1/81 in Q14 */ 318 } 319 win=0; 320 enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl]; 321 for (i=0; i<plc_blockl; i++) { 322 win+=inc; 323 *enh_bufPtr1 = 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); 327 enh_bufPtr1--; 328 } 329 } else { 330 int16_t *synt = &downsampled[LPC_FILTERORDER]; 331 332 enh_bufPtr1=&enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl]; 333 WEBRTC_SPL_MEMCPY_W16(enh_bufPtr1, plc_pred, plc_blockl); 334 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); 339 340 /* Initialize filter memory by filtering through 2 lags */ 341 WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], iLBCdec_inst->syntMem, 342 LPC_FILTERORDER); 343 WebRtcSpl_FilterARFastQ12( 344 enh_bufPtr1, 345 synt, 346 &iLBCdec_inst->old_syntdenum[ 347 (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)], 348 LPC_FILTERORDER+1, (int16_t)lag); 349 350 WEBRTC_SPL_MEMCPY_W16(&synt[-LPC_FILTERORDER], &synt[lag-LPC_FILTERORDER], 351 LPC_FILTERORDER); 352 WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs, 353 iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx, 354 (int16_t)lag); 355 WebRtcSpl_FilterARFastQ12( 356 enh_bufPtr1, synt, 357 &iLBCdec_inst->old_syntdenum[ 358 (iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1)], 359 LPC_FILTERORDER+1, (int16_t)lag); 360 361 WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &synt[lag-LPC_FILTERORDER], 362 LPC_FILTERORDER); 363 WebRtcIlbcfix_HpOutput(synt, (int16_t*)WebRtcIlbcfix_kHpOutCoefs, 364 iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx, 365 (int16_t)lag); 366 } 367 } 368 369 370 /* Perform enhancement block by block */ 371 372 for (iblock = 0; iblock<new_blocks; iblock++) { 373 WebRtcIlbcfix_Enhancer(out+WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL), 374 enh_buf, 375 ENH_BUFL, 376 (int16_t)(WEBRTC_SPL_MUL_16_16(iblock, ENH_BLOCKL)+startPos), 377 enh_period, 378 (int16_t*)WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT); 379 } 380 381 return (lag); 382 } 383