1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* Copyright (C) 2002-2006 Jean-Marc Valin
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com   File: ltp.c
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com   Long-Term Prediction functions
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com   Redistribution and use in source and binary forms, with or without
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com   modification, are permitted provided that the following conditions
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com   are met:
8b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
9b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   - Redistributions of source code must retain the above copyright
10b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   notice, this list of conditions and the following disclaimer.
11b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
12b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   - Redistributions in binary form must reproduce the above copyright
13b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   notice, this list of conditions and the following disclaimer in the
142f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   documentation and/or other materials provided with the distribution.
152f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com
16ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com   - Neither the name of the Xiph.org Foundation nor the names of its
172f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   contributors may be used to endorse or promote products derived from
182f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   this software without specific prior written permission.
192f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com
202f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
212f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
232f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
252880df2609eba09b555ca37be04b6ad89290c765Tom Hudson   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
262f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
272f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
292f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
302f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
312f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com*/
322f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com
332f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com#ifdef HAVE_CONFIG_H
342f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com#include "config.h"
352f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com#endif
362f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com
372f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com#include <math.h>
38a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "ltp.h"
39a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "stack_alloc.h"
40ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com#include "filters.h"
41a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include <speex/speex_bits.h>
42a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "math_approx.h"
43a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "os_support.h"
44ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com
45a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#ifndef NULL
46a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#define NULL 0
47a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#endif
48a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org
49a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org
50a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#ifdef _USE_SSE
51a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "ltp_sse.h"
52a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#elif defined (ARM4_ASM) || defined(ARM5E_ASM)
53a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "ltp_arm4.h"
54a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#elif defined (BFIN_ASM)
55a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#include "ltp_bfin.h"
56a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#endif
57a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org
58a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#ifndef OVERRIDE_INNER_PROD
59a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.orgspx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
60a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org{
61261b8e2ca1cf22303ad95267f0bdc6e87e1bbe70reed@google.com   spx_word32_t sum=0;
62a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   len >>= 2;
63a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   while(len--)
64ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com   {
65a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      spx_word32_t part=0;
66261b8e2ca1cf22303ad95267f0bdc6e87e1bbe70reed@google.com      part = MAC16_16(part,*x++,*y++);
67a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      part = MAC16_16(part,*x++,*y++);
68a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      part = MAC16_16(part,*x++,*y++);
69ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com      part = MAC16_16(part,*x++,*y++);
70a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      /* HINT: If you had a 40-bit accumulator, you could shift only at the end */
71261b8e2ca1cf22303ad95267f0bdc6e87e1bbe70reed@google.com      sum = ADD32(sum,SHR32(part,6));
72a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   }
73a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   return sum;
74ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com}
75a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#endif
76261b8e2ca1cf22303ad95267f0bdc6e87e1bbe70reed@google.com
77a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#ifndef OVERRIDE_PITCH_XCORR
78a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#if 0 /* HINT: Enable this for machines with enough registers (i.e. not x86) */
79ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.comvoid pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
80a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org{
81261b8e2ca1cf22303ad95267f0bdc6e87e1bbe70reed@google.com   int i,j;
82a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   for (i=0;i<nb_pitch;i+=4)
83a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   {
84ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com      /* Compute correlation*/
85a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      /*corr[nb_pitch-1-i]=inner_prod(x, _y+i, len);*/
86a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org      spx_word32_t sum1=0;
87b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      spx_word32_t sum2=0;
88b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      spx_word32_t sum3=0;
89dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      spx_word32_t sum4=0;
90dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      const spx_word16_t *y = _y+i;
91dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      const spx_word16_t *x = _x;
92dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      spx_word16_t y0, y1, y2, y3;
93dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      /*y0=y[0];y1=y[1];y2=y[2];y3=y[3];*/
94dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      y0=*y++;
95dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      y1=*y++;
96dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      y2=*y++;
97dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      y3=*y++;
98dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      for (j=0;j<len;j+=4)
99dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      {
100dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         spx_word32_t part1;
101dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         spx_word32_t part2;
102dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         spx_word32_t part3;
103dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         spx_word32_t part4;
104dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part1 = MULT16_16(*x,y0);
105dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part2 = MULT16_16(*x,y1);
106b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         part3 = MULT16_16(*x,y2);
107dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part4 = MULT16_16(*x,y3);
108b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         x++;
109dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         y0=*y++;
110dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part1 = MAC16_16(part1,*x,y1);
111dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part2 = MAC16_16(part2,*x,y2);
112dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part3 = MAC16_16(part3,*x,y3);
113dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part4 = MAC16_16(part4,*x,y0);
114dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         x++;
115dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         y1=*y++;
116dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part1 = MAC16_16(part1,*x,y2);
117dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part2 = MAC16_16(part2,*x,y3);
118dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part3 = MAC16_16(part3,*x,y0);
119dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part4 = MAC16_16(part4,*x,y1);
120dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         x++;
121dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         y2=*y++;
122dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part1 = MAC16_16(part1,*x,y3);
123dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part2 = MAC16_16(part2,*x,y0);
124dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part3 = MAC16_16(part3,*x,y1);
125dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         part4 = MAC16_16(part4,*x,y2);
126dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         x++;
127dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         y3=*y++;
128dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
129dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         sum1 = ADD32(sum1,SHR32(part1,6));
130dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         sum2 = ADD32(sum2,SHR32(part2,6));
131dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         sum3 = ADD32(sum3,SHR32(part3,6));
132dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         sum4 = ADD32(sum4,SHR32(part4,6));
133dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      }
134b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      corr[nb_pitch-1-i]=sum1;
135b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      corr[nb_pitch-2-i]=sum2;
136b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      corr[nb_pitch-3-i]=sum3;
137b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      corr[nb_pitch-4-i]=sum4;
138dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   }
139dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
140dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org}
141dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#else
142dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgvoid pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
143dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org{
144dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   int i;
145dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   for (i=0;i<nb_pitch;i++)
146dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   {
147dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      /* Compute correlation*/
148dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      corr[nb_pitch-1-i]=inner_prod(_x, _y+i, len);
149dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   }
150dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
151dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org}
152dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#endif
153dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#endif
154dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
155dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#ifndef OVERRIDE_COMPUTE_PITCH_ERROR
156dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgstatic inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control)
157dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org{
158dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   spx_word32_t sum = 0;
159b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[0],pitch_control),C[0]));
160b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[1],pitch_control),C[1]));
161b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[2],pitch_control),C[2]));
162b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[1]),C[3]));
163b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[1]),C[4]));
164b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[0]),C[5]));
165b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[0]),C[6]));
166a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[1],g[1]),C[7]));
167a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[2]),C[8]));
168b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   return sum;
169b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org}
170b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#endif
171b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
172b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#ifndef OVERRIDE_OPEN_LOOP_NBEST_PITCH
173b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgvoid open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack)
174b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org{
175b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   int i,j,k;
176b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word32_t *best_score);
177b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word32_t *best_ener);
178b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word32_t e0;
179b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word32_t *corr);
180b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#ifdef FIXED_POINT
181b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* In fixed-point, we need only one (temporary) array of 32-bit values and two (corr16, ener16)
182b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      arrays for (normalized) 16-bit values */
183b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word16_t *corr16);
184b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word16_t *ener16);
185b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word32_t *energy;
186b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   int cshift=0, eshift=0;
187b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   int scaledown = 0;
188b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   ALLOC(corr16, end-start+1, spx_word16_t);
189b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   ALLOC(ener16, end-start+1, spx_word16_t);
190b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   ALLOC(corr, end-start+1, spx_word32_t);
191b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   energy = corr;
192b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#else
193b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* In floating-point, we need to float arrays and no normalized copies */
194b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word32_t *energy);
195b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word16_t *corr16;
196b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word16_t *ener16;
197b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   ALLOC(energy, end-start+2, spx_word32_t);
198b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   ALLOC(corr, end-start+1, spx_word32_t);
199b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   corr16 = corr;
200a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   ener16 = energy;
201a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org#endif
202a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org
203a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   ALLOC(best_score, N, spx_word32_t);
204a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   ALLOC(best_ener, N, spx_word32_t);
205a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   for (i=0;i<N;i++)
206a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   {
207a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org        best_score[i]=-1;
208a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org        best_ener[i]=0;
209b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org        pitch[i]=start;
210b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
211b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
212dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#ifdef FIXED_POINT
213dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   for (i=-end;i<len;i++)
214dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   {
215dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      if (ABS16(sw[i])>16383)
216dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      {
217dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         scaledown=1;
218dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         break;
219dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      }
220b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
221b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* If the weighted input is close to saturation, then we scale it down */
222b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   if (scaledown)
223b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   {
224b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      for (i=-end;i<len;i++)
225b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      {
226b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         sw[i]=SHR16(sw[i],1);
227b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      }
228b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
229b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#endif
230b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   energy[0]=inner_prod(sw-start, sw-start, len);
231b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   e0=inner_prod(sw, sw, len);
232b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   for (i=start;i<end;i++)
233b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   {
234b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      /* Update energy for next pitch*/
235b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      energy[i-start+1] = SUB32(ADD32(energy[i-start],SHR32(MULT16_16(sw[-i-1],sw[-i-1]),6)), SHR32(MULT16_16(sw[-i+len-1],sw[-i+len-1]),6));
236b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      if (energy[i-start+1] < 0)
237b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         energy[i-start+1] = 0;
238b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
239ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com
240b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#ifdef FIXED_POINT
241b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   eshift = normalize16(energy, ener16, 32766, end-start+1);
242b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#endif
243b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
244b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* In fixed-point, this actually overrites the energy array (aliased to corr) */
245b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
246b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
247b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#ifdef FIXED_POINT
248b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* Normalize to 180 so we can square it and it still fits in 16 bits */
249b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   cshift = normalize16(corr, corr16, 180, end-start+1);
250b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */
251a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   if (scaledown)
252a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org   {
253b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      for (i=-end;i<len;i++)
254b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      {
255b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         sw[i]=SHL16(sw[i],1);
256b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      }
257b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
258b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#endif
259b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
260b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   /* Search for the best pitch prediction gain */
261b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   for (i=start;i<=end;i++)
262b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   {
263b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
264b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      /* Instead of dividing the tmp by the energy, we multiply on the other side */
2652880df2609eba09b555ca37be04b6ad89290c765Tom Hudson      if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
266b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      {
267b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         /* We can safely put it last and then check */
268b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         best_score[N-1]=tmp;
269b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         best_ener[N-1]=ener16[i-start]+1;
270b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         pitch[N-1]=i;
271b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         /* Check if it comes in front of others */
2721d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com         for (j=0;j<N-1;j++)
273b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         {
274b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org            if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
275b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org            {
276b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org               for (k=N-1;k>j;k--)
277b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org               {
278b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org                  best_score[k]=best_score[k-1];
279b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org                  best_ener[k]=best_ener[k-1];
280b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org                  pitch[k]=pitch[k-1];
281b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org               }
282b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org               best_score[j]=tmp;
283b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org               best_ener[j]=ener16[i-start]+1;
284dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org               pitch[j]=i;
285dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org               break;
286dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org            }
287dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org         }
288dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org      }
289dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   }
290dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
291dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   /* Compute open-loop gain if necessary */
2922880df2609eba09b555ca37be04b6ad89290c765Tom Hudson   if (gain)
293dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org   {
294ae933ce0ea5fd9d21cb6ef2cee7e729d32690aacrmistry@google.com      for (j=0;j<N;j++)
295b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      {
296b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         spx_word16_t g;
297b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         i=pitch[j];
298b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6));
299b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         /* FIXME: g = max(g,corr/energy) */
300b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         if (g<0)
301b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org            g = 0;
302b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org         gain[j]=g;
303b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      }
304b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   }
305b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
306b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
307b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org}
308b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#endif
309b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org
310b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org#ifndef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
311b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgstatic int pitch_gain_search_3tap_vq(
3122f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com  const signed char *gain_cdbk,
3132f3dc9dc4c970bd066be329a842a791d91f524e2reed@google.com  int                gain_cdbk_size,
314b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  spx_word16_t      *C16,
315dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  spx_word16_t       max_gain
316b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org)
317b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org{
318b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  const signed char *ptr=gain_cdbk;
319b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  int                best_cdbk=0;
320b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  spx_word32_t       best_sum=-VERY_LARGE32;
321b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  spx_word32_t       sum=0;
322b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  spx_word16_t       g[3];
323b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org  spx_word16_t       pitch_control=64;
324dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  spx_word16_t       gain_sum;
325dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  int                i;
326dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
327dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  for (i=0;i<gain_cdbk_size;i++) {
328dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
329dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    ptr = gain_cdbk+4*i;
330dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    g[0]=ADD16((spx_word16_t)ptr[0],32);
331dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    g[1]=ADD16((spx_word16_t)ptr[1],32);
332dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    g[2]=ADD16((spx_word16_t)ptr[2],32);
333dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    gain_sum = (spx_word16_t)ptr[3];
334dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
335dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org    sum = compute_pitch_error(C16, g, pitch_control);
336dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
337b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org    if (sum>best_sum && gain_sum<=max_gain) {
338b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      best_sum=sum;
339b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org      best_cdbk=i;
340b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org    }
341dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  }
342dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
343dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org  return best_cdbk;
344dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org}
345dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org#endif
346dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.org
3472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */
348dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgstatic spx_word32_t pitch_gain_search_3tap(
349b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgconst spx_word16_t target[],       /* Target vector */
350b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgconst spx_coef_t ak[],          /* LPCs for this subframe */
351b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgconst spx_coef_t awk1[],        /* Weighted LPCs #1 for this subframe */
352b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgconst spx_coef_t awk2[],        /* Weighted LPCs #2 for this subframe */
353b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgspx_sig_t exc[],                /* Excitation */
354b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgconst signed char *gain_cdbk,
355b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgint gain_cdbk_size,
356b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.orgint   pitch,                    /* Pitch value */
357dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgint   p,                        /* Number of LPC coeffs */
358dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgint   nsf,                      /* Number of samples in subframe */
359dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgSpeexBits *bits,
360dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgchar *stack,
361dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgconst spx_word16_t *exc2,
362dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgconst spx_word16_t *r,
363dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgspx_word16_t *new_target,
364dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgint  *cdbk_index,
365dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgint plc_tuning,
366dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgspx_word32_t cumul_gain,
367dd0cd34067d103ace7c6739405cb7885d8ad3fb2mike@reedtribe.orgint scaledown
3682880df2609eba09b555ca37be04b6ad89290c765Tom Hudson)
369b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org{
370b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   int i,j;
371b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word16_t *tmp1);
372b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   VARDECL(spx_word16_t *e);
373b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word16_t *x[3];
374b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word32_t corr[3];
375b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word32_t A[3][3];
376b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word16_t gain[3];
377b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word32_t err;
378b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   spx_word16_t max_gain=128;
379b7d956df4665e06f3ae98cb696cef7c04452ab8emike@reedtribe.org   int          best_cdbk=0;
380
381   ALLOC(tmp1, 3*nsf, spx_word16_t);
382   ALLOC(e, nsf, spx_word16_t);
383
384   if (cumul_gain > 262144)
385      max_gain = 31;
386
387   x[0]=tmp1;
388   x[1]=tmp1+nsf;
389   x[2]=tmp1+2*nsf;
390
391   for (j=0;j<nsf;j++)
392      new_target[j] = target[j];
393
394   {
395      VARDECL(spx_mem_t *mm);
396      int pp=pitch-1;
397      ALLOC(mm, p, spx_mem_t);
398      for (j=0;j<nsf;j++)
399      {
400         if (j-pp<0)
401            e[j]=exc2[j-pp];
402         else if (j-pp-pitch<0)
403            e[j]=exc2[j-pp-pitch];
404         else
405            e[j]=0;
406      }
407#ifdef FIXED_POINT
408      /* Scale target and excitation down if needed (avoiding overflow) */
409      if (scaledown)
410      {
411         for (j=0;j<nsf;j++)
412            e[j] = SHR16(e[j],1);
413         for (j=0;j<nsf;j++)
414            new_target[j] = SHR16(new_target[j],1);
415      }
416#endif
417      for (j=0;j<p;j++)
418         mm[j] = 0;
419      iir_mem16(e, ak, e, nsf, p, mm, stack);
420      for (j=0;j<p;j++)
421         mm[j] = 0;
422      filter_mem16(e, awk1, awk2, e, nsf, p, mm, stack);
423      for (j=0;j<nsf;j++)
424         x[2][j] = e[j];
425   }
426   for (i=1;i>=0;i--)
427   {
428      spx_word16_t e0=exc2[-pitch-1+i];
429#ifdef FIXED_POINT
430      /* Scale excitation down if needed (avoiding overflow) */
431      if (scaledown)
432         e0 = SHR16(e0,1);
433#endif
434      x[i][0]=MULT16_16_Q14(r[0], e0);
435      for (j=0;j<nsf-1;j++)
436         x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0));
437   }
438
439   for (i=0;i<3;i++)
440      corr[i]=inner_prod(x[i],new_target,nsf);
441   for (i=0;i<3;i++)
442      for (j=0;j<=i;j++)
443         A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf);
444
445   {
446      spx_word32_t C[9];
447#ifdef FIXED_POINT
448      spx_word16_t C16[9];
449#else
450      spx_word16_t *C16=C;
451#endif
452      C[0]=corr[2];
453      C[1]=corr[1];
454      C[2]=corr[0];
455      C[3]=A[1][2];
456      C[4]=A[0][1];
457      C[5]=A[0][2];
458      C[6]=A[2][2];
459      C[7]=A[1][1];
460      C[8]=A[0][0];
461
462      /*plc_tuning *= 2;*/
463      if (plc_tuning<2)
464         plc_tuning=2;
465      if (plc_tuning>30)
466         plc_tuning=30;
467#ifdef FIXED_POINT
468      C[0] = SHL32(C[0],1);
469      C[1] = SHL32(C[1],1);
470      C[2] = SHL32(C[2],1);
471      C[3] = SHL32(C[3],1);
472      C[4] = SHL32(C[4],1);
473      C[5] = SHL32(C[5],1);
474      C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]);
475      C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]);
476      C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]);
477      normalize16(C, C16, 32767, 9);
478#else
479      C[6]*=.5*(1+.02*plc_tuning);
480      C[7]*=.5*(1+.02*plc_tuning);
481      C[8]*=.5*(1+.02*plc_tuning);
482#endif
483
484      best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain);
485
486#ifdef FIXED_POINT
487      gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]);
488      gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]);
489      gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]);
490      /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/
491#else
492      gain[0] = 0.015625*gain_cdbk[best_cdbk*4]  + .5;
493      gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5;
494      gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5;
495#endif
496      *cdbk_index=best_cdbk;
497   }
498
499   SPEEX_MEMSET(exc, 0, nsf);
500   for (i=0;i<3;i++)
501   {
502      int j;
503      int tmp1, tmp3;
504      int pp=pitch+1-i;
505      tmp1=nsf;
506      if (tmp1>pp)
507         tmp1=pp;
508      for (j=0;j<tmp1;j++)
509         exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp]);
510      tmp3=nsf;
511      if (tmp3>pp+pitch)
512         tmp3=pp+pitch;
513      for (j=tmp1;j<tmp3;j++)
514         exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp-pitch]);
515   }
516   for (i=0;i<nsf;i++)
517   {
518      spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])),
519                            MULT16_16(gain[2],x[0][i]));
520      new_target[i] = SUB16(new_target[i], EXTRACT16(PSHR32(tmp,6)));
521   }
522   err = inner_prod(new_target, new_target, nsf);
523
524   return err;
525}
526
527/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */
528int pitch_search_3tap(
529spx_word16_t target[],                 /* Target vector */
530spx_word16_t *sw,
531spx_coef_t ak[],                     /* LPCs for this subframe */
532spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
533spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
534spx_sig_t exc[],                    /* Excitation */
535const void *par,
536int   start,                    /* Smallest pitch value allowed */
537int   end,                      /* Largest pitch value allowed */
538spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
539int   p,                        /* Number of LPC coeffs */
540int   nsf,                      /* Number of samples in subframe */
541SpeexBits *bits,
542char *stack,
543spx_word16_t *exc2,
544spx_word16_t *r,
545int complexity,
546int cdbk_offset,
547int plc_tuning,
548spx_word32_t *cumul_gain
549)
550{
551   int i;
552   int cdbk_index, pitch=0, best_gain_index=0;
553   VARDECL(spx_sig_t *best_exc);
554   VARDECL(spx_word16_t *new_target);
555   VARDECL(spx_word16_t *best_target);
556   int best_pitch=0;
557   spx_word32_t err, best_err=-1;
558   int N;
559   const ltp_params *params;
560   const signed char *gain_cdbk;
561   int   gain_cdbk_size;
562   int scaledown=0;
563
564   VARDECL(int *nbest);
565
566   params = (const ltp_params*) par;
567   gain_cdbk_size = 1<<params->gain_bits;
568   gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset;
569
570   N=complexity;
571   if (N>10)
572      N=10;
573   if (N<1)
574      N=1;
575
576   ALLOC(nbest, N, int);
577   params = (const ltp_params*) par;
578
579   if (end<start)
580   {
581      speex_bits_pack(bits, 0, params->pitch_bits);
582      speex_bits_pack(bits, 0, params->gain_bits);
583      SPEEX_MEMSET(exc, 0, nsf);
584      return start;
585   }
586
587#ifdef FIXED_POINT
588   /* Check if we need to scale everything down in the pitch search to avoid overflows */
589   for (i=0;i<nsf;i++)
590   {
591      if (ABS16(target[i])>16383)
592      {
593         scaledown=1;
594         break;
595      }
596   }
597   for (i=-end;i<nsf;i++)
598   {
599      if (ABS16(exc2[i])>16383)
600      {
601         scaledown=1;
602         break;
603      }
604   }
605#endif
606   if (N>end-start+1)
607      N=end-start+1;
608   if (end != start)
609      open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack);
610   else
611      nbest[0] = start;
612
613   ALLOC(best_exc, nsf, spx_sig_t);
614   ALLOC(new_target, nsf, spx_word16_t);
615   ALLOC(best_target, nsf, spx_word16_t);
616
617   for (i=0;i<N;i++)
618   {
619      pitch=nbest[i];
620      SPEEX_MEMSET(exc, 0, nsf);
621      err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf,
622                                 bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain, scaledown);
623      if (err<best_err || best_err<0)
624      {
625         SPEEX_COPY(best_exc, exc, nsf);
626         SPEEX_COPY(best_target, new_target, nsf);
627         best_err=err;
628         best_pitch=pitch;
629         best_gain_index=cdbk_index;
630      }
631   }
632   /*printf ("pitch: %d %d\n", best_pitch, best_gain_index);*/
633   speex_bits_pack(bits, best_pitch-start, params->pitch_bits);
634   speex_bits_pack(bits, best_gain_index, params->gain_bits);
635#ifdef FIXED_POINT
636   *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain));
637#else
638   *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3];
639#endif
640   /*printf ("%f\n", cumul_gain);*/
641   /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/
642   SPEEX_COPY(exc, best_exc, nsf);
643   SPEEX_COPY(target, best_target, nsf);
644#ifdef FIXED_POINT
645   /* Scale target back up if needed */
646   if (scaledown)
647   {
648      for (i=0;i<nsf;i++)
649         target[i]=SHL16(target[i],1);
650   }
651#endif
652   return pitch;
653}
654
655void pitch_unquant_3tap(
656spx_word16_t exc[],             /* Input excitation */
657spx_word32_t exc_out[],         /* Output excitation */
658int   start,                    /* Smallest pitch value allowed */
659int   end,                      /* Largest pitch value allowed */
660spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
661const void *par,
662int   nsf,                      /* Number of samples in subframe */
663int *pitch_val,
664spx_word16_t *gain_val,
665SpeexBits *bits,
666char *stack,
667int count_lost,
668int subframe_offset,
669spx_word16_t last_pitch_gain,
670int cdbk_offset
671)
672{
673   int i;
674   int pitch;
675   int gain_index;
676   spx_word16_t gain[3];
677   const signed char *gain_cdbk;
678   int gain_cdbk_size;
679   const ltp_params *params;
680
681   params = (const ltp_params*) par;
682   gain_cdbk_size = 1<<params->gain_bits;
683   gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset;
684
685   pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits);
686   pitch += start;
687   gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits);
688   /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/
689#ifdef FIXED_POINT
690   gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]);
691   gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]);
692   gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]);
693#else
694   gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5;
695   gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5;
696   gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5;
697#endif
698
699   if (count_lost && pitch > subframe_offset)
700   {
701      spx_word16_t gain_sum;
702      if (1) {
703#ifdef FIXED_POINT
704         spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1);
705         if (tmp>62)
706            tmp=62;
707#else
708         spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain;
709         if (tmp>.95)
710            tmp=.95;
711#endif
712         gain_sum = gain_3tap_to_1tap(gain);
713
714         if (gain_sum > tmp)
715         {
716            spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum);
717            for (i=0;i<3;i++)
718               gain[i]=MULT16_16_Q14(fact,gain[i]);
719         }
720
721      }
722
723   }
724
725   *pitch_val = pitch;
726   gain_val[0]=gain[0];
727   gain_val[1]=gain[1];
728   gain_val[2]=gain[2];
729   gain[0] = SHL16(gain[0],7);
730   gain[1] = SHL16(gain[1],7);
731   gain[2] = SHL16(gain[2],7);
732   SPEEX_MEMSET(exc_out, 0, nsf);
733   for (i=0;i<3;i++)
734   {
735      int j;
736      int tmp1, tmp3;
737      int pp=pitch+1-i;
738      tmp1=nsf;
739      if (tmp1>pp)
740         tmp1=pp;
741      for (j=0;j<tmp1;j++)
742         exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp]);
743      tmp3=nsf;
744      if (tmp3>pp+pitch)
745         tmp3=pp+pitch;
746      for (j=tmp1;j<tmp3;j++)
747         exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp-pitch]);
748   }
749   /*for (i=0;i<nsf;i++)
750   exc[i]=PSHR32(exc32[i],13);*/
751}
752
753
754/** Forced pitch delay and gain */
755int forced_pitch_quant(
756spx_word16_t target[],                 /* Target vector */
757spx_word16_t *sw,
758spx_coef_t ak[],                     /* LPCs for this subframe */
759spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
760spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
761spx_sig_t exc[],                    /* Excitation */
762const void *par,
763int   start,                    /* Smallest pitch value allowed */
764int   end,                      /* Largest pitch value allowed */
765spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
766int   p,                        /* Number of LPC coeffs */
767int   nsf,                      /* Number of samples in subframe */
768SpeexBits *bits,
769char *stack,
770spx_word16_t *exc2,
771spx_word16_t *r,
772int complexity,
773int cdbk_offset,
774int plc_tuning,
775spx_word32_t *cumul_gain
776)
777{
778   int i;
779   VARDECL(spx_word16_t *res);
780   ALLOC(res, nsf, spx_word16_t);
781#ifdef FIXED_POINT
782   if (pitch_coef>63)
783      pitch_coef=63;
784#else
785   if (pitch_coef>.99)
786      pitch_coef=.99;
787#endif
788   for (i=0;i<nsf&&i<start;i++)
789   {
790      exc[i]=MULT16_16(SHL16(pitch_coef, 7),exc2[i-start]);
791   }
792   for (;i<nsf;i++)
793   {
794      exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]);
795   }
796   for (i=0;i<nsf;i++)
797      res[i] = EXTRACT16(PSHR32(exc[i], SIG_SHIFT-1));
798   syn_percep_zero16(res, ak, awk1, awk2, res, nsf, p, stack);
799   for (i=0;i<nsf;i++)
800      target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),EXTEND32(res[i])),32700));
801   return start;
802}
803
804/** Unquantize forced pitch delay and gain */
805void forced_pitch_unquant(
806spx_word16_t exc[],             /* Input excitation */
807spx_word32_t exc_out[],         /* Output excitation */
808int   start,                    /* Smallest pitch value allowed */
809int   end,                      /* Largest pitch value allowed */
810spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
811const void *par,
812int   nsf,                      /* Number of samples in subframe */
813int *pitch_val,
814spx_word16_t *gain_val,
815SpeexBits *bits,
816char *stack,
817int count_lost,
818int subframe_offset,
819spx_word16_t last_pitch_gain,
820int cdbk_offset
821)
822{
823   int i;
824#ifdef FIXED_POINT
825   if (pitch_coef>63)
826      pitch_coef=63;
827#else
828   if (pitch_coef>.99)
829      pitch_coef=.99;
830#endif
831   for (i=0;i<nsf;i++)
832   {
833      exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7));
834      exc[i] = EXTRACT16(PSHR32(exc_out[i],13));
835   }
836   *pitch_val = start;
837   gain_val[0]=gain_val[2]=0;
838   gain_val[1] = pitch_coef;
839}
840