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 #include "webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h" 12 13 #ifdef WEBRTC_ARCH_ARM_NEON 14 #include <arm_neon.h> 15 #endif 16 17 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" 18 #include "webrtc/system_wrappers/interface/compile_assert_c.h" 19 20 /* log2[0.2, 0.5, 0.98] in Q8 */ 21 static const int16_t kLogLagWinQ8[3] = { 22 -594, -256, -7 23 }; 24 25 /* [1 -0.75 0.25] in Q12 */ 26 static const int16_t kACoefQ12[3] = { 27 4096, -3072, 1024 28 }; 29 30 int32_t WebRtcIsacfix_Log2Q8(uint32_t x) { 31 int32_t zeros, lg2; 32 int16_t frac; 33 34 zeros=WebRtcSpl_NormU32(x); 35 frac=(int16_t)WEBRTC_SPL_RSHIFT_W32(((uint32_t)(WEBRTC_SPL_LSHIFT_W32(x, zeros))&0x7FFFFFFF), 23); 36 /* log2(magn(i)) */ 37 38 lg2= (WEBRTC_SPL_LSHIFT_W32((31-zeros), 8)+frac); 39 return lg2; 40 41 } 42 43 static __inline int16_t Exp2Q10(int16_t x) { // Both in and out in Q10 44 45 int16_t tmp16_1, tmp16_2; 46 47 tmp16_2=(int16_t)(0x0400|(x&0x03FF)); 48 tmp16_1=-(int16_t)WEBRTC_SPL_RSHIFT_W16(x,10); 49 if(tmp16_1>0) 50 return (int16_t) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); 51 else 52 return (int16_t) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); 53 54 } 55 56 57 58 /* 1D parabolic interpolation . All input and output values are in Q8 */ 59 static __inline void Intrp1DQ8(int32_t *x, int32_t *fx, int32_t *y, int32_t *fy) { 60 61 int16_t sign1=1, sign2=1; 62 int32_t r32, q32, t32, nom32, den32; 63 int16_t t16, tmp16, tmp16_1; 64 65 if ((fx[0]>0) && (fx[2]>0)) { 66 r32=fx[1]-fx[2]; 67 q32=fx[0]-fx[1]; 68 nom32=q32+r32; 69 den32 = (q32 - r32) * 2; 70 if (nom32<0) 71 sign1=-1; 72 if (den32<0) 73 sign2=-1; 74 75 /* t = (q32+r32)/(2*(q32-r32)) = (fx[0]-fx[1] + fx[1]-fx[2])/(2 * fx[0]-fx[1] - (fx[1]-fx[2]))*/ 76 /* (Signs are removed because WebRtcSpl_DivResultInQ31 can't handle negative numbers) */ 77 /* t in Q31, without signs */ 78 t32 = WebRtcSpl_DivResultInQ31(nom32 * sign1, den32 * sign2); 79 80 t16=(int16_t)WEBRTC_SPL_RSHIFT_W32(t32, 23); /* Q8 */ 81 t16=t16*sign1*sign2; /* t in Q8 with signs */ 82 83 *y = x[0]+t16; /* Q8 */ 84 // *y = x[1]+t16; /* Q8 */ 85 86 /* The following code calculates fy in three steps */ 87 /* fy = 0.5 * t * (t-1) * fx[0] + (1-t*t) * fx[1] + 0.5 * t * (t+1) * fx[2]; */ 88 89 /* Part I: 0.5 * t * (t-1) * fx[0] */ 90 tmp16_1=(int16_t)WEBRTC_SPL_MUL_16_16(t16,t16); /* Q8*Q8=Q16 */ 91 tmp16_1 = WEBRTC_SPL_RSHIFT_W16(tmp16_1,2); /* Q16>>2 = Q14 */ 92 t16 = (int16_t)WEBRTC_SPL_MUL_16_16(t16, 64); /* Q8<<6 = Q14 */ 93 tmp16 = tmp16_1-t16; 94 *fy = WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[0]); /* (Q14 * Q8 >>15)/2 = Q8 */ 95 96 /* Part II: (1-t*t) * fx[1] */ 97 tmp16 = 16384-tmp16_1; /* 1 in Q14 - Q14 */ 98 *fy += WEBRTC_SPL_MUL_16_32_RSFT14(tmp16, fx[1]);/* Q14 * Q8 >> 14 = Q8 */ 99 100 /* Part III: 0.5 * t * (t+1) * fx[2] */ 101 tmp16 = tmp16_1+t16; 102 *fy += WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[2]);/* (Q14 * Q8 >>15)/2 = Q8 */ 103 } else { 104 *y = x[0]; 105 *fy= fx[1]; 106 } 107 } 108 109 110 static void FindFour32(int32_t *in, int16_t length, int16_t *bestind) 111 { 112 int32_t best[4]= {-100, -100, -100, -100}; 113 int16_t k; 114 115 for (k=0; k<length; k++) { 116 if (in[k] > best[3]) { 117 if (in[k] > best[2]) { 118 if (in[k] > best[1]) { 119 if (in[k] > best[0]) { // The Best 120 best[3] = best[2]; 121 bestind[3] = bestind[2]; 122 best[2] = best[1]; 123 bestind[2] = bestind[1]; 124 best[1] = best[0]; 125 bestind[1] = bestind[0]; 126 best[0] = in[k]; 127 bestind[0] = k; 128 } else { // 2nd best 129 best[3] = best[2]; 130 bestind[3] = bestind[2]; 131 best[2] = best[1]; 132 bestind[2] = bestind[1]; 133 best[1] = in[k]; 134 bestind[1] = k; 135 } 136 } else { // 3rd best 137 best[3] = best[2]; 138 bestind[3] = bestind[2]; 139 best[2] = in[k]; 140 bestind[2] = k; 141 } 142 } else { // 4th best 143 best[3] = in[k]; 144 bestind[3] = k; 145 } 146 } 147 } 148 } 149 150 151 152 153 154 extern void WebRtcIsacfix_PCorr2Q32(const int16_t *in, int32_t *logcorQ8); 155 156 157 158 void WebRtcIsacfix_InitialPitch(const int16_t *in, /* Q0 */ 159 PitchAnalysisStruct *State, 160 int16_t *lagsQ7 /* Q7 */ 161 ) 162 { 163 int16_t buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; 164 int32_t *crrvecQ8_1,*crrvecQ8_2; 165 int32_t cv1q[PITCH_LAG_SPAN2+2],cv2q[PITCH_LAG_SPAN2+2], peakvq[PITCH_LAG_SPAN2+2]; 166 int k; 167 int16_t peaks_indq; 168 int16_t peakiq[PITCH_LAG_SPAN2]; 169 int32_t corr; 170 int32_t corr32, corr_max32, corr_max_o32; 171 int16_t npkq; 172 int16_t best4q[4]={0,0,0,0}; 173 int32_t xq[3],yq[1],fyq[1]; 174 int32_t *fxq; 175 int32_t best_lag1q, best_lag2q; 176 int32_t tmp32a,tmp32b,lag32,ratq; 177 int16_t start; 178 int16_t oldgQ12, tmp16a, tmp16b, gain_bias16,tmp16c, tmp16d, bias16; 179 int32_t tmp32c,tmp32d, tmp32e; 180 int16_t old_lagQ; 181 int32_t old_lagQ8; 182 int32_t lagsQ8[4]; 183 184 old_lagQ = State->PFstr_wght.oldlagQ7; // Q7 185 old_lagQ8= WEBRTC_SPL_LSHIFT_W32((int32_t)old_lagQ,1); //Q8 186 187 oldgQ12= State->PFstr_wght.oldgainQ12; 188 189 crrvecQ8_1=&cv1q[1]; 190 crrvecQ8_2=&cv2q[1]; 191 192 193 /* copy old values from state buffer */ 194 memcpy(buf_dec16, State->dec_buffer16, WEBRTC_SPL_MUL_16_16(sizeof(int16_t), (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2))); 195 196 /* decimation; put result after the old values */ 197 WebRtcIsacfix_DecimateAllpass32(in, State->decimator_state32, PITCH_FRAME_LEN, 198 &buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); 199 200 /* low-pass filtering */ 201 start= PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; 202 WebRtcSpl_FilterARFastQ12(&buf_dec16[start],&buf_dec16[start],(int16_t*)kACoefQ12,3, PITCH_FRAME_LEN/2); 203 204 /* copy end part back into state buffer */ 205 for (k = 0; k < (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2); k++) 206 State->dec_buffer16[k] = buf_dec16[k+PITCH_FRAME_LEN/2]; 207 208 209 /* compute correlation for first and second half of the frame */ 210 WebRtcIsacfix_PCorr2Q32(buf_dec16, crrvecQ8_1); 211 WebRtcIsacfix_PCorr2Q32(buf_dec16 + PITCH_CORR_STEP2, crrvecQ8_2); 212 213 214 /* bias towards pitch lag of previous frame */ 215 tmp32a = WebRtcIsacfix_Log2Q8((uint32_t) old_lagQ8) - 2304; 216 // log2(0.5*oldlag) in Q8 217 tmp32b = WEBRTC_SPL_MUL_16_16_RSFT(oldgQ12,oldgQ12, 10); //Q12 & * 4.0; 218 gain_bias16 = (int16_t) tmp32b; //Q12 219 if (gain_bias16 > 3276) gain_bias16 = 3276; // 0.8 in Q12 220 221 222 for (k = 0; k < PITCH_LAG_SPAN2; k++) 223 { 224 if (crrvecQ8_1[k]>0) { 225 tmp32b = WebRtcIsacfix_Log2Q8((uint32_t) (k + (PITCH_MIN_LAG/2-2))); 226 tmp16a = (int16_t) (tmp32b - tmp32a); // Q8 & fabs(ratio)<4 227 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(tmp16a,tmp16a, 6); //Q10 228 tmp16b = (int16_t) tmp32c; // Q10 & <8 229 tmp32d = WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 177 , 8); // mult with ln2 in Q8 230 tmp16c = (int16_t) tmp32d; // Q10 & <4 231 tmp16d = Exp2Q10((int16_t) -tmp16c); //Q10 232 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(gain_bias16,tmp16d,13); // Q10 & * 0.5 233 bias16 = (int16_t) (1024 + tmp32c); // Q10 234 tmp32b = WebRtcIsacfix_Log2Q8((uint32_t)bias16) - 2560; 235 // Q10 in -> Q8 out with 10*2^8 offset 236 crrvecQ8_1[k] += tmp32b ; // -10*2^8 offset 237 } 238 } 239 240 /* taper correlation functions */ 241 for (k = 0; k < 3; k++) { 242 crrvecQ8_1[k] += kLogLagWinQ8[k]; 243 crrvecQ8_2[k] += kLogLagWinQ8[k]; 244 245 crrvecQ8_1[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; 246 crrvecQ8_2[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; 247 } 248 249 250 /* Make zeropadded corr vectors */ 251 cv1q[0]=0; 252 cv2q[0]=0; 253 cv1q[PITCH_LAG_SPAN2+1]=0; 254 cv2q[PITCH_LAG_SPAN2+1]=0; 255 corr_max32 = 0; 256 257 for (k = 1; k <= PITCH_LAG_SPAN2; k++) 258 { 259 260 261 corr32=crrvecQ8_1[k-1]; 262 if (corr32 > corr_max32) 263 corr_max32 = corr32; 264 265 corr32=crrvecQ8_2[k-1]; 266 corr32 += -4; // Compensate for later (log2(0.99)) 267 268 if (corr32 > corr_max32) 269 corr_max32 = corr32; 270 271 } 272 273 /* threshold value to qualify as a peak */ 274 // corr_max32 += -726; // log(0.14)/log(2.0) in Q8 275 corr_max32 += -1000; // log(0.14)/log(2.0) in Q8 276 corr_max_o32 = corr_max32; 277 278 279 /* find peaks in corr1 */ 280 peaks_indq = 0; 281 for (k = 1; k <= PITCH_LAG_SPAN2; k++) 282 { 283 corr32=cv1q[k]; 284 if (corr32>corr_max32) { // Disregard small peaks 285 if ((corr32>=cv1q[k-1]) && (corr32>cv1q[k+1])) { // Peak? 286 peakvq[peaks_indq] = corr32; 287 peakiq[peaks_indq++] = k; 288 } 289 } 290 } 291 292 293 /* find highest interpolated peak */ 294 corr_max32=0; 295 best_lag1q =0; 296 if (peaks_indq > 0) { 297 FindFour32(peakvq, (int16_t) peaks_indq, best4q); 298 npkq = WEBRTC_SPL_MIN(peaks_indq, 4); 299 300 for (k=0;k<npkq;k++) { 301 302 lag32 = peakiq[best4q[k]]; 303 fxq = &cv1q[peakiq[best4q[k]]-1]; 304 xq[0]= lag32; 305 xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); 306 Intrp1DQ8(xq, fxq, yq, fyq); 307 308 tmp32a= WebRtcIsacfix_Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 309 /* Bias towards short lags */ 310 /* log(pow(0.8, log(2.0 * *y )))/log(2.0) */ 311 tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -42, 8); 312 tmp32c= tmp32b + 256; 313 *fyq += tmp32c; 314 if (*fyq > corr_max32) { 315 corr_max32 = *fyq; 316 best_lag1q = *yq; 317 } 318 } 319 tmp32a = best_lag1q - OFFSET_Q8; 320 tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); 321 lagsQ8[0] = tmp32b + PITCH_MIN_LAG_Q8; 322 lagsQ8[1] = lagsQ8[0]; 323 } else { 324 lagsQ8[0] = old_lagQ8; 325 lagsQ8[1] = lagsQ8[0]; 326 } 327 328 /* Bias towards constant pitch */ 329 tmp32a = lagsQ8[0] - PITCH_MIN_LAG_Q8; 330 ratq = WEBRTC_SPL_RSHIFT_W32(tmp32a, 1) + OFFSET_Q8; 331 332 for (k = 1; k <= PITCH_LAG_SPAN2; k++) 333 { 334 tmp32a = WEBRTC_SPL_LSHIFT_W32(k, 7); // 0.5*k Q8 335 tmp32b = (int32_t) (WEBRTC_SPL_LSHIFT_W32(tmp32a, 1)) - ratq; // Q8 336 tmp32c = WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32b, (int16_t) tmp32b, 8); // Q8 337 338 tmp32b = (int32_t)tmp32c + (int32_t)WEBRTC_SPL_RSHIFT_W32(ratq, 1); 339 // (k-r)^2 + 0.5 * r Q8 340 tmp32c = WebRtcIsacfix_Log2Q8((uint32_t)tmp32a) - 2048; 341 // offset 8*2^8 , log2(0.5*k) Q8 342 tmp32d = WebRtcIsacfix_Log2Q8((uint32_t)tmp32b) - 2048; 343 // offset 8*2^8 , log2(0.5*k) Q8 344 tmp32e = tmp32c - tmp32d; 345 346 cv2q[k] += WEBRTC_SPL_RSHIFT_W32(tmp32e, 1); 347 348 } 349 350 /* find peaks in corr2 */ 351 corr_max32 = corr_max_o32; 352 peaks_indq = 0; 353 354 for (k = 1; k <= PITCH_LAG_SPAN2; k++) 355 { 356 corr=cv2q[k]; 357 if (corr>corr_max32) { // Disregard small peaks 358 if ((corr>=cv2q[k-1]) && (corr>cv2q[k+1])) { // Peak? 359 peakvq[peaks_indq] = corr; 360 peakiq[peaks_indq++] = k; 361 } 362 } 363 } 364 365 366 367 /* find highest interpolated peak */ 368 corr_max32 = 0; 369 best_lag2q =0; 370 if (peaks_indq > 0) { 371 372 FindFour32(peakvq, (int16_t) peaks_indq, best4q); 373 npkq = WEBRTC_SPL_MIN(peaks_indq, 4); 374 for (k=0;k<npkq;k++) { 375 376 lag32 = peakiq[best4q[k]]; 377 fxq = &cv2q[peakiq[best4q[k]]-1]; 378 379 xq[0]= lag32; 380 xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); 381 Intrp1DQ8(xq, fxq, yq, fyq); 382 383 /* Bias towards short lags */ 384 /* log(pow(0.8, log(2.0f * *y )))/log(2.0f) */ 385 tmp32a= WebRtcIsacfix_Log2Q8((uint32_t) *yq) - 2048; // offset 8*2^8 386 tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32a, -82, 8); 387 tmp32c= tmp32b + 256; 388 *fyq += tmp32c; 389 if (*fyq > corr_max32) { 390 corr_max32 = *fyq; 391 best_lag2q = *yq; 392 } 393 } 394 395 tmp32a = best_lag2q - OFFSET_Q8; 396 tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); 397 lagsQ8[2] = tmp32b + PITCH_MIN_LAG_Q8; 398 lagsQ8[3] = lagsQ8[2]; 399 } else { 400 lagsQ8[2] = lagsQ8[0]; 401 lagsQ8[3] = lagsQ8[0]; 402 } 403 404 lagsQ7[0]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[0], 1); 405 lagsQ7[1]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[1], 1); 406 lagsQ7[2]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[2], 1); 407 lagsQ7[3]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[3], 1); 408 409 410 } 411 412 413 414 void WebRtcIsacfix_PitchAnalysis(const int16_t *inn, /* PITCH_FRAME_LEN samples */ 415 int16_t *outQ0, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ 416 PitchAnalysisStruct *State, 417 int16_t *PitchLags_Q7, 418 int16_t *PitchGains_Q12) 419 { 420 int16_t inbufQ0[PITCH_FRAME_LEN + QLOOKAHEAD]; 421 int16_t k; 422 423 /* inital pitch estimate */ 424 WebRtcIsacfix_InitialPitch(inn, State, PitchLags_Q7); 425 426 427 /* Calculate gain */ 428 WebRtcIsacfix_PitchFilterGains(inn, &(State->PFstr_wght), PitchLags_Q7, PitchGains_Q12); 429 430 /* concatenate previous input's end and current input */ 431 for (k = 0; k < QLOOKAHEAD; k++) { 432 inbufQ0[k] = State->inbuf[k]; 433 } 434 for (k = 0; k < PITCH_FRAME_LEN; k++) { 435 inbufQ0[k+QLOOKAHEAD] = (int16_t) inn[k]; 436 } 437 438 /* lookahead pitch filtering for masking analysis */ 439 WebRtcIsacfix_PitchFilter(inbufQ0, outQ0, &(State->PFstr), PitchLags_Q7,PitchGains_Q12, 2); 440 441 442 /* store last part of input */ 443 for (k = 0; k < QLOOKAHEAD; k++) { 444 State->inbuf[k] = inbufQ0[k + PITCH_FRAME_LEN]; 445 } 446 } 447