Coverage Report

Created: 2026-04-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/celt/pitch.c
Line
Count
Source
1
/* Copyright (c) 2007-2008 CSIRO
2
   Copyright (c) 2007-2009 Xiph.Org Foundation
3
   Written by Jean-Marc Valin */
4
/**
5
   @file pitch.c
6
   @brief Pitch analysis
7
 */
8
9
/*
10
   Redistribution and use in source and binary forms, with or without
11
   modification, are permitted provided that the following conditions
12
   are met:
13
14
   - Redistributions of source code must retain the above copyright
15
   notice, this list of conditions and the following disclaimer.
16
17
   - Redistributions in binary form must reproduce the above copyright
18
   notice, this list of conditions and the following disclaimer in the
19
   documentation and/or other materials provided with the distribution.
20
21
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25
   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
*/
33
34
#ifdef HAVE_CONFIG_H
35
#include "config.h"
36
#endif
37
38
#include "pitch.h"
39
#include "os_support.h"
40
#include "modes.h"
41
#include "stack_alloc.h"
42
#include "mathops.h"
43
#include "celt_lpc.h"
44
45
static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
46
                            int max_pitch, int *best_pitch
47
#ifdef FIXED_POINT
48
                            , int yshift, opus_val32 maxcorr
49
#endif
50
                            )
51
42.0k
{
52
42.0k
   int i, j;
53
42.0k
   opus_val32 Syy=1;
54
42.0k
   opus_val16 best_num[2];
55
42.0k
   opus_val32 best_den[2];
56
#ifdef FIXED_POINT
57
   int xshift;
58
59
   xshift = celt_ilog2(maxcorr)-14;
60
#endif
61
62
42.0k
   best_num[0] = -1;
63
42.0k
   best_num[1] = -1;
64
42.0k
   best_den[0] = 0;
65
42.0k
   best_den[1] = 0;
66
42.0k
   best_pitch[0] = 0;
67
42.0k
   best_pitch[1] = 1;
68
20.9M
   for (j=0;j<len;j++)
69
20.9M
      Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
70
9.82M
   for (i=0;i<max_pitch;i++)
71
9.78M
   {
72
9.78M
      if (xcorr[i]>0)
73
1.48M
      {
74
1.48M
         opus_val16 num;
75
1.48M
         opus_val32 xcorr16;
76
1.48M
         xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
77
1.48M
#ifndef FIXED_POINT
78
         /* Considering the range of xcorr16, this should avoid both underflows
79
            and overflows (inf) when squaring xcorr16 */
80
1.48M
         xcorr16 *= 1e-12f;
81
1.48M
#endif
82
1.48M
         num = MULT16_16_Q15(xcorr16,xcorr16);
83
1.48M
         if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
84
382k
         {
85
382k
            if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
86
278k
            {
87
278k
               best_num[1] = best_num[0];
88
278k
               best_den[1] = best_den[0];
89
278k
               best_pitch[1] = best_pitch[0];
90
278k
               best_num[0] = num;
91
278k
               best_den[0] = Syy;
92
278k
               best_pitch[0] = i;
93
278k
            } else {
94
104k
               best_num[1] = num;
95
104k
               best_den[1] = Syy;
96
104k
               best_pitch[1] = i;
97
104k
            }
98
382k
         }
99
1.48M
      }
100
9.78M
      Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
101
9.78M
      Syy = MAX32(1, Syy);
102
9.78M
   }
103
42.0k
}
104
105
static void celt_fir5(opus_val16 *x,
106
         const opus_val16 *num,
107
         int N)
