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 "modules/audio_coding/codecs/ilbc/defines.h" 22 #include "modules/audio_coding/codecs/ilbc/constants.h" 23 #include "modules/audio_coding/codecs/ilbc/xcorr_coef.h" 24 #include "modules/audio_coding/codecs/ilbc/enhancer.h" 25 #include "modules/audio_coding/codecs/ilbc/hp_output.h" 26 27 28 29 /*----------------------------------------------------------------* 30 * interface for enhancer 31 *---------------------------------------------------------------*/ 32 33 size_t // (o) Estimated lag in end of in[] WebRtcIlbcfix_EnhancerInterface(int16_t * out,const int16_t * in,IlbcDecoder * iLBCdec_inst)34 WebRtcIlbcfix_EnhancerInterface( 35 int16_t* out, // (o) enhanced signal 36 const int16_t* in, // (i) unenhanced signal 37 IlbcDecoder* iLBCdec_inst) { // (i) buffers etc 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 const 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 - 2 * corrSh; 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