Home | History | Annotate | Download | only in source
      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