108
21.0k
{
109
21.0k
   int i;
110
21.0k
   opus_val16 num0, num1, num2, num3, num4;
111
21.0k
   opus_val32 mem0, mem1, mem2, mem3, mem4;
112
21.0k
   num0=num[0];
113
21.0k
   num1=num[1];
114
21.0k
   num2=num[2];
115
21.0k
   num3=num[3];
116
21.0k
   num4=num[4];
117
21.0k
   mem0=0;
118
21.0k
   mem1=0;
119
21.0k
   mem2=0;
120
21.0k
   mem3=0;
121
21.0k
   mem4=0;
122
21.5M
   for (i=0;i<N;i++)
123
21.5M
   {
124
21.5M
      opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
125
21.5M
      sum = MAC16_16(sum,num0,mem0);
126
21.5M
      sum = MAC16_16(sum,num1,mem1);
127
21.5M
      sum = MAC16_16(sum,num2,mem2);
128
21.5M
      sum = MAC16_16(sum,num3,mem3);
129
21.5M
      sum = MAC16_16(sum,num4,mem4);
130
21.5M
      mem4 = mem3;
131
21.5M
      mem3 = mem2;
132
21.5M
      mem2 = mem1;
133
21.5M
      mem1 = mem0;
134
21.5M
      mem0 = x[i];
135
21.5M
      x[i] = ROUND16(sum, SIG_SHIFT);
136
21.5M
   }
137
21.0k
}
138
139
140
void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
141
      int len, int C, int factor, int arch)
142
21.0k
{
143
21.0k
   int i;
144
21.0k
   opus_val32 ac[5];
145
21.0k
   opus_val16 tmp=Q15ONE;
146
21.0k
   opus_val16 lpc[4];
147
21.0k
   opus_val16 lpc2[5];
148
21.0k
   opus_val16 c1 = QCONST16(.8f,15);
149
21.0k
   int offset;
150
#ifdef FIXED_POINT
151
   int shift;
152
   opus_val32 maxabs;
153
#endif
154
21.0k
   offset = factor/2;
155
#ifdef FIXED_POINT
156
   maxabs = celt_maxabs32(x[0], len*factor);
157
   if (C==2)
158
   {
159
      opus_val32 maxabs_1 = celt_maxabs32(x[1], len*factor);
160
      maxabs = MAX32(maxabs, maxabs_1);
161
   }
162
   if (maxabs<1)
163
      maxabs=1;
164
   shift = celt_ilog2(maxabs)-10;
165
   if (shift<0)
166
      shift=0;
167
   if (C==2)
168
      shift++;
169
   for (i=1;i<len;i++)
170
      x_lp[i] = SHR32(x[0][(factor*i-offset)], shift+2) + SHR32(x[0][(factor*i+offset)], shift+2) + SHR32(x[0][factor*i], shift+1);
171
   x_lp[0] = SHR32(x[0][offset], shift+2) + SHR32(x[0][0], shift+1);
172
   if (C==2)
173
   {
174
      for (i=1;i<len;i++)
175
         x_lp[i] += SHR32(x[1][(factor*i-offset)], shift+2) + SHR32(x[1][(factor*i+offset)], shift+2) + SHR32(x[1][factor*i], shift+1);
176
      x_lp[0] += SHR32(x[1][offset], shift+2) + SHR32(x[1][0], shift+1);
177
   }
178
#else
179
21.5M
   for (i=1;i<len;i++)
180
21.5M
      x_lp[i] = .25f*x[0][(factor*i-offset)] + .25f*x[0][(factor*i+offset)] + .5f*x[0][factor*i];
181
21.0k
   x_lp[0] = .25f*x[0][offset] + .5f*x[0][0];
182
21.0k
   if (C==2)
183
17.5k
   {
184
17.9M
      for (i=1;i<len;i++)
185
17.9M
         x_lp[i] += .25f*x[1][(factor*i-offset)] + .25f*x[1][(factor*i+offset)] + .5f*x[1][factor*i];
186
17.5k
      x_lp[0] += .25f*x[1][offset] + .5f*x[1][0];
187
17.5k
   }
188
21.0k
#endif
189
21.0k
   _celt_autocorr(x_lp, ac, NULL, 0,
190
21.0k
                  4, len, arch);
191
192
   /* Noise floor -40 dB */
193
#ifdef FIXED_POINT
194
   ac[0] += SHR32(ac[0],13);
195
#else
196
21.0k
   ac[0] *= 1.0001f;
197
21.0k
#endif
198
   /* Lag windowing */
199
105k
   for (i=1;i<=4;i++)
200
84.1k
   {
201
      /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
202
#ifdef FIXED_POINT
203
      ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
204
#else
205
84.1k
      ac[i] -= ac[i]*(.008f*i)*(.008f*i);
206
84.1k
#endif
207
84.1k
   }
208
209
21.0k
   _celt_lpc(lpc, ac, 4);
210
105k
   for (i=0;i<4;i++)
211
84.1k
   {
212
84.1k
      tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
213
84.1k
      lpc[i] = MULT16_16_Q15(lpc[i], tmp);
214
84.1k
   }
215
   /* Add a zero */
216
21.0k
   lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
217
21.0k
   lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
218
21.0k
   lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
219
21.0k
   lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
220
21.0k
   lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
221
21.0k
   celt_fir5(x_lp, lpc2, len);
222
21.0k
}
223
224
/* Pure C implementation. */
225
#ifdef FIXED_POINT
226
opus_val32
227
#else
228
void
229
#endif
230
celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
231
      opus_val32 *xcorr, int len, int max_pitch, int arch)
