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 */
27static const WebRtc_Word16 kLogLagWinQ8[3] = {
28  -594, -256, -7
29};
30
31/* [1 -0.75 0.25] in Q12 */
32static const WebRtc_Word16 kACoefQ12[3] = {
33  4096, -3072, 1024
34};
35
36
37
38static __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
52static __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 */
68static __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
118static 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
162static 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
268void 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
519void 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