cannam@154
|
1 /* Copyright (c) 2009-2010 Xiph.Org Foundation
|
cannam@154
|
2 Written by Jean-Marc Valin */
|
cannam@154
|
3 /*
|
cannam@154
|
4 Redistribution and use in source and binary forms, with or without
|
cannam@154
|
5 modification, are permitted provided that the following conditions
|
cannam@154
|
6 are met:
|
cannam@154
|
7
|
cannam@154
|
8 - Redistributions of source code must retain the above copyright
|
cannam@154
|
9 notice, this list of conditions and the following disclaimer.
|
cannam@154
|
10
|
cannam@154
|
11 - Redistributions in binary form must reproduce the above copyright
|
cannam@154
|
12 notice, this list of conditions and the following disclaimer in the
|
cannam@154
|
13 documentation and/or other materials provided with the distribution.
|
cannam@154
|
14
|
cannam@154
|
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
cannam@154
|
16 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
cannam@154
|
17 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
cannam@154
|
18 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
cannam@154
|
19 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
cannam@154
|
20 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
cannam@154
|
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
cannam@154
|
22 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
cannam@154
|
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
cannam@154
|
24 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
cannam@154
|
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
cannam@154
|
26 */
|
cannam@154
|
27
|
cannam@154
|
28 #ifdef HAVE_CONFIG_H
|
cannam@154
|
29 #include "config.h"
|
cannam@154
|
30 #endif
|
cannam@154
|
31
|
cannam@154
|
32 #include "celt_lpc.h"
|
cannam@154
|
33 #include "stack_alloc.h"
|
cannam@154
|
34 #include "mathops.h"
|
cannam@154
|
35 #include "pitch.h"
|
cannam@154
|
36
|
cannam@154
|
37 void _celt_lpc(
|
cannam@154
|
38 opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
|
cannam@154
|
39 const opus_val32 *ac, /* in: [0...p] autocorrelation values */
|
cannam@154
|
40 int p
|
cannam@154
|
41 )
|
cannam@154
|
42 {
|
cannam@154
|
43 int i, j;
|
cannam@154
|
44 opus_val32 r;
|
cannam@154
|
45 opus_val32 error = ac[0];
|
cannam@154
|
46 #ifdef FIXED_POINT
|
cannam@154
|
47 opus_val32 lpc[LPC_ORDER];
|
cannam@154
|
48 #else
|
cannam@154
|
49 float *lpc = _lpc;
|
cannam@154
|
50 #endif
|
cannam@154
|
51
|
cannam@154
|
52 OPUS_CLEAR(lpc, p);
|
cannam@154
|
53 if (ac[0] != 0)
|
cannam@154
|
54 {
|
cannam@154
|
55 for (i = 0; i < p; i++) {
|
cannam@154
|
56 /* Sum up this iteration's reflection coefficient */
|
cannam@154
|
57 opus_val32 rr = 0;
|
cannam@154
|
58 for (j = 0; j < i; j++)
|
cannam@154
|
59 rr += MULT32_32_Q31(lpc[j],ac[i - j]);
|
cannam@154
|
60 rr += SHR32(ac[i + 1],3);
|
cannam@154
|
61 r = -frac_div32(SHL32(rr,3), error);
|
cannam@154
|
62 /* Update LPC coefficients and total error */
|
cannam@154
|
63 lpc[i] = SHR32(r,3);
|
cannam@154
|
64 for (j = 0; j < (i+1)>>1; j++)
|
cannam@154
|
65 {
|
cannam@154
|
66 opus_val32 tmp1, tmp2;
|
cannam@154
|
67 tmp1 = lpc[j];
|
cannam@154
|
68 tmp2 = lpc[i-1-j];
|
cannam@154
|
69 lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
|
cannam@154
|
70 lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
|
cannam@154
|
71 }
|
cannam@154
|
72
|
cannam@154
|
73 error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
|
cannam@154
|
74 /* Bail out once we get 30 dB gain */
|
cannam@154
|
75 #ifdef FIXED_POINT
|
cannam@154
|
76 if (error<SHR32(ac[0],10))
|
cannam@154
|
77 break;
|
cannam@154
|
78 #else
|
cannam@154
|
79 if (error<.001f*ac[0])
|
cannam@154
|
80 break;
|
cannam@154
|
81 #endif
|
cannam@154
|
82 }
|
cannam@154
|
83 }
|
cannam@154
|
84 #ifdef FIXED_POINT
|
cannam@154
|
85 for (i=0;i<p;i++)
|
cannam@154
|
86 _lpc[i] = ROUND16(lpc[i],16);
|
cannam@154
|
87 #endif
|
cannam@154
|
88 }
|
cannam@154
|
89
|
cannam@154
|
90
|
cannam@154
|
91 void celt_fir_c(
|
cannam@154
|
92 const opus_val16 *x,
|
cannam@154
|
93 const opus_val16 *num,
|
cannam@154
|
94 opus_val16 *y,
|
cannam@154
|
95 int N,
|
cannam@154
|
96 int ord,
|
cannam@154
|
97 int arch)
|
cannam@154
|
98 {
|
cannam@154
|
99 int i,j;
|
cannam@154
|
100 VARDECL(opus_val16, rnum);
|
cannam@154
|
101 SAVE_STACK;
|
cannam@154
|
102 celt_assert(x != y);
|
cannam@154
|
103 ALLOC(rnum, ord, opus_val16);
|
cannam@154
|
104 for(i=0;i<ord;i++)
|
cannam@154
|
105 rnum[i] = num[ord-i-1];
|
cannam@154
|
106 for (i=0;i<N-3;i+=4)
|
cannam@154
|
107 {
|
cannam@154
|
108 opus_val32 sum[4];
|
cannam@154
|
109 sum[0] = SHL32(EXTEND32(x[i ]), SIG_SHIFT);
|
cannam@154
|
110 sum[1] = SHL32(EXTEND32(x[i+1]), SIG_SHIFT);
|
cannam@154
|
111 sum[2] = SHL32(EXTEND32(x[i+2]), SIG_SHIFT);
|
cannam@154
|
112 sum[3] = SHL32(EXTEND32(x[i+3]), SIG_SHIFT);
|
cannam@154
|
113 xcorr_kernel(rnum, x+i-ord, sum, ord, arch);
|
cannam@154
|
114 y[i ] = ROUND16(sum[0], SIG_SHIFT);
|
cannam@154
|
115 y[i+1] = ROUND16(sum[1], SIG_SHIFT);
|
cannam@154
|
116 y[i+2] = ROUND16(sum[2], SIG_SHIFT);
|
cannam@154
|
117 y[i+3] = ROUND16(sum[3], SIG_SHIFT);
|
cannam@154
|
118 }
|
cannam@154
|
119 for (;i<N;i++)
|
cannam@154
|
120 {
|
cannam@154
|
121 opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
|
cannam@154
|
122 for (j=0;j<ord;j++)
|
cannam@154
|
123 sum = MAC16_16(sum,rnum[j],x[i+j-ord]);
|
cannam@154
|
124 y[i] = ROUND16(sum, SIG_SHIFT);
|
cannam@154
|
125 }
|
cannam@154
|
126 RESTORE_STACK;
|
cannam@154
|
127 }
|
cannam@154
|
128
|
cannam@154
|
129 void celt_iir(const opus_val32 *_x,
|
cannam@154
|
130 const opus_val16 *den,
|
cannam@154
|
131 opus_val32 *_y,
|
cannam@154
|
132 int N,
|
cannam@154
|
133 int ord,
|
cannam@154
|
134 opus_val16 *mem,
|
cannam@154
|
135 int arch)
|
cannam@154
|
136 {
|
cannam@154
|
137 #ifdef SMALL_FOOTPRINT
|
cannam@154
|
138 int i,j;
|
cannam@154
|
139 (void)arch;
|
cannam@154
|
140 for (i=0;i<N;i++)
|
cannam@154
|
141 {
|
cannam@154
|
142 opus_val32 sum = _x[i];
|
cannam@154
|
143 for (j=0;j<ord;j++)
|
cannam@154
|
144 {
|
cannam@154
|
145 sum -= MULT16_16(den[j],mem[j]);
|
cannam@154
|
146 }
|
cannam@154
|
147 for (j=ord-1;j>=1;j--)
|
cannam@154
|
148 {
|
cannam@154
|
149 mem[j]=mem[j-1];
|
cannam@154
|
150 }
|
cannam@154
|
151 mem[0] = SROUND16(sum, SIG_SHIFT);
|
cannam@154
|
152 _y[i] = sum;
|
cannam@154
|
153 }
|
cannam@154
|
154 #else
|
cannam@154
|
155 int i,j;
|
cannam@154
|
156 VARDECL(opus_val16, rden);
|
cannam@154
|
157 VARDECL(opus_val16, y);
|
cannam@154
|
158 SAVE_STACK;
|
cannam@154
|
159
|
cannam@154
|
160 celt_assert((ord&3)==0);
|
cannam@154
|
161 ALLOC(rden, ord, opus_val16);
|
cannam@154
|
162 ALLOC(y, N+ord, opus_val16);
|
cannam@154
|
163 for(i=0;i<ord;i++)
|
cannam@154
|
164 rden[i] = den[ord-i-1];
|
cannam@154
|
165 for(i=0;i<ord;i++)
|
cannam@154
|
166 y[i] = -mem[ord-i-1];
|
cannam@154
|
167 for(;i<N+ord;i++)
|
cannam@154
|
168 y[i]=0;
|
cannam@154
|
169 for (i=0;i<N-3;i+=4)
|
cannam@154
|
170 {
|
cannam@154
|
171 /* Unroll by 4 as if it were an FIR filter */
|
cannam@154
|
172 opus_val32 sum[4];
|
cannam@154
|
173 sum[0]=_x[i];
|
cannam@154
|
174 sum[1]=_x[i+1];
|
cannam@154
|
175 sum[2]=_x[i+2];
|
cannam@154
|
176 sum[3]=_x[i+3];
|
cannam@154
|
177 xcorr_kernel(rden, y+i, sum, ord, arch);
|
cannam@154
|
178
|
cannam@154
|
179 /* Patch up the result to compensate for the fact that this is an IIR */
|
cannam@154
|
180 y[i+ord ] = -SROUND16(sum[0],SIG_SHIFT);
|
cannam@154
|
181 _y[i ] = sum[0];
|
cannam@154
|
182 sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]);
|
cannam@154
|
183 y[i+ord+1] = -SROUND16(sum[1],SIG_SHIFT);
|
cannam@154
|
184 _y[i+1] = sum[1];
|
cannam@154
|
185 sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
|
cannam@154
|
186 sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]);
|
cannam@154
|
187 y[i+ord+2] = -SROUND16(sum[2],SIG_SHIFT);
|
cannam@154
|
188 _y[i+2] = sum[2];
|
cannam@154
|
189
|
cannam@154
|
190 sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
|
cannam@154
|
191 sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
|
cannam@154
|
192 sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]);
|
cannam@154
|
193 y[i+ord+3] = -SROUND16(sum[3],SIG_SHIFT);
|
cannam@154
|
194 _y[i+3] = sum[3];
|
cannam@154
|
195 }
|
cannam@154
|
196 for (;i<N;i++)
|
cannam@154
|
197 {
|
cannam@154
|
198 opus_val32 sum = _x[i];
|
cannam@154
|
199 for (j=0;j<ord;j++)
|
cannam@154
|
200 sum -= MULT16_16(rden[j],y[i+j]);
|
cannam@154
|
201 y[i+ord] = SROUND16(sum,SIG_SHIFT);
|
cannam@154
|
202 _y[i] = sum;
|
cannam@154
|
203 }
|
cannam@154
|
204 for(i=0;i<ord;i++)
|
cannam@154
|
205 mem[i] = _y[N-i-1];
|
cannam@154
|
206 RESTORE_STACK;
|
cannam@154
|
207 #endif
|
cannam@154
|
208 }
|
cannam@154
|
209
|
cannam@154
|
210 int _celt_autocorr(
|
cannam@154
|
211 const opus_val16 *x, /* in: [0...n-1] samples x */
|
cannam@154
|
212 opus_val32 *ac, /* out: [0...lag-1] ac values */
|
cannam@154
|
213 const opus_val16 *window,
|
cannam@154
|
214 int overlap,
|
cannam@154
|
215 int lag,
|
cannam@154
|
216 int n,
|
cannam@154
|
217 int arch
|
cannam@154
|
218 )
|
cannam@154
|
219 {
|
cannam@154
|
220 opus_val32 d;
|
cannam@154
|
221 int i, k;
|
cannam@154
|
222 int fastN=n-lag;
|
cannam@154
|
223 int shift;
|
cannam@154
|
224 const opus_val16 *xptr;
|
cannam@154
|
225 VARDECL(opus_val16, xx);
|
cannam@154
|
226 SAVE_STACK;
|
cannam@154
|
227 ALLOC(xx, n, opus_val16);
|
cannam@154
|
228 celt_assert(n>0);
|
cannam@154
|
229 celt_assert(overlap>=0);
|
cannam@154
|
230 if (overlap == 0)
|
cannam@154
|
231 {
|
cannam@154
|
232 xptr = x;
|
cannam@154
|
233 } else {
|
cannam@154
|
234 for (i=0;i<n;i++)
|
cannam@154
|
235 xx[i] = x[i];
|
cannam@154
|
236 for (i=0;i<overlap;i++)
|
cannam@154
|
237 {
|
cannam@154
|
238 xx[i] = MULT16_16_Q15(x[i],window[i]);
|
cannam@154
|
239 xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
|
cannam@154
|
240 }
|
cannam@154
|
241 xptr = xx;
|
cannam@154
|
242 }
|
cannam@154
|
243 shift=0;
|
cannam@154
|
244 #ifdef FIXED_POINT
|
cannam@154
|
245 {
|
cannam@154
|
246 opus_val32 ac0;
|
cannam@154
|
247 ac0 = 1+(n<<7);
|
cannam@154
|
248 if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
|
cannam@154
|
249 for(i=(n&1);i<n;i+=2)
|
cannam@154
|
250 {
|
cannam@154
|
251 ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
|
cannam@154
|
252 ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
|
cannam@154
|
253 }
|
cannam@154
|
254
|
cannam@154
|
255 shift = celt_ilog2(ac0)-30+10;
|
cannam@154
|
256 shift = (shift)/2;
|
cannam@154
|
257 if (shift>0)
|
cannam@154
|
258 {
|
cannam@154
|
259 for(i=0;i<n;i++)
|
cannam@154
|
260 xx[i] = PSHR32(xptr[i], shift);
|
cannam@154
|
261 xptr = xx;
|
cannam@154
|
262 } else
|
cannam@154
|
263 shift = 0;
|
cannam@154
|
264 }
|
cannam@154
|
265 #endif
|
cannam@154
|
266 celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1, arch);
|
cannam@154
|
267 for (k=0;k<=lag;k++)
|
cannam@154
|
268 {
|
cannam@154
|
269 for (i = k+fastN, d = 0; i < n; i++)
|
cannam@154
|
270 d = MAC16_16(d, xptr[i], xptr[i-k]);
|
cannam@154
|
271 ac[k] += d;
|
cannam@154
|
272 }
|
cannam@154
|
273 #ifdef FIXED_POINT
|
cannam@154
|
274 shift = 2*shift;
|
cannam@154
|
275 if (shift<=0)
|
cannam@154
|
276 ac[0] += SHL32((opus_int32)1, -shift);
|
cannam@154
|
277 if (ac[0] < 268435456)
|
cannam@154
|
278 {
|
cannam@154
|
279 int shift2 = 29 - EC_ILOG(ac[0]);
|
cannam@154
|
280 for (i=0;i<=lag;i++)
|
cannam@154
|
281 ac[i] = SHL32(ac[i], shift2);
|
cannam@154
|
282 shift -= shift2;
|
cannam@154
|
283 } else if (ac[0] >= 536870912)
|
cannam@154
|
284 {
|
cannam@154
|
285 int shift2=1;
|
cannam@154
|
286 if (ac[0] >= 1073741824)
|
cannam@154
|
287 shift2++;
|
cannam@154
|
288 for (i=0;i<=lag;i++)
|
cannam@154
|
289 ac[i] = SHR32(ac[i], shift2);
|
cannam@154
|
290 shift += shift2;
|
cannam@154
|
291 }
|
cannam@154
|
292 #endif
|
cannam@154
|
293
|
cannam@154
|
294 RESTORE_STACK;
|
cannam@154
|
295 return shift;
|
cannam@154
|
296 }
|