232
0
{
233
234
#if 0 /* This is a simple version of the pitch correlation that should work
235
         well on DSPs like Blackfin and TI C5x/C6x */
236
   int i, j;
237
#ifdef FIXED_POINT
238
   opus_val32 maxcorr=1;
239
#endif
240
#if !defined(OVERRIDE_PITCH_XCORR)
241
   (void)arch;
242
#endif
243
   for (i=0;i<max_pitch;i++)
244
   {
245
      opus_val32 sum = 0;
246
      for (j=0;j<len;j++)
247
         sum = MAC16_16(sum, _x[j], _y[i+j]);
248
      xcorr[i] = sum;
249
#ifdef FIXED_POINT
250
      maxcorr = MAX32(maxcorr, sum);
251
#endif
252
   }
253
#ifdef FIXED_POINT
254
   return maxcorr;
255
#endif
256
257
#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
258
0
   int i;
259
   /*The EDSP version requires that max_pitch is at least 1, and that _x is
260
      32-bit aligned.
261
     Since it's hard to put asserts in assembly, put them here.*/
262
#ifdef FIXED_POINT
263
   opus_val32 maxcorr=1;
264
#endif
265
0
   celt_assert(max_pitch>0);
266
0
   celt_sig_assert(((size_t)_x&3)==0);
267
0
   for (i=0;i<max_pitch-3;i+=4)
268
0
   {
269
0
      opus_val32 sum[4]={0,0,0,0};
270
#if defined(OPUS_CHECK_ASM) && defined(FIXED_POINT)
271
      {
272
         opus_val32 sum_c[4]={0,0,0,0};
273
         xcorr_kernel_c(_x, _y+i, sum_c, len);
274
#endif
275
0
         xcorr_kernel(_x, _y+i, sum, len, arch);
276
#if defined(OPUS_CHECK_ASM) && defined(FIXED_POINT)
277
         celt_assert(memcmp(sum, sum_c, sizeof(sum)) == 0);
278
      }
279
#endif
280
0
      xcorr[i]=sum[0];
281
0
      xcorr[i+1]=sum[1];
282
0
      xcorr[i+2]=sum[2];
283
0
      xcorr[i+3]=sum[3];
284
#ifdef FIXED_POINT
285
      sum[0] = MAX32(sum[0], sum[1]);
286
      sum[2] = MAX32(sum[2], sum[3]);
287
      sum[0] = MAX32(sum[0], sum[2]);
288
      maxcorr = MAX32(maxcorr, sum[0]);
289
#endif
290
0
   }
291
   /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
292
0
   for (;i<max_pitch;i++)
293
0
   {
294
0
      opus_val32 sum;
295
0
      sum = celt_inner_prod(_x, _y+i, len, arch);
296
0
      xcorr[i] = sum;
297
#ifdef FIXED_POINT
298
      maxcorr = MAX32(maxcorr, sum);
299
#endif
300
0
   }
301
#ifdef FIXED_POINT
302
   return maxcorr;
303
#endif
304
0
#endif
305
0
}
306
307
void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
308
                  int len, int max_pitch, int *pitch, int arch)
309
21.0k
{
310
21.0k
   int i, j;
311
21.0k
   int lag;
312
21.0k
   int best_pitch[2]={0,0};
313
21.0k
   VARDECL(opus_val16, x_lp4);
314
21.0k
   VARDECL(opus_val16, y_lp4);
315
21.0k
   VARDECL(opus_val32, xcorr);
316
#ifdef FIXED_POINT
317
   opus_val32 maxcorr;
318
   opus_val32 xmax, ymax;
319
   int shift=0;
320
#endif
321
21.0k
   int offset;
322
323
21.0k
   SAVE_STACK;
324
325
21.0k
   celt_assert(len>0);
326
21.0k
   celt_assert(max_pitch>0);
327
21.0k
   lag = len+max_pitch;
328
329
21.0k
   ALLOC(x_lp4, len>>2, opus_val16);
330
21.0k
   ALLOC(y_lp4, lag>>2, opus_val16);
331
21.0k
   ALLOC(xcorr, max_pitch>>1, opus_val32);
332
333
   /* Downsample by 2 again */
334
7.00M
   for (j=0;j<len>>2;j++)
335
6.98M
      x_lp4[j] = x_lp[2*j];
336
10.2M
   for (j=0;j<lag>>2;j++)
337
10.2M
      y_lp4[j] = y[2*j];
338
339
#ifdef FIXED_POINT
340
   xmax = celt_maxabs16(x_lp4, len>>2);
341
   ymax = celt_maxabs16(y_lp4, lag>>2);
342
   shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax))) - 14 + celt_ilog2(len)/2;
343
   if (shift>0)
344
   {
345
      for (j=0;j<len>>2;j++)
346
         x_lp4[j] = SHR16(x_lp4[j], shift);
347
      for (j=0;j<lag>>2;j++)
348
         y_lp4[j] = SHR16(y_lp4[j], shift);
349
      /* Use double the shift for a MAC */
350
      shift *= 2;
351
   } else {
352
      shift = 0;
353
   }
354
#endif
355
356
   /* Coarse search with 4x decimation */
357
358
#ifdef FIXED_POINT
359
   maxcorr =
360
#endif
361
21.0k
   celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
362
363
21.0k
   find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
364
#ifdef FIXED_POINT
365
                   , 0, maxcorr
366
#endif
367
21.0k
                   );
368
369
   /* Finer search with 2x decimation */
370
#ifdef FIXED_POINT
371
   maxcorr=1;
372
#endif
373
6.54M
   for (i=0;i<max_pitch>>1;i++)
374
6.52M
   {
375
6.52M
      opus_val32 sum;
376
6.52M
      xcorr[i] = 0;
377
6.52M
      if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
378
6.33M
         continue;
379
#ifdef FIXED_POINT
380
      sum = 0;
381
      for (j=0;j<len>>1;j++)
382
         sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
383
#else
384
186k
      sum = celt_inner_prod(x_lp, y+i, len>>1, arch);
385
186k
#endif
386
186k
      xcorr[i] = MAX32(-1, sum);
387
#ifdef FIXED_POINT
388
      maxcorr = MAX32(maxcorr, sum);
389
#endif
390
186k
   }
391
21.0k
   find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
392
#ifdef FIXED_POINT
393
                   , shift+1, maxcorr
394
#endif
395
21.0k
                   );
396
397
   /* Refine by pseudo-interpolation */
398
21.0k
   if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
399
18.3k
   {
400
18.3k
      opus_val32 a, b, c;
401
18.3k
      a = xcorr[best_pitch[0]-1];
402
18.3k
      b = xcorr[best_pitch[0]];
403
18.3k
      c = xcorr[best_pitch[0]+1];
404
18.3k
      if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
405
2.57k
         offset = 1;
406
15.7k
      else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
407
3.31k
         offset = -1;
408
12.4k
      else
409
12.4k
         offset = 0;
410
18.3k
   } else {
411
2.67k
      offset = 0;
412
2.67k
   }
413
21.0k
   *pitch = 2*best_pitch[0]-offset;
414
415
21.0k
   RESTORE_STACK;
416
21.0k
}
417
418
#ifdef FIXED_POINT
419
static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
420
{
421
   opus_val32 x2y2;
422
   int sx, sy, shift;
423
   opus_val32 g;
424
   opus_val16 den;
425
   if (xy == 0 || xx == 0 || yy == 0)
426
      return 0;
427
   sx = celt_ilog2(xx)-14;
428
   sy = celt_ilog2(yy)-14;
429
   shift = sx + sy;
430
   x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14);
431
   if (shift & 1) {
432
      if (x2y2 < 32768)
433
      {
434
         x2y2 <<= 1;
435
         shift--;
436
      } else {
437
         x2y2 >>= 1;
438
         shift++;
439
      }
440
   }
441
   den = celt_rsqrt_norm(x2y2);
442
   g = MULT16_32_Q15(den, xy);
443
   g = VSHR32(g, (shift>>1)-1);
444
   return EXTRACT16(MAX32(-Q15ONE, MIN32(g, Q15ONE)));
445
}
446
#else
447
static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
448
0
{
449
0
   return xy/celt_sqrt(1+xx*yy);
450
0
}
451
#endif
452
453
static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
454
opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
455
      int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch)
456
0
{
457
0
   int k, i, T, T0;
458
0
   opus_val16 g, g0;
459
0
   opus_val16 pg;
460
0
   opus_val32 xy,xx,yy,xy2;
461
0
   opus_val32 xcorr[3];
462
0
   opus_val32 best_xy, best_yy;
463
0
   int offset;
464
0
   int minperiod0;
465
0
   VARDECL(opus_val32, yy_lookup);
466
0
   SAVE_STACK;
467
468
0
   minperiod0 = minperiod;
469
0
   maxperiod /= 2;
470
0
   minperiod /= 2;
471
0
   *T0_ /= 2;
472
0
   prev_period /= 2;
473
0
   N /= 2;
474
0
   x += maxperiod;
475
0
   if (*T0_>=maxperiod)
476
0
      *T0_=maxperiod-1;
477
478
0
   T = T0 = *T0_;
479
0
   ALLOC(yy_lookup, maxperiod+1, opus_val32);
480
0
   dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch);
481
0
   yy_lookup[0] = xx;
482
0
   yy=xx;
483
0
   for (i=1;i<=maxperiod;i++)
484
0
   {
485
0
      yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
486
0
      yy_lookup[i] = MAX32(0, yy);
487
0
   }
488
0
   yy = yy_lookup[T0];
489
0
   best_xy = xy;
490
0
   best_yy = yy;
491
0
   g = g0 = compute_pitch_gain(xy, xx, yy);
492
   /* Look for any pitch at T/k */
493
0
   for (k=2;k<=15;k++)
494
0
   {
495
0
      int T1, T1b;
496
0
      opus_val16 g1;
497
0
      opus_val16 cont=0;
498
0
      opus_val16 thresh;
499
0
      T1 = celt_udiv(2*T0+k, 2*k);
500
0
      if (T1 < minperiod)
501
0
         break;
502
      /* Look for another strong correlation at T1b */
503
0
      if (k==2)
504
0
      {
505
0
         if (T1+T0>maxperiod)
506
0
            T1b = T0;
507
0
         else
508
0
            T1b = T0+T1;
509
0
      } else
510
0
      {
511
0
         T1b = celt_udiv(2*second_check[k]*T0+k, 2*k);
512
0
      }
513
0
      dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch);
514
0
      xy = HALF32(xy + xy2);
515
0
      yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]);
516
0
      g1 = compute_pitch_gain(xy, xx, yy);
517
0
      if (abs(T1-prev_period)<=1)
518
0
         cont = prev_gain;
519
0
      else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
520
0
         cont = HALF16(prev_gain);
521
0
      else
522
0
         cont = 0;
523
0
      thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
524
      /* Bias against very high pitch (very short period) to avoid false-positives
525
         due to short-term correlation */
526
0
      if (T1<3*minperiod)
527
0
         thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
528
0
      else if (T1<2*minperiod)
529
0
         thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
530
0
      if (g1 > thresh)
531
0
      {
532
0
         best_xy = xy;
533
0
         best_yy = yy;
534
0
         T = T1;
535
0
         g = g1;
536
0
      }
537
0
   }
538
0
   best_xy = MAX32(0, best_xy);
539
0
   if (best_yy <= best_xy)
540
0
      pg = Q15ONE;
541
0
   else
542
0
      pg = SHR32(frac_div32(best_xy,best_yy+1),16);
543
544
0
   for (k=0;k<3;k++)
545
0
      xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch);
546
0
   if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
547
0
      offset = 1;
548
0
   else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
549
0
      offset = -1;
550
0
   else
551
0
      offset = 0;
552
0
   if (pg > g)
553
0
      pg = g;
554
0
   *T0_ = 2*T+offset;
555
556
0
   if (*T0_<minperiod0)
557
0
      *T0_=minperiod0;
558
0
   RESTORE_STACK;
559
0
   return pg;
560
0
}