blob: 1ca68bf6d60a756cd9344fa1b46fc85ab79ece4e [file] [log] [blame]
Jean-Marc Valin8b2ff0d2009-10-17 21:40:10 -04001/* Copyright (c) 2007-2008 CSIRO
2 Copyright (c) 2007-2009 Xiph.Org Foundation
3 Written by Jean-Marc Valin */
Jean-Marc Valin14191b32007-11-30 12:15:49 +11004/**
5 @file pitch.c
6 @brief Pitch analysis
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +11007 */
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:
Gregory Maxwell71d39ad2011-07-30 00:00:29 -040013
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +110014 - Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
Gregory Maxwell71d39ad2011-07-30 00:00:29 -040016
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +110017 - 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.
Gregory Maxwell71d39ad2011-07-30 00:00:29 -040020
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +110021 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
Jean-Marc Valincb05e7c2012-04-20 16:40:24 -040024 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +110026 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.
Jean-Marc Valin14191b32007-11-30 12:15:49 +110032*/
33
Jean-Marc Valin02fa9132008-02-20 12:09:29 +110034#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
Jean-Marc Valin14191b32007-11-30 12:15:49 +110037
Jean-Marc Valinf3efa3e2007-12-01 01:55:17 +110038#include "pitch.h"
Jean-Marc Valinf93747c2008-03-05 17:20:30 +110039#include "os_support.h"
Jean-Marc Valinf11d6f42008-04-18 23:13:14 +100040#include "modes.h"
Jean-Marc Valinc7e0b762008-03-16 07:55:29 +110041#include "stack_alloc.h"
Jean-Marc Valin9319e3e2009-11-09 13:51:54 +090042#include "mathops.h"
Jean-Marc Valin2779df72011-10-04 13:26:53 -040043#include "celt_lpc.h"
Jean-Marc Valin294863b2009-11-08 22:29:54 +090044
Gregory Maxwell40f956e2011-09-01 19:42:37 -040045static 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 )
Jean-Marc Valin294863b2009-11-08 22:29:54 +090051{
52 int i, j;
Jean-Marc Valinff5f7222011-07-29 18:59:12 -040053 opus_val32 Syy=1;
54 opus_val16 best_num[2];
55 opus_val32 best_den[2];
Jean-Marc Valin294863b2009-11-08 22:29:54 +090056#ifdef FIXED_POINT
57 int xshift;
58
59 xshift = celt_ilog2(maxcorr)-14;
60#endif
61
62 best_num[0] = -1;
63 best_num[1] = -1;
64 best_den[0] = 0;
65 best_den[1] = 0;
66 best_pitch[0] = 0;
67 best_pitch[1] = 1;
68 for (j=0;j<len;j++)
Jean-Marc Valin178758b2012-04-06 23:32:11 -040069 Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
Jean-Marc Valin294863b2009-11-08 22:29:54 +090070 for (i=0;i<max_pitch;i++)
71 {
Jean-Marc Valin294863b2009-11-08 22:29:54 +090072 if (xcorr[i]>0)
73 {
Jean-Marc Valinff5f7222011-07-29 18:59:12 -040074 opus_val16 num;
75 opus_val32 xcorr16;
Jean-Marc Valin294863b2009-11-08 22:29:54 +090076 xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
Jean-Marc Valin9faea252012-05-08 13:58:57 -040077#ifndef FIXED_POINT
78 /* Considering the range of xcorr16, this should avoid both underflows
79 and overflows (inf) when squaring xcorr16 */
Ralph Giles027ec512012-10-23 10:49:18 -070080 xcorr16 *= 1e-12f;
Jean-Marc Valin9faea252012-05-08 13:58:57 -040081#endif
Jean-Marc Valin294863b2009-11-08 22:29:54 +090082 num = MULT16_16_Q15(xcorr16,xcorr16);
Jean-Marc Valin294863b2009-11-08 22:29:54 +090083 if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
84 {
85 if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
86 {
87 best_num[1] = best_num[0];
88 best_den[1] = best_den[0];
89 best_pitch[1] = best_pitch[0];
90 best_num[0] = num;
91 best_den[0] = Syy;
92 best_pitch[0] = i;
93 } else {
94 best_num[1] = num;
95 best_den[1] = Syy;
96 best_pitch[1] = i;
97 }
98 }
99 }
100 Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
101 Syy = MAX32(1, Syy);
102 }
103}
104
Jean-Marc Valinfbf99982013-05-24 17:18:41 -0400105static void celt_fir5(const opus_val16 *x,
106 const opus_val16 *num,
107 opus_val16 *y,
108 int N,
109 opus_val16 *mem)
110{
111 int i;
112 opus_val16 num0, num1, num2, num3, num4;
113 opus_val32 mem0, mem1, mem2, mem3, mem4;
114 num0=num[0];
115 num1=num[1];
116 num2=num[2];
117 num3=num[3];
118 num4=num[4];
119 mem0=mem[0];
120 mem1=mem[1];
121 mem2=mem[2];
122 mem3=mem[3];
123 mem4=mem[4];
124 for (i=0;i<N;i++)
125 {
126 opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
127 sum = MAC16_16(sum,num0,mem0);
128 sum = MAC16_16(sum,num1,mem1);
129 sum = MAC16_16(sum,num2,mem2);
130 sum = MAC16_16(sum,num3,mem3);
131 sum = MAC16_16(sum,num4,mem4);
132 mem4 = mem3;
133 mem3 = mem2;
134 mem2 = mem1;
135 mem1 = mem0;
136 mem0 = x[i];
137 y[i] = ROUND16(sum, SIG_SHIFT);
138 }
139 mem[0]=mem0;
140 mem[1]=mem1;
141 mem[2]=mem2;
142 mem[3]=mem3;
143 mem[4]=mem4;
144}
145
146
Gregory Maxwellde0b5322012-07-18 12:12:35 -0400147void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500148 int len, int C, int arch)
Jean-Marc Valine465c142009-11-26 00:39:36 -0500149{
150 int i;
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400151 opus_val32 ac[5];
152 opus_val16 tmp=Q15ONE;
Jean-Marc Valinfbf99982013-05-24 17:18:41 -0400153 opus_val16 lpc[4], mem[5]={0,0,0,0,0};
154 opus_val16 lpc2[5];
155 opus_val16 c1 = QCONST16(.8f,15);
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400156#ifdef FIXED_POINT
157 int shift;
Jean-Marc Valin66ac1022012-05-29 17:01:35 -0400158 opus_val32 maxabs = celt_maxabs32(x[0], len);
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400159 if (C==2)
Jean-Marc Valin66ac1022012-05-29 17:01:35 -0400160 {
161 opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
162 maxabs = MAX32(maxabs, maxabs_1);
163 }
164 if (maxabs<1)
165 maxabs=1;
166 shift = celt_ilog2(maxabs)-10;
167 if (shift<0)
168 shift=0;
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400169 if (C==2)
170 shift++;
171#endif
Jean-Marc Valine465c142009-11-26 00:39:36 -0500172 for (i=1;i<len>>1;i++)
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400173 x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
174 x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
Jean-Marc Valine465c142009-11-26 00:39:36 -0500175 if (C==2)
176 {
177 for (i=1;i<len>>1;i++)
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400178 x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
179 x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
Jean-Marc Valine465c142009-11-26 00:39:36 -0500180 }
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400181
182 _celt_autocorr(x_lp, ac, NULL, 0,
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500183 4, len>>1, arch);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400184
185 /* Noise floor -40 dB */
186#ifdef FIXED_POINT
187 ac[0] += SHR32(ac[0],13);
188#else
189 ac[0] *= 1.0001f;
190#endif
191 /* Lag windowing */
192 for (i=1;i<=4;i++)
193 {
194 /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
195#ifdef FIXED_POINT
196 ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
197#else
198 ac[i] -= ac[i]*(.008f*i)*(.008f*i);
199#endif
200 }
201
202 _celt_lpc(lpc, ac, 4);
203 for (i=0;i<4;i++)
204 {
205 tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
206 lpc[i] = MULT16_16_Q15(lpc[i], tmp);
207 }
Jean-Marc Valinfbf99982013-05-24 17:18:41 -0400208 /* Add a zero */
209 lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
210 lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
211 lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
212 lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
213 lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
214 celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
Jean-Marc Valine465c142009-11-26 00:39:36 -0500215}
216
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800217/* Pure C implementation. */
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400218#ifdef FIXED_POINT
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400219opus_val32
220#else
221void
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400222#endif
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800223#if defined(OVERRIDE_PITCH_XCORR)
224celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
225 opus_val32 *xcorr, int len, int max_pitch)
226#else
227celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
228 opus_val32 *xcorr, int len, int max_pitch, int arch)
229#endif
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400230{
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800231
232#if 0 /* This is a simple version of the pitch correlation that should work
233 well on DSPs like Blackfin and TI C5x/C6x */
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400234 int i, j;
235#ifdef FIXED_POINT
Jean-Marc Valin088929d2013-05-24 01:38:06 -0400236 opus_val32 maxcorr=1;
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400237#endif
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800238#if !defined(OVERRIDE_PITCH_XCORR)
239 (void)arch;
240#endif
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400241 for (i=0;i<max_pitch;i++)
242 {
243 opus_val32 sum = 0;
244 for (j=0;j<len;j++)
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800245 sum = MAC16_16(sum, _x[j], _y[i+j]);
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400246 xcorr[i] = sum;
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400247#ifdef FIXED_POINT
248 maxcorr = MAX32(maxcorr, sum);
249#endif
250 }
251#ifdef FIXED_POINT
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400252 return maxcorr;
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400253#endif
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400254
255#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500256 int i;
Timothy B. Terriberry5c02c5f2013-11-26 21:51:39 -0800257 /*The EDSP version requires that max_pitch is at least 1, and that _x is
258 32-bit aligned.
259 Since it's hard to put asserts in assembly, put them here.*/
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400260#ifdef FIXED_POINT
Jean-Marc Valin088929d2013-05-24 01:38:06 -0400261 opus_val32 maxcorr=1;
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400262#endif
Gregory Maxwella65db562014-01-08 11:48:38 -0800263 celt_assert(max_pitch>0);
264 celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
Jean-Marc Valin85a66182013-05-24 03:41:04 -0400265 for (i=0;i<max_pitch-3;i+=4)
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400266 {
Jean-Marc Valin068cbd82013-05-26 20:08:35 -0400267 opus_val32 sum[4]={0,0,0,0};
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800268#if defined(OVERRIDE_PITCH_XCORR)
269 xcorr_kernel_c(_x, _y+i, sum, len);
270#else
xiangmingzhuc95c9a02014-04-30 15:48:07 +0800271 xcorr_kernel(_x, _y+i, sum, len, arch);
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800272#endif
Jean-Marc Valin068cbd82013-05-26 20:08:35 -0400273 xcorr[i]=sum[0];
274 xcorr[i+1]=sum[1];
275 xcorr[i+2]=sum[2];
276 xcorr[i+3]=sum[3];
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400277#ifdef FIXED_POINT
Jean-Marc Valin068cbd82013-05-26 20:08:35 -0400278 sum[0] = MAX32(sum[0], sum[1]);
279 sum[2] = MAX32(sum[2], sum[3]);
280 sum[0] = MAX32(sum[0], sum[2]);
281 maxcorr = MAX32(maxcorr, sum[0]);
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400282#endif
283 }
Jean-Marc Valin85a66182013-05-24 03:41:04 -0400284 /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
285 for (;i<max_pitch;i++)
286 {
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500287 opus_val32 sum;
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800288#if defined(OVERRIDE_PITCH_XCORR)
289 sum = celt_inner_prod_c(_x, _y+i, len);
290#else
xiangmingzhuc95c9a02014-04-30 15:48:07 +0800291 sum = celt_inner_prod(_x, _y+i, len, arch);
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800292#endif
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400293 xcorr[i] = sum;
Jean-Marc Valin85a66182013-05-24 03:41:04 -0400294#ifdef FIXED_POINT
295 maxcorr = MAX32(maxcorr, sum);
296#endif
297 }
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400298#ifdef FIXED_POINT
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400299 return maxcorr;
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400300#endif
Timothy B. Terriberryaad28182014-12-01 10:47:25 -0800301#endif
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400302}
303
Gregory Maxwellde0b5322012-07-18 12:12:35 -0400304void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500305 int len, int max_pitch, int *pitch, int arch)
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900306{
307 int i, j;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400308 int lag;
Gregory Maxwell06d57b22011-08-01 22:02:25 -0400309 int best_pitch[2]={0,0};
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400310 VARDECL(opus_val16, x_lp4);
311 VARDECL(opus_val16, y_lp4);
312 VARDECL(opus_val32, xcorr);
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400313#ifdef FIXED_POINT
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400314 opus_val32 maxcorr;
Jean-Marc Valinb7bd4c22013-05-18 23:33:48 -0400315 opus_val32 xmax, ymax;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900316 int shift=0;
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400317#endif
318 int offset;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900319
Thorvald Natvig065dafd2009-11-25 01:02:42 +0100320 SAVE_STACK;
321
Gregory Maxwell5d5875a2011-10-03 21:07:39 -0400322 celt_assert(len>0);
323 celt_assert(max_pitch>0);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400324 lag = len+max_pitch;
325
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400326 ALLOC(x_lp4, len>>2, opus_val16);
327 ALLOC(y_lp4, lag>>2, opus_val16);
328 ALLOC(xcorr, max_pitch>>1, opus_val32);
Thorvald Natvig065dafd2009-11-25 01:02:42 +0100329
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900330 /* Downsample by 2 again */
331 for (j=0;j<len>>2;j++)
332 x_lp4[j] = x_lp[2*j];
333 for (j=0;j<lag>>2;j++)
334 y_lp4[j] = y[2*j];
335
336#ifdef FIXED_POINT
Jean-Marc Valin66ac1022012-05-29 17:01:35 -0400337 xmax = celt_maxabs16(x_lp4, len>>2);
338 ymax = celt_maxabs16(y_lp4, lag>>2);
Jean-Marc Valinb7bd4c22013-05-18 23:33:48 -0400339 shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900340 if (shift>0)
341 {
342 for (j=0;j<len>>2;j++)
343 x_lp4[j] = SHR16(x_lp4[j], shift);
344 for (j=0;j<lag>>2;j++)
345 y_lp4[j] = SHR16(y_lp4[j], shift);
346 /* Use double the shift for a MAC */
347 shift *= 2;
348 } else {
349 shift = 0;
350 }
351#endif
352
353 /* Coarse search with 4x decimation */
354
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400355#ifdef FIXED_POINT
Jean-Marc Valine8e57a32013-05-25 02:14:25 -0400356 maxcorr =
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400357#endif
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500358 celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
Jean-Marc Valin559fbe82013-05-24 01:09:31 -0400359
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400360 find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
361#ifdef FIXED_POINT
362 , 0, maxcorr
363#endif
364 );
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900365
366 /* Finer search with 2x decimation */
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400367#ifdef FIXED_POINT
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900368 maxcorr=1;
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400369#endif
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900370 for (i=0;i<max_pitch>>1;i++)
371 {
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500372 opus_val32 sum;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900373 xcorr[i] = 0;
374 if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
375 continue;
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500376#ifdef FIXED_POINT
377 sum = 0;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900378 for (j=0;j<len>>1;j++)
379 sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500380#else
Linfeng Zhanga1ae8212016-09-07 15:29:03 -0700381 sum = celt_inner_prod(x_lp, y+i, len>>1, arch);
Jean-Marc Valin57cd8492013-12-09 02:33:42 -0500382#endif
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900383 xcorr[i] = MAX32(-1, sum);
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400384#ifdef FIXED_POINT
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900385 maxcorr = MAX32(maxcorr, sum);
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400386#endif
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900387 }
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400388 find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
389#ifdef FIXED_POINT
Jean-Marc Valin178758b2012-04-06 23:32:11 -0400390 , shift+1, maxcorr
Gregory Maxwell40f956e2011-09-01 19:42:37 -0400391#endif
392 );
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900393
394 /* Refine by pseudo-interpolation */
395 if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
396 {
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400397 opus_val32 a, b, c;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900398 a = xcorr[best_pitch[0]-1];
399 b = xcorr[best_pitch[0]];
400 c = xcorr[best_pitch[0]+1];
401 if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
402 offset = 1;
403 else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
404 offset = -1;
Gregory Maxwell71d39ad2011-07-30 00:00:29 -0400405 else
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900406 offset = 0;
407 } else {
408 offset = 0;
409 }
410 *pitch = 2*best_pitch[0]-offset;
411
Thorvald Natvig065dafd2009-11-25 01:02:42 +0100412 RESTORE_STACK;
Jean-Marc Valin294863b2009-11-08 22:29:54 +0900413}
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400414
Jean-Marc Valinddea3a62016-06-18 11:15:25 -0400415#ifdef FIXED_POINT
416static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
417{
418 opus_val32 x2y2;
419 int sx, sy, shift;
420 opus_val32 g;
421 opus_val16 den;
422 if (xy == 0 || xx == 0 || yy == 0)
423 return 0;
424 sx = celt_ilog2(xx)-14;
425 sy = celt_ilog2(yy)-14;
426 shift = sx + sy;
Jean-Marc Valin3609a222017-05-24 01:21:51 -0400427 x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14);
Jean-Marc Valinddea3a62016-06-18 11:15:25 -0400428 if (shift & 1) {
429 if (x2y2 < 32768)
430 {
431 x2y2 <<= 1;
432 shift--;
433 } else {
434 x2y2 >>= 1;
435 shift++;
436 }
437 }
438 den = celt_rsqrt_norm(x2y2);
439 g = MULT16_32_Q15(den, xy);
440 g = VSHR32(g, (shift>>1)-1);
441 return EXTRACT16(MIN32(g, Q15ONE));
442}
443#else
444static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
445{
446 return xy/celt_sqrt(1+xx*yy);
447}
448#endif
449
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400450static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400451opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
xiangmingzhuc95c9a02014-04-30 15:48:07 +0800452 int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch)
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400453{
Gregory Maxwellb8a6b312011-02-03 22:56:01 -0500454 int k, i, T, T0;
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400455 opus_val16 g, g0;
456 opus_val16 pg;
Jean-Marc Valinb9176a42013-06-17 16:37:41 -0400457 opus_val32 xy,xx,yy,xy2;
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400458 opus_val32 xcorr[3];
459 opus_val32 best_xy, best_yy;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400460 int offset;
Jean-Marc Valind1212602011-01-25 13:11:36 -0500461 int minperiod0;
Jean-Marc Valin64ba5022013-05-25 20:13:49 -0400462 VARDECL(opus_val32, yy_lookup);
463 SAVE_STACK;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400464
Jean-Marc Valind1212602011-01-25 13:11:36 -0500465 minperiod0 = minperiod;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400466 maxperiod /= 2;
467 minperiod /= 2;
Ralph Giles120800f2011-11-25 13:02:00 -0800468 *T0_ /= 2;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400469 prev_period /= 2;
470 N /= 2;
471 x += maxperiod;
Ralph Giles120800f2011-11-25 13:02:00 -0800472 if (*T0_>=maxperiod)
473 *T0_=maxperiod-1;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400474
Ralph Giles120800f2011-11-25 13:02:00 -0800475 T = T0 = *T0_;
Jean-Marc Valin64ba5022013-05-25 20:13:49 -0400476 ALLOC(yy_lookup, maxperiod+1, opus_val32);
Jonathan Lennox43120f02015-08-03 17:04:27 -0400477 dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch);
Jean-Marc Valin64ba5022013-05-25 20:13:49 -0400478 yy_lookup[0] = xx;
479 yy=xx;
480 for (i=1;i<=maxperiod;i++)
481 {
482 yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
483 yy_lookup[i] = MAX32(0, yy);
484 }
485 yy = yy_lookup[T0];
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400486 best_xy = xy;
487 best_yy = yy;
Jean-Marc Valinddea3a62016-06-18 11:15:25 -0400488 g = g0 = compute_pitch_gain(xy, xx, yy);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400489 /* Look for any pitch at T/k */
490 for (k=2;k<=15;k++)
491 {
492 int T1, T1b;
Jean-Marc Valinff5f7222011-07-29 18:59:12 -0400493 opus_val16 g1;
494 opus_val16 cont=0;
Jean-Marc Valin0892c162012-01-12 03:44:49 -0500495 opus_val16 thresh;
Jean-Marc Valin29354ff2014-01-21 10:39:33 -0500496 T1 = celt_udiv(2*T0+k, 2*k);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400497 if (T1 < minperiod)
498 break;
499 /* Look for another strong correlation at T1b */
500 if (k==2)
501 {
502 if (T1+T0>maxperiod)
503 T1b = T0;
504 else
505 T1b = T0+T1;
506 } else
507 {
Jean-Marc Valin29354ff2014-01-21 10:39:33 -0500508 T1b = celt_udiv(2*second_check[k]*T0+k, 2*k);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400509 }
Jonathan Lennox43120f02015-08-03 17:04:27 -0400510 dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch);
Jean-Marc Valinddea3a62016-06-18 11:15:25 -0400511 xy = HALF32(xy + xy2);
512 yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]);
513 g1 = compute_pitch_gain(xy, xx, yy);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400514 if (abs(T1-prev_period)<=1)
515 cont = prev_gain;
516 else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
Jean-Marc Valinb66080a2016-06-20 12:11:05 -0400517 cont = HALF16(prev_gain);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400518 else
519 cont = 0;
Ralph Giles027ec512012-10-23 10:49:18 -0700520 thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
Jean-Marc Valin0892c162012-01-12 03:44:49 -0500521 /* Bias against very high pitch (very short period) to avoid false-positives
522 due to short-term correlation */
523 if (T1<3*minperiod)
Ralph Giles027ec512012-10-23 10:49:18 -0700524 thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
Jean-Marc Valin0892c162012-01-12 03:44:49 -0500525 else if (T1<2*minperiod)
Ralph Giles027ec512012-10-23 10:49:18 -0700526 thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
Jean-Marc Valin0892c162012-01-12 03:44:49 -0500527 if (g1 > thresh)
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400528 {
529 best_xy = xy;
530 best_yy = yy;
531 T = T1;
532 g = g1;
533 }
534 }
Jean-Marc Valinb3deb532012-04-24 17:00:54 -0400535 best_xy = MAX32(0, best_xy);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400536 if (best_yy <= best_xy)
537 pg = Q15ONE;
538 else
539 pg = SHR32(frac_div32(best_xy,best_yy+1),16);
540
541 for (k=0;k<3;k++)
xiangmingzhuc95c9a02014-04-30 15:48:07 +0800542 xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch);
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400543 if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
544 offset = 1;
545 else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
546 offset = -1;
547 else
548 offset = 0;
549 if (pg > g)
550 pg = g;
Ralph Giles120800f2011-11-25 13:02:00 -0800551 *T0_ = 2*T+offset;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400552
Ralph Giles120800f2011-11-25 13:02:00 -0800553 if (*T0_<minperiod0)
554 *T0_=minperiod0;
Jean-Marc Valin64ba5022013-05-25 20:13:49 -0400555 RESTORE_STACK;
Jean-Marc Valin35095c62010-11-04 13:24:44 -0400556 return pg;
557}