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 "pitch_estimator.h"
12
13#include <math.h>
14#include <memory.h>
15#include <string.h>
16#ifdef WEBRTC_ANDROID
17#include <stdlib.h>
18#endif
19
20static const double kInterpolWin[8] = {-0.00067556028640,  0.02184247643159, -0.12203175715679,  0.60086484101160,
21                                       0.60086484101160, -0.12203175715679,  0.02184247643159, -0.00067556028640};
22
23/* interpolation filter */
24__inline static void IntrepolFilter(double *data_ptr, double *intrp)
25{
26  *intrp = kInterpolWin[0] * data_ptr[-3];
27  *intrp += kInterpolWin[1] * data_ptr[-2];
28  *intrp += kInterpolWin[2] * data_ptr[-1];
29  *intrp += kInterpolWin[3] * data_ptr[0];
30  *intrp += kInterpolWin[4] * data_ptr[1];
31  *intrp += kInterpolWin[5] * data_ptr[2];
32  *intrp += kInterpolWin[6] * data_ptr[3];
33  *intrp += kInterpolWin[7] * data_ptr[4];
34}
35
36
37/* 2D parabolic interpolation */
38/* probably some 0.5 factors can be eliminated, and the square-roots can be removed from the Cholesky fact. */
39__inline static void Intrpol2D(double T[3][3], double *x, double *y, double *peak_val)
40{
41  double c, b[2], A[2][2];
42  double t1, t2, d;
43  double delta1, delta2;
44
45
46  // double T[3][3] = {{-1.25, -.25,-.25}, {-.25, .75, .75}, {-.25, .75, .75}};
47  // should result in: delta1 = 0.5;  delta2 = 0.0;  peak_val = 1.0
48
49  c = T[1][1];
50  b[0] = 0.5 * (T[1][2] + T[2][1] - T[0][1] - T[1][0]);
51  b[1] = 0.5 * (T[1][0] + T[2][1] - T[0][1] - T[1][2]);
52  A[0][1] = -0.5 * (T[0][1] + T[2][1] - T[1][0] - T[1][2]);
53  t1 = 0.5 * (T[0][0] + T[2][2]) - c;
54  t2 = 0.5 * (T[2][0] + T[0][2]) - c;
55  d = (T[0][1] + T[1][2] + T[1][0] + T[2][1]) - 4.0 * c - t1 - t2;
56  A[0][0] = -t1 - 0.5 * d;
57  A[1][1] = -t2 - 0.5 * d;
58
59  /* deal with singularities or ill-conditioned cases */
60  if ( (A[0][0] < 1e-7) || ((A[0][0] * A[1][1] - A[0][1] * A[0][1]) < 1e-7) ) {
61    *peak_val = T[1][1];
62    return;
63  }
64
65  /* Cholesky decomposition: replace A by upper-triangular factor */
66  A[0][0] = sqrt(A[0][0]);
67  A[0][1] = A[0][1] / A[0][0];
68  A[1][1] = sqrt(A[1][1] - A[0][1] * A[0][1]);
69
70  /* compute [x; y] = -0.5 * inv(A) * b */
71  t1 = b[0] / A[0][0];
72  t2 = (b[1] - t1 * A[0][1]) / A[1][1];
73  delta2 = t2 / A[1][1];
74  delta1 = 0.5 * (t1 - delta2 * A[0][1]) / A[0][0];
75  delta2 *= 0.5;
76
77  /* limit norm */
78  t1 = delta1 * delta1 + delta2 * delta2;
79  if (t1 > 1.0) {
80    delta1 /= t1;
81    delta2 /= t1;
82  }
83
84  *peak_val = 0.5 * (b[0] * delta1 + b[1] * delta2) + c;
85
86  *x += delta1;
87  *y += delta2;
88}
89
90
91static void PCorr(const double *in, double *outcorr)
92{
93  double sum, ysum, prod;
94  const double *x, *inptr;
95  int k, n;
96
97  //ysum = 1e-6;          /* use this with float (i.s.o. double)! */
98  ysum = 1e-13;
99  sum = 0.0;
100  x = in + PITCH_MAX_LAG/2 + 2;
101  for (n = 0; n < PITCH_CORR_LEN2; n++) {
102    ysum += in[n] * in[n];
103    sum += x[n] * in[n];
104  }
105
106  outcorr += PITCH_LAG_SPAN2 - 1;     /* index of last element in array */
107  *outcorr = sum / sqrt(ysum);
108
109  for (k = 1; k < PITCH_LAG_SPAN2; k++) {
110    ysum -= in[k-1] * in[k-1];
111    ysum += in[PITCH_CORR_LEN2 + k - 1] * in[PITCH_CORR_LEN2 + k - 1];
112    sum = 0.0;
113    inptr = &in[k];
114    prod = x[0] * inptr[0];
115    for (n = 1; n < PITCH_CORR_LEN2; n++) {
116      sum += prod;
117      prod = x[n] * inptr[n];
118    }
119    sum += prod;
120    outcorr--;
121    *outcorr = sum / sqrt(ysum);
122  }
123}
124
125
126void WebRtcIsac_InitializePitch(const double *in,
127                                const double old_lag,
128                                const double old_gain,
129                                PitchAnalysisStruct *State,
130                                double *lags)
131{
132  double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2];
133  double ratio, log_lag, gain_bias;
134  double bias;
135  double corrvec1[PITCH_LAG_SPAN2];
136  double corrvec2[PITCH_LAG_SPAN2];
137  int m, k;
138  // Allocating 10 extra entries at the begining of the CorrSurf
139  double corrSurfBuff[10 + (2*PITCH_BW+3)*(PITCH_LAG_SPAN2+4)];
140  double* CorrSurf[2*PITCH_BW+3];
141  double *CorrSurfPtr1, *CorrSurfPtr2;
142  double LagWin[3] = {0.2, 0.5, 0.98};
143  int ind1, ind2, peaks_ind, peak, max_ind;
144  int peaks[PITCH_MAX_NUM_PEAKS];
145  double adj, gain_tmp;
146  double corr, corr_max;
147  double intrp_a, intrp_b, intrp_c, intrp_d;
148  double peak_vals[PITCH_MAX_NUM_PEAKS];
149  double lags1[PITCH_MAX_NUM_PEAKS];
150  double lags2[PITCH_MAX_NUM_PEAKS];
151  double T[3][3];
152  int row;
153
154  for(k = 0; k < 2*PITCH_BW+3; k++)
155  {
156    CorrSurf[k] = &corrSurfBuff[10 + k * (PITCH_LAG_SPAN2+4)];
157  }
158  /* reset CorrSurf matrix */
159  memset(corrSurfBuff, 0, sizeof(double) * (10 + (2*PITCH_BW+3) * (PITCH_LAG_SPAN2+4)));
160
161  //warnings -DH
162  max_ind = 0;
163  peak = 0;
164
165  /* copy old values from state buffer */
166  memcpy(buf_dec, State->dec_buffer, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2));
167
168  /* decimation; put result after the old values */
169  WebRtcIsac_DecimateAllpass(in, State->decimator_state, PITCH_FRAME_LEN,
170                             &buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]);
171
172  /* low-pass filtering */
173  for (k = PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2; k++)
174    buf_dec[k] += 0.75 * buf_dec[k-1] - 0.25 * buf_dec[k-2];
175
176  /* copy end part back into state buffer */
177  memcpy(State->dec_buffer, buf_dec+PITCH_FRAME_LEN/2, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2));
178
179  /* compute correlation for first and second half of the frame */
180  PCorr(buf_dec, corrvec1);
181  PCorr(buf_dec + PITCH_CORR_STEP2, corrvec2);
182
183  /* bias towards pitch lag of previous frame */
184  log_lag = log(0.5 * old_lag);
185  gain_bias = 4.0 * old_gain * old_gain;
186  if (gain_bias > 0.8) gain_bias = 0.8;
187  for (k = 0; k < PITCH_LAG_SPAN2; k++)
188  {
189    ratio = log((double) (k + (PITCH_MIN_LAG/2-2))) - log_lag;
190    bias = 1.0 + gain_bias * exp(-5.0 * ratio * ratio);
191    corrvec1[k] *= bias;
192  }
193
194  /* taper correlation functions */
195  for (k = 0; k < 3; k++) {
196    gain_tmp = LagWin[k];
197    corrvec1[k] *= gain_tmp;
198    corrvec2[k] *= gain_tmp;
199    corrvec1[PITCH_LAG_SPAN2-1-k] *= gain_tmp;
200    corrvec2[PITCH_LAG_SPAN2-1-k] *= gain_tmp;
201  }
202
203  corr_max = 0.0;
204  /* fill middle row of correlation surface */
205  ind1 = 0;
206  ind2 = 0;
207  CorrSurfPtr1 = &CorrSurf[PITCH_BW][2];
208  for (k = 0; k < PITCH_LAG_SPAN2; k++) {
209    corr = corrvec1[ind1++] + corrvec2[ind2++];
210    CorrSurfPtr1[k] = corr;
211    if (corr > corr_max) {
212      corr_max = corr;  /* update maximum */
213      max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
214    }
215  }
216  /* fill first and last rows of correlation surface */
217  ind1 = 0;
218  ind2 = PITCH_BW;
219  CorrSurfPtr1 = &CorrSurf[0][2];
220  CorrSurfPtr2 = &CorrSurf[2*PITCH_BW][PITCH_BW+2];
221  for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW; k++) {
222    ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
223    adj = 0.2 * ratio * (2.0 - ratio);   /* adjustment factor; inverse parabola as a function of ratio */
224    corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
225    CorrSurfPtr1[k] = corr;
226    if (corr > corr_max) {
227      corr_max = corr;  /* update maximum */
228      max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
229    }
230    corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
231    CorrSurfPtr2[k] = corr;
232    if (corr > corr_max) {
233      corr_max = corr;  /* update maximum */
234      max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
235    }
236  }
237  /* fill second and next to last rows of correlation surface */
238  ind1 = 0;
239  ind2 = PITCH_BW-1;
240  CorrSurfPtr1 = &CorrSurf[1][2];
241  CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-1][PITCH_BW+1];
242  for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+1; k++) {
243    ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
244    adj = 0.9 * ratio * (2.0 - ratio);   /* adjustment factor; inverse parabola as a function of ratio */
245    corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
246    CorrSurfPtr1[k] = corr;
247    if (corr > corr_max) {
248      corr_max = corr;  /* update maximum */
249      max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
250    }
251    corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
252    CorrSurfPtr2[k] = corr;
253    if (corr > corr_max) {
254      corr_max = corr;  /* update maximum */
255      max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
256    }
257  }
258  /* fill remainder of correlation surface */
259  for (m = 2; m < PITCH_BW; m++) {
260    ind1 = 0;
261    ind2 = PITCH_BW - m;         /* always larger than ind1 */
262    CorrSurfPtr1 = &CorrSurf[m][2];
263    CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-m][PITCH_BW+2-m];
264    for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+m; k++) {
265      ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
266      adj = ratio * (2.0 - ratio);    /* adjustment factor; inverse parabola as a function of ratio */
267      corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
268      CorrSurfPtr1[k] = corr;
269      if (corr > corr_max) {
270        corr_max = corr;  /* update maximum */
271        max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
272      }
273      corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
274      CorrSurfPtr2[k] = corr;
275      if (corr > corr_max) {
276        corr_max = corr;  /* update maximum */
277        max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
278      }
279    }
280  }
281
282  /* threshold value to qualify as a peak */
283  corr_max *= 0.6;
284
285  peaks_ind = 0;
286  /* find peaks */
287  for (m = 1; m < PITCH_BW+1; m++) {
288    if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
289    CorrSurfPtr1 = &CorrSurf[m][2];
290    for (k = 2; k < PITCH_LAG_SPAN2-PITCH_BW-2+m; k++) {
291      corr = CorrSurfPtr1[k];
292      if (corr > corr_max) {
293        if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) {
294          if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) {
295            /* found a peak; store index into matrix */
296            peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
297            if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
298          }
299        }
300      }
301    }
302  }
303  for (m = PITCH_BW+1; m < 2*PITCH_BW; m++) {
304    if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
305    CorrSurfPtr1 = &CorrSurf[m][2];
306    for (k = 2+m-PITCH_BW; k < PITCH_LAG_SPAN2-2; k++) {
307      corr = CorrSurfPtr1[k];
308      if (corr > corr_max) {
309        if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) {
310          if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) {
311            /* found a peak; store index into matrix */
312            peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
313            if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
314          }
315        }
316      }
317    }
318  }
319
320  if (peaks_ind > 0) {
321    /* examine each peak */
322    CorrSurfPtr1 = &CorrSurf[0][0];
323    for (k = 0; k < peaks_ind; k++) {
324      peak = peaks[k];
325
326      /* compute four interpolated values around current peak */
327      IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)], &intrp_a);
328      IntrepolFilter(&CorrSurfPtr1[peak - 1            ], &intrp_b);
329      IntrepolFilter(&CorrSurfPtr1[peak                ], &intrp_c);
330      IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)], &intrp_d);
331
332      /* determine maximum of the interpolated values */
333      corr = CorrSurfPtr1[peak];
334      corr_max = intrp_a;
335      if (intrp_b > corr_max) corr_max = intrp_b;
336      if (intrp_c > corr_max) corr_max = intrp_c;
337      if (intrp_d > corr_max) corr_max = intrp_d;
338
339      /* determine where the peak sits and fill a 3x3 matrix around it */
340      row = peak / (PITCH_LAG_SPAN2+4);
341      lags1[k] = (double) ((peak - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4);
342      lags2[k] = (double) (lags1[k] + PITCH_BW - row);
343      if ( corr > corr_max ) {
344        T[0][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
345        T[2][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
346        T[1][1] = corr;
347        T[0][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
348        T[2][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
349        T[1][0] = intrp_a;
350        T[0][1] = intrp_b;
351        T[2][1] = intrp_c;
352        T[1][2] = intrp_d;
353      } else {
354        if (intrp_a == corr_max) {
355          lags1[k] -= 0.5;
356          lags2[k] += 0.5;
357          IntrepolFilter(&CorrSurfPtr1[peak - 2*(PITCH_LAG_SPAN2+5)], &T[0][0]);
358          IntrepolFilter(&CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)], &T[2][0]);
359          T[1][1] = intrp_a;
360          T[0][2] = intrp_b;
361          T[2][2] = intrp_c;
362          T[1][0] = CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)];
363          T[0][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
364          T[2][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
365          T[1][2] = corr;
366        } else if (intrp_b == corr_max) {
367          lags1[k] -= 0.5;
368          lags2[k] -= 0.5;
369          IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+6)], &T[0][0]);
370          T[2][0] = intrp_a;
371          T[1][1] = intrp_b;
372          IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+3)], &T[0][2]);
373          T[2][2] = intrp_d;
374          T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
375          T[0][1] = CorrSurfPtr1[peak - 1];
376          T[2][1] = corr;
377          T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
378        } else if (intrp_c == corr_max) {
379          lags1[k] += 0.5;
380          lags2[k] += 0.5;
381          T[0][0] = intrp_a;
382          IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)], &T[2][0]);
383          T[1][1] = intrp_c;
384          T[0][2] = intrp_d;
385          IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)], &T[2][2]);
386          T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
387          T[0][1] = corr;
388          T[2][1] = CorrSurfPtr1[peak + 1];
389          T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
390        } else {
391          lags1[k] += 0.5;
392          lags2[k] -= 0.5;
393          T[0][0] = intrp_b;
394          T[2][0] = intrp_c;
395          T[1][1] = intrp_d;
396          IntrepolFilter(&CorrSurfPtr1[peak + 2*(PITCH_LAG_SPAN2+4)], &T[0][2]);
397          IntrepolFilter(&CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)], &T[2][2]);
398          T[1][0] = corr;
399          T[0][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
400          T[2][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
401          T[1][2] = CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)];
402        }
403      }
404
405      /* 2D parabolic interpolation gives more accurate lags and peak value */
406      Intrpol2D(T, &lags1[k], &lags2[k], &peak_vals[k]);
407    }
408
409    /* determine the highest peak, after applying a bias towards short lags */
410    corr_max = 0.0;
411    for (k = 0; k < peaks_ind; k++) {
412      corr = peak_vals[k] * pow(PITCH_PEAK_DECAY, log(lags1[k] + lags2[k]));
413      if (corr > corr_max) {
414        corr_max = corr;
415        peak = k;
416      }
417    }
418
419    lags1[peak] *= 2.0;
420    lags2[peak] *= 2.0;
421
422    if (lags1[peak] < (double) PITCH_MIN_LAG) lags1[peak] = (double) PITCH_MIN_LAG;
423    if (lags2[peak] < (double) PITCH_MIN_LAG) lags2[peak] = (double) PITCH_MIN_LAG;
424    if (lags1[peak] > (double) PITCH_MAX_LAG) lags1[peak] = (double) PITCH_MAX_LAG;
425    if (lags2[peak] > (double) PITCH_MAX_LAG) lags2[peak] = (double) PITCH_MAX_LAG;
426
427    /* store lags of highest peak in output array */
428    lags[0] = lags1[peak];
429    lags[1] = lags1[peak];
430    lags[2] = lags2[peak];
431    lags[3] = lags2[peak];
432  }
433  else
434  {
435    row = max_ind / (PITCH_LAG_SPAN2+4);
436    lags1[0] = (double) ((max_ind - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4);
437    lags2[0] = (double) (lags1[0] + PITCH_BW - row);
438
439    if (lags1[0] < (double) PITCH_MIN_LAG) lags1[0] = (double) PITCH_MIN_LAG;
440    if (lags2[0] < (double) PITCH_MIN_LAG) lags2[0] = (double) PITCH_MIN_LAG;
441    if (lags1[0] > (double) PITCH_MAX_LAG) lags1[0] = (double) PITCH_MAX_LAG;
442    if (lags2[0] > (double) PITCH_MAX_LAG) lags2[0] = (double) PITCH_MAX_LAG;
443
444    /* store lags of highest peak in output array */
445    lags[0] = lags1[0];
446    lags[1] = lags1[0];
447    lags[2] = lags2[0];
448    lags[3] = lags2[0];
449  }
450}
451
452
453
454/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order
455 * t = (0:4)';
456 * A = [t.^0, t.^1, t.^2, t.^3, t.^4];
457 * [Q, dummy] = qr(A);
458 * P.Weight = Q * diag([0, .1, .5, 1, 1]) * Q'; */
459static const double kWeight[5][5] = {
460  { 0.29714285714286,  -0.30857142857143,  -0.05714285714286,   0.05142857142857,  0.01714285714286},
461  {-0.30857142857143,   0.67428571428571,  -0.27142857142857,  -0.14571428571429,  0.05142857142857},
462  {-0.05714285714286,  -0.27142857142857,   0.65714285714286,  -0.27142857142857, -0.05714285714286},
463  { 0.05142857142857,  -0.14571428571429,  -0.27142857142857,   0.67428571428571, -0.30857142857143},
464  { 0.01714285714286,   0.05142857142857,  -0.05714285714286,  -0.30857142857143,  0.29714285714286}
465};
466
467
468void WebRtcIsac_PitchAnalysis(const double *in,               /* PITCH_FRAME_LEN samples */
469                              double *out,                    /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
470                              PitchAnalysisStruct *State,
471                              double *lags,
472                              double *gains)
473{
474  double HPin[PITCH_FRAME_LEN];
475  double Weighted[PITCH_FRAME_LEN];
476  double Whitened[PITCH_FRAME_LEN + QLOOKAHEAD];
477  double inbuf[PITCH_FRAME_LEN + QLOOKAHEAD];
478  double out_G[PITCH_FRAME_LEN + QLOOKAHEAD];          // could be removed by using out instead
479  double out_dG[4][PITCH_FRAME_LEN + QLOOKAHEAD];
480  double old_lag, old_gain;
481  double nrg_wht, tmp;
482  double Wnrg, Wfluct, Wgain;
483  double H[4][4];
484  double grad[4];
485  double dG[4];
486  int k, m, n, iter;
487
488  /* high pass filtering using second order pole-zero filter */
489  WebRtcIsac_Highpass(in, HPin, State->hp_state, PITCH_FRAME_LEN);
490
491  /* copy from state into buffer */
492  memcpy(Whitened, State->whitened_buf, sizeof(double) * QLOOKAHEAD);
493
494  /* compute weighted and whitened signals */
495  WebRtcIsac_WeightingFilter(HPin, &Weighted[0], &Whitened[QLOOKAHEAD], &(State->Wghtstr));
496
497  /* copy from buffer into state */
498  memcpy(State->whitened_buf, Whitened+PITCH_FRAME_LEN, sizeof(double) * QLOOKAHEAD);
499
500  old_lag = State->PFstr_wght.oldlagp[0];
501  old_gain = State->PFstr_wght.oldgainp[0];
502
503  /* inital pitch estimate */
504  WebRtcIsac_InitializePitch(Weighted, old_lag, old_gain, State, lags);
505
506
507  /* Iterative optimization of lags - to be done */
508
509  /* compute energy of whitened signal */
510  nrg_wht = 0.0;
511  for (k = 0; k < PITCH_FRAME_LEN + QLOOKAHEAD; k++)
512    nrg_wht += Whitened[k] * Whitened[k];
513
514
515  /* Iterative optimization of gains */
516
517  /* set weights for energy, gain fluctiation, and spectral gain penalty functions */
518  Wnrg = 1.0 / nrg_wht;
519  Wgain = 0.005;
520  Wfluct = 3.0;
521
522  /* set initial gains */
523  for (k = 0; k < 4; k++)
524    gains[k] = PITCH_MAX_GAIN_06;
525
526  /* two iterations should be enough */
527  for (iter = 0; iter < 2; iter++) {
528    /* compute Jacobian of pre-filter output towards gains */
529    WebRtcIsac_PitchfilterPre_gains(Whitened, out_G, out_dG, &(State->PFstr_wght), lags, gains);
530
531    /* gradient and approximate Hessian (lower triangle) for minimizing the filter's output power */
532    for (k = 0; k < 4; k++) {
533      tmp = 0.0;
534      for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++)
535        tmp += out_G[n] * out_dG[k][n];
536      grad[k] = tmp * Wnrg;
537    }
538    for (k = 0; k < 4; k++) {
539      for (m = 0; m <= k; m++) {
540        tmp = 0.0;
541        for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++)
542          tmp += out_dG[m][n] * out_dG[k][n];
543        H[k][m] = tmp * Wnrg;
544      }
545    }
546
547    /* add gradient and Hessian (lower triangle) for dampening fast gain changes */
548    for (k = 0; k < 4; k++) {
549      tmp = kWeight[k+1][0] * old_gain;
550      for (m = 0; m < 4; m++)
551        tmp += kWeight[k+1][m+1] * gains[m];
552      grad[k] += tmp * Wfluct;
553    }
554    for (k = 0; k < 4; k++) {
555      for (m = 0; m <= k; m++) {
556        H[k][m] += kWeight[k+1][m+1] * Wfluct;
557      }
558    }
559
560    /* add gradient and Hessian for dampening gain */
561    for (k = 0; k < 3; k++) {
562      tmp = 1.0 / (1 - gains[k]);
563      grad[k] += tmp * tmp * Wgain;
564      H[k][k] += 2.0 * tmp * (tmp * tmp * Wgain);
565    }
566    tmp = 1.0 / (1 - gains[3]);
567    grad[3] += 1.33 * (tmp * tmp * Wgain);
568    H[3][3] += 2.66 * tmp * (tmp * tmp * Wgain);
569
570
571    /* compute Cholesky factorization of Hessian
572     * by overwritting the upper triangle; scale factors on diagonal
573     * (for non pc-platforms store the inverse of the diagonals seperately to minimize divisions) */
574    H[0][1] = H[1][0] / H[0][0];
575    H[0][2] = H[2][0] / H[0][0];
576    H[0][3] = H[3][0] / H[0][0];
577    H[1][1] -= H[0][0] * H[0][1] * H[0][1];
578    H[1][2] = (H[2][1] - H[0][1] * H[2][0]) / H[1][1];
579    H[1][3] = (H[3][1] - H[0][1] * H[3][0]) / H[1][1];
580    H[2][2] -= H[0][0] * H[0][2] * H[0][2] + H[1][1] * H[1][2] * H[1][2];
581    H[2][3] = (H[3][2] - H[0][2] * H[3][0] - H[1][2] * H[1][1] * H[1][3]) / H[2][2];
582    H[3][3] -= H[0][0] * H[0][3] * H[0][3] + H[1][1] * H[1][3] * H[1][3] + H[2][2] * H[2][3] * H[2][3];
583
584    /* Compute update as  delta_gains = -inv(H) * grad */
585    /* copy and negate */
586    for (k = 0; k < 4; k++)
587      dG[k] = -grad[k];
588    /* back substitution */
589    dG[1] -= dG[0] * H[0][1];
590    dG[2] -= dG[0] * H[0][2] + dG[1] * H[1][2];
591    dG[3] -= dG[0] * H[0][3] + dG[1] * H[1][3] + dG[2] * H[2][3];
592    /* scale */
593    for (k = 0; k < 4; k++)
594      dG[k] /= H[k][k];
595    /* back substitution */
596    dG[2] -= dG[3] * H[2][3];
597    dG[1] -= dG[3] * H[1][3] + dG[2] * H[1][2];
598    dG[0] -= dG[3] * H[0][3] + dG[2] * H[0][2] + dG[1] * H[0][1];
599
600    /* update gains and check range */
601    for (k = 0; k < 4; k++) {
602      gains[k] += dG[k];
603      if (gains[k] > PITCH_MAX_GAIN)
604        gains[k] = PITCH_MAX_GAIN;
605      else if (gains[k] < 0.0)
606        gains[k] = 0.0;
607    }
608  }
609
610  /* update state for next frame */
611  WebRtcIsac_PitchfilterPre(Whitened, out, &(State->PFstr_wght), lags, gains);
612
613  /* concatenate previous input's end and current input */
614  memcpy(inbuf, State->inbuf, sizeof(double) * QLOOKAHEAD);
615  memcpy(inbuf+QLOOKAHEAD, in, sizeof(double) * PITCH_FRAME_LEN);
616
617  /* lookahead pitch filtering for masking analysis */
618  WebRtcIsac_PitchfilterPre_la(inbuf, out, &(State->PFstr), lags, gains);
619
620  /* store last part of input */
621  for (k = 0; k < QLOOKAHEAD; k++)
622    State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN];
623}
624