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 "modules/audio_coding/codecs/ilbc/enhancer_interface.h" 20 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "modules/audio_coding/codecs/ilbc/constants.h" 25 #include "modules/audio_coding/codecs/ilbc/defines.h" 26 #include "modules/audio_coding/codecs/ilbc/enhancer.h" 27 #include "modules/audio_coding/codecs/ilbc/hp_output.h" 28 #include "modules/audio_coding/codecs/ilbc/xcorr_coef.h" 29 30 31 32 /*----------------------------------------------------------------* 33 * interface for enhancer 34 *---------------------------------------------------------------*/ 35 36 size_t // (o) Estimated lag in end of in[] WebRtcIlbcfix_EnhancerInterface(int16_t * out,const int16_t * in,IlbcDecoder * iLBCdec_inst)37 WebRtcIlbcfix_EnhancerInterface( 38 int16_t* out, // (o) enhanced signal 39 const int16_t* in, // (i) unenhanced signal 40 IlbcDecoder* iLBCdec_inst) { // (i) buffers etc 41 size_t iblock; 42 size_t lag=20, tlag=20; 43 size_t inLen=iLBCdec_inst->blockl+120; 44 int16_t scale, scale1; 45 size_t plc_blockl; 46 int16_t *enh_buf; 47 size_t *enh_period; 48 int32_t tmp1, tmp2, max; 49 size_t new_blocks; 50 int16_t *enh_bufPtr1; 51 size_t i; 52 size_t k; 53 int16_t EnChange; 54 int16_t SqrtEnChange; 55 int16_t inc; 56 int16_t win; 57 int16_t *tmpW16ptr; 58 size_t startPos; 59 int16_t *plc_pred; 60 const int16_t *target, *regressor; 61 int16_t max16; 62 int shifts; 63 int32_t ener; 64 int16_t enerSh; 65 int16_t corrSh; 66 size_t ind; 67 int16_t sh; 68 size_t start, stop; 69 /* Stack based */ 70 int16_t totsh[3]; 71 int16_t downsampled[(BLOCKL_MAX+120)>>1]; /* length 180 */ 72 int32_t corr32[50]; 73 int32_t corrmax[3]; 74 int16_t corr16[3]; 75 int16_t en16[3]; 76 size_t lagmax[3]; 77 78 plc_pred = downsampled; /* Reuse memory since plc_pred[ENH_BLOCKL] and 79 downsampled are non overlapping */ 80 enh_buf=iLBCdec_inst->enh_buf; 81 enh_period=iLBCdec_inst->enh_period; 82 83 /* Copy in the new data into the enhancer buffer */ 84 memmove(enh_buf, &enh_buf[iLBCdec_inst->blockl], 85 (ENH_BUFL - iLBCdec_inst->blockl) * sizeof(*enh_buf)); 86 87 WEBRTC_SPL_MEMCPY_W16(&enh_buf[ENH_BUFL-iLBCdec_inst->blockl], in, 88 iLBCdec_inst->blockl); 89 90 /* Set variables that are dependent on frame size */ 91 if (iLBCdec_inst->mode==30) { 92 plc_blockl=ENH_BLOCKL; 93 new_blocks=3; 94 startPos=320; /* Start position for enhancement 95 (640-new_blocks*ENH_BLOCKL-80) */ 96 } else { 97 plc_blockl=40; 98 new_blocks=2; 99 startPos=440; /* Start position for enhancement 100 (640-new_blocks*ENH_BLOCKL-40) */ 101 } 102 103 /* Update the pitch prediction for each enhancer block, move the old ones */ 104 memmove(enh_period, &enh_period[new_blocks], 105 (ENH_NBLOCKS_TOT - new_blocks) * sizeof(*enh_period)); 106 107 WebRtcSpl_DownsampleFast( 108 enh_buf+ENH_BUFL-inLen, /* Input samples */ 109 inLen + ENH_BUFL_FILTEROVERHEAD, 110 downsampled, 111 inLen / 2, 112 (int16_t*)WebRtcIlbcfix_kLpFiltCoefs, /* Coefficients in Q12 */ 113 FILTERORDER_DS_PLUS1, /* Length of filter (order-1) */ 114 FACTOR_DS, 115 DELAY_DS); 116 117 /* Estimate the pitch in the down sampled domain. */ 118 for(iblock = 0; iblock<new_blocks; iblock++){ 119 120 /* references */ 121 target = downsampled + 60 + iblock * ENH_BLOCKL_HALF; 122 regressor = target - 10; 123 124 /* scaling */ 125 max16 = WebRtcSpl_MaxAbsValueW16(®ressor[-50], ENH_BLOCKL_HALF + 50 - 1); 126 shifts = WebRtcSpl_GetSizeInBits((uint32_t)(max16 * max16)) - 25; 127 shifts = WEBRTC_SPL_MAX(0, shifts); 128 129 /* compute cross correlation */ 130 WebRtcSpl_CrossCorrelation(corr32, target, regressor, ENH_BLOCKL_HALF, 50, 131 shifts, -1); 132 133 /* Find 3 highest correlations that should be compared for the 134 highest (corr*corr)/ener */ 135 136 for (i=0;i<2;i++) { 137 lagmax[i] = WebRtcSpl_MaxIndexW32(corr32, 50); 138 corrmax[i] = corr32[lagmax[i]]; 139 start = WEBRTC_SPL_MAX(2, lagmax[i]) - 2; 140 stop = WEBRTC_SPL_MIN(47, lagmax[i]) + 2; 141 for (k = start; k <= stop; k++) { 142 corr32[k] = 0; 143 } 144 } 145 lagmax[2] = WebRtcSpl_MaxIndexW32(corr32, 50); 146 corrmax[2] = corr32[lagmax[2]]; 147 148 /* Calculate normalized corr^2 and ener */ 149 for (i=0;i<3;i++) { 150 corrSh = 15-WebRtcSpl_GetSizeInBits(corrmax[i]); 151 ener = WebRtcSpl_DotProductWithScale(regressor - lagmax[i], 152 regressor - lagmax[i], 153 ENH_BLOCKL_HALF, shifts); 154 enerSh = 15-WebRtcSpl_GetSizeInBits(ener); 155 corr16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(corrmax[i], corrSh); 156 corr16[i] = (int16_t)((corr16[i] * corr16[i]) >> 16); 157 en16[i] = (int16_t)WEBRTC_SPL_SHIFT_W32(ener, enerSh); 158 totsh[i] = enerSh - 2 * corrSh; 159 } 160 161 /* Compare lagmax[0..3] for the (corr^2)/ener criteria */ 162 ind = 0; 163 for (i=1; i<3; i++) { 164 if (totsh[ind] > totsh[i]) { 165 sh = WEBRTC_SPL_MIN(31, totsh[ind]-totsh[i]); 166 if (corr16[ind] * en16[i] < (corr16[i] * en16[ind]) >> sh) { 167 ind = i; 168 } 169 } else { 170 sh = WEBRTC_SPL_MIN(31, totsh[i]-totsh[ind]); 171 if ((corr16[ind] * en16[i]) >> sh < corr16[i] * en16[ind]) { 172 ind = i; 173 } 174 } 175 } 176 177 lag = lagmax[ind] + 10; 178 179 /* Store the estimated lag in the non-downsampled domain */ 180 enh_period[ENH_NBLOCKS_TOT - new_blocks + iblock] = lag * 8; 181 182 /* Store the estimated lag for backward PLC */ 183 if (iLBCdec_inst->prev_enh_pl==1) { 184 if (!iblock) { 185 tlag = lag * 2; 186 } 187 } else { 188 if (iblock==1) { 189 tlag = lag * 2; 190 } 191 } 192 193 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 // Note that this is not abs-max, so we will take the absolute value below. 208 max16 = WebRtcSpl_MaxAbsElementW16(regressor, plc_blockl + 3 - 1); 209 const int16_t max_target = 210 WebRtcSpl_MaxAbsElementW16(target, plc_blockl + 3 - 1); 211 const int64_t max_val = plc_blockl * abs(max16 * max_target); 212 const int32_t factor = max_val >> 31; 213 shifts = factor == 0 ? 0 : 31 - WebRtcSpl_NormW32(factor); 214 215 /* compute cross correlation */ 216 WebRtcSpl_CrossCorrelation(corr32, target, regressor, plc_blockl, 3, shifts, 217 1); 218 219 /* find lag */ 220 lag=WebRtcSpl_MaxIndexW32(corr32, 3); 221 lag+=tlag-1; 222 223 /* Copy the backward PLC to plc_pred */ 224 225 if (iLBCdec_inst->prev_enh_pl==1) { 226 if (lag>plc_blockl) { 227 WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-plc_blockl], plc_blockl); 228 } else { 229 WEBRTC_SPL_MEMCPY_W16(&plc_pred[plc_blockl-lag], in, lag); 230 WEBRTC_SPL_MEMCPY_W16( 231 plc_pred, &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl+lag], 232 (plc_blockl-lag)); 233 } 234 } else { 235 size_t pos; 236 237 pos = plc_blockl; 238 239 while (lag<pos) { 240 WEBRTC_SPL_MEMCPY_W16(&plc_pred[pos-lag], in, lag); 241 pos = pos - lag; 242 } 243 WEBRTC_SPL_MEMCPY_W16(plc_pred, &in[lag-pos], pos); 244 245 } 246 247 if (iLBCdec_inst->prev_enh_pl==1) { 248 /* limit energy change 249 if energy in backward PLC is more than 4 times higher than the forward 250 PLC, then reduce the energy in the backward PLC vector: 251 sample 1...len-16 set energy of the to 4 times forward PLC 252 sample len-15..len interpolate between 4 times fw PLC and bw PLC energy 253 254 Note: Compared to floating point code there is a slight change, 255 the window is 16 samples long instead of 10 samples to simplify the 256 calculations 257 */ 258 259 max=WebRtcSpl_MaxAbsValueW16( 260 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], plc_blockl); 261 max16=WebRtcSpl_MaxAbsValueW16(plc_pred, plc_blockl); 262 max = WEBRTC_SPL_MAX(max, max16); 263 scale=22-(int16_t)WebRtcSpl_NormW32(max); 264 scale=WEBRTC_SPL_MAX(scale,0); 265 266 tmp2 = WebRtcSpl_DotProductWithScale( 267 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], 268 &enh_buf[ENH_BUFL-iLBCdec_inst->blockl-plc_blockl], 269 plc_blockl, scale); 270 tmp1 = WebRtcSpl_DotProductWithScale(plc_pred, plc_pred, 271 plc_blockl, scale); 272 273 /* Check the energy difference */ 274 if ((tmp1>0)&&((tmp1>>2)>tmp2)) { 275 /* EnChange is now guaranteed to be <0.5 276 Calculate EnChange=tmp2/tmp1 in Q16 277 */ 278 279 scale1=(int16_t)WebRtcSpl_NormW32(tmp1); 280 tmp1=WEBRTC_SPL_SHIFT_W32(tmp1, (scale1-16)); /* using 15 bits */ 281 282 tmp2=WEBRTC_SPL_SHIFT_W32(tmp2, (scale1)); 283 EnChange = (int16_t)WebRtcSpl_DivW32W16(tmp2, 284 (int16_t)tmp1); 285 286 /* Calculate the Sqrt of the energy in Q15 ((14+16)/2) */ 287 SqrtEnChange = (int16_t)WebRtcSpl_SqrtFloor(EnChange << 14); 288 289 290 /* Multiply first part of vector with 2*SqrtEnChange */ 291 WebRtcSpl_ScaleVector(plc_pred, plc_pred, SqrtEnChange, plc_blockl-16, 292 14); 293 294 /* Calculate increase parameter for window part (16 last samples) */ 295 /* (1-2*SqrtEnChange)/16 in Q15 */ 296 inc = 2048 - (SqrtEnChange >> 3); 297 298 win=0; 299 tmpW16ptr=&plc_pred[plc_blockl-16]; 300 301 for (i=16;i>0;i--) { 302 *tmpW16ptr = (int16_t)( 303 (*tmpW16ptr * (SqrtEnChange + (win >> 1))) >> 14); 304 /* multiply by (2.0*SqrtEnChange+win) */ 305 306 win += inc; 307 tmpW16ptr++; 308 } 309 } 310 311 /* Make the linear interpolation between the forward PLC'd data 312 and the backward PLC'd data (from the new frame) 313 */ 314 315 if (plc_blockl==40) { 316 inc=400; /* 1/41 in Q14 */ 317 } else { /* plc_blockl==80 */ 318 inc=202; /* 1/81 in Q14 */ 319 } 320 win=0; 321 enh_bufPtr1=&enh_buf[ENH_BUFL-1-iLBCdec_inst->blockl]; 322 for (i=0; i<plc_blockl; i++) { 323 win+=inc; 324 *enh_bufPtr1 = (int16_t)((*enh_bufPtr1 * win) >> 14); 325 *enh_bufPtr1 += (int16_t)( 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, 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 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, 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 lag); 366 } 367 } 368 369 370 /* Perform enhancement block by block */ 371 372 for (iblock = 0; iblock<new_blocks; iblock++) { 373 WebRtcIlbcfix_Enhancer(out + iblock * ENH_BLOCKL, 374 enh_buf, 375 ENH_BUFL, 376 iblock * ENH_BLOCKL + startPos, 377 enh_period, 378 WebRtcIlbcfix_kEnhPlocs, ENH_NBLOCKS_TOT); 379 } 380 381 return (lag); 382 } 383