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