blob: 0b8fe3c79eccf921e07616990e2eebbec30f4dba [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 Valin41af4212007-11-30 18:35:37 +11004/*
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 - Neither the name of the Xiph.org Foundation nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
Jean-Marc Valin02fa9132008-02-20 12:09:29 +110033#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
Jean-Marc Valin3ca9b1d2008-02-27 23:50:31 +110037#include "mathops.h"
Jean-Marc Valin29ccab82007-12-06 15:39:38 +110038#include "cwrs.h"
Jean-Marc Valin9cace642007-12-06 17:44:09 +110039#include "vq.h"
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +110040#include "arch.h"
Jean-Marc Valinb60340f2008-02-26 15:41:51 +110041#include "os_support.h"
Jean-Marc Valin164a2292009-07-22 07:48:35 -040042#include "rate.h"
Jean-Marc Valin41af4212007-11-30 18:35:37 +110043
Jean-Marc Valind5e54362009-09-30 20:50:41 -040044#ifndef M_PI
45#define M_PI 3.141592653
46#endif
47
Jean-Marc Valin354bf602010-04-03 09:23:29 -040048static void frac_hadamard1(celt_norm *X, int len, int stride, celt_word16 c, celt_word16 s)
Jean-Marc Valina7750b92009-08-29 22:52:03 +010049{
Jean-Marc Valin354bf602010-04-03 09:23:29 -040050 int j;
51 celt_norm *x, *y;
52 celt_norm * end;
53
54 j = 0;
55 x = X;
56 y = X+stride;
57 end = X+len;
58 do
Jean-Marc Valina7750b92009-08-29 22:52:03 +010059 {
Jean-Marc Valin354bf602010-04-03 09:23:29 -040060 celt_norm x1, x2;
61 x1 = *x;
62 x2 = *y;
63 *x++ = EXTRACT16(SHR32(MULT16_16(c,x1) + MULT16_16(s,x2),15));
64 *y++ = EXTRACT16(SHR32(MULT16_16(s,x1) - MULT16_16(c,x2),15));
65 j++;
66 if (j>=stride)
67 {
68 j=0;
69 x+=stride;
70 y+=stride;
71 }
72 } while (y<end);
73
74 /* Reverse samples so that the next level starts from the other end */
75 for (j=0;j<len>>1;j++)
Jean-Marc Valina7750b92009-08-29 22:52:03 +010076 {
Jean-Marc Valin354bf602010-04-03 09:23:29 -040077 celt_norm tmp = X[j];
78 X[j] = X[len-j-1];
79 X[len-j-1] = tmp;
Jean-Marc Valina7750b92009-08-29 22:52:03 +010080 }
Jean-Marc Valina7750b92009-08-29 22:52:03 +010081}
82
Jean-Marc Valin354bf602010-04-03 09:23:29 -040083#define MAX_LEVELS 8
84static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K)
85{
86 int i, N=0;
Jean-Marc Valin9a92d612010-04-03 16:30:49 -040087 int transient;
Jean-Marc Valin354bf602010-04-03 09:23:29 -040088 celt_word16 gain, theta;
89 int istride[MAX_LEVELS];
Jean-Marc Valin9a92d612010-04-03 16:30:49 -040090 celt_word16 c[MAX_LEVELS], s[MAX_LEVELS];
91
92 if (K >= len)
93 return;
94 transient = stride>1;
95 /*if (len>=30)
96 {
97 for (i=0;i<len;i++)
98 X[i] = 0;
99 X[30] = 1;
100 dir = -1;
101 transient = 1;
102 }*/
103 gain = celt_div((celt_word32)MULT16_16(Q15_ONE,len),(celt_word32)(3+len+4*K));
104 /* FIXME: Make that HALF16 instead of HALF32 */
105 theta = HALF32(MULT16_16_Q15(gain,gain));
106 c[0] = celt_cos_norm(EXTEND32(theta));
107 s[0] = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400108
109 do {
110 istride[N] = stride;
111 stride *= 2;
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400112 if (K==1)
113 theta = QCONST16(.25f,15);
114 c[N] = c[0];
115 s[N] = s[0];
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400116 N++;
117 } while (N<MAX_LEVELS && stride < len);
118
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400119 /* This should help a little bit with the transients */
120 if (transient)
121 c[0] = s[0] = QCONST16(.7071068, 15);
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400122
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400123 /* Needs to be < 0 to prevent gaps on the side of the spreading */
124 if (dir < 0)
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400125 {
126 for (i=0;i<N;i++)
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400127 frac_hadamard1(X, len, istride[i], c[i], s[i]);
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400128 } else {
129 for (i=N-1;i>=0;i--)
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400130 frac_hadamard1(X, len, istride[i], c[i], s[i]);
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400131 }
132
133 /* Undo last reversal */
134 for (i=0;i<len>>1;i++)
135 {
136 celt_norm tmp = X[i];
137 X[i] = X[len-i-1];
138 X[len-i-1] = tmp;
139 }
Jean-Marc Valin9a92d612010-04-03 16:30:49 -0400140 /*if (len>=30)
141 {
142 for (i=0;i<len;i++)
143 printf ("%f ", X[i]);
144 printf ("\n");
145 exit(0);
146 }*/
Jean-Marc Valin354bf602010-04-03 09:23:29 -0400147}
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100148
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100149/** Takes the pitch vector and the decoded residual vector, computes the gain
150 that will give ||p+g*y||=1 and mixes the residual with the pitch. */
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400151static void normalise_residual(int * restrict iy, celt_norm * restrict X, int N, int K, celt_word32 Ryy)
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100152{
153 int i;
Timothy Terriberry8c7bb4c2009-10-31 10:19:06 -0700154#ifdef FIXED_POINT
155 int k;
156#endif
157 celt_word32 t;
158 celt_word16 g;
Jean-Marc Valinf6dc1eb2009-10-06 20:08:49 -0400159
Timothy Terriberry8c7bb4c2009-10-31 10:19:06 -0700160#ifdef FIXED_POINT
161 k = celt_ilog2(Ryy)>>1;
162#endif
163 t = VSHR32(Ryy, (k-7)<<1);
164 g = celt_rsqrt_norm(t);
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100165
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000166 i=0;
Jean-Marc Valinf6dc1eb2009-10-06 20:08:49 -0400167 do
Timothy Terriberry8c7bb4c2009-10-31 10:19:06 -0700168 X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000169 while (++i < N);
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100170}
171
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400172void alg_quant(celt_norm *X, int N, int K, int spread, ec_enc *enc)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100173{
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400174 VARDECL(celt_norm, y);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100175 VARDECL(int, iy);
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400176 VARDECL(celt_word16, signx);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000177 int j, is;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400178 celt_word16 s;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100179 int pulsesLeft;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400180 celt_word32 sum;
181 celt_word32 xy, yy;
Jean-Marc Valinf9584772008-03-27 12:22:44 +1100182 int N_1; /* Inverse of N, in Q14 format (even for float) */
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100183#ifdef FIXED_POINT
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100184 int yshift;
185#endif
186 SAVE_STACK;
187
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400188 K = get_pulses(K);
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100189#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100190 yshift = 13-celt_ilog2(K);
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100191#endif
Jean-Marc Valin9d8d9b32008-02-27 16:17:39 +1100192
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400193 ALLOC(y, N, celt_norm);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100194 ALLOC(iy, N, int);
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400195 ALLOC(signx, N, celt_word16);
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100196 N_1 = 512/N;
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100197
198 if (spread)
199 exp_rotation(X, N, 1, spread, K);
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000200
201 sum = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000202 j=0; do {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100203 if (X[j]>0)
204 signx[j]=1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500205 else {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100206 signx[j]=-1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500207 X[j]=-X[j];
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500208 }
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000209 iy[j] = 0;
210 y[j] = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000211 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100212
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400213 xy = yy = 0;
Jean-Marc Valin0d587d82008-02-14 21:29:50 +1100214
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100215 pulsesLeft = K;
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500216
217 /* Do a pre-search by projecting on the pyramid */
Jean-Marc Valina733f082008-12-04 22:52:26 -0500218 if (K > (N>>1))
219 {
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400220 celt_word16 rcp;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500221 j=0; do {
222 sum += X[j];
223 } while (++j<N);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400224
225#ifdef FIXED_POINT
226 if (sum <= K)
227#else
228 if (sum <= EPSILON)
229#endif
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500230 {
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400231 X[0] = QCONST16(1.f,14);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400232 j=1; do
233 X[j]=0;
234 while (++j<N);
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400235 sum = QCONST16(1.f,14);
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500236 }
237 /* Do we have sufficient accuracy here? */
238 rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
Jean-Marc Valina733f082008-12-04 22:52:26 -0500239 j=0; do {
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500240#ifdef FIXED_POINT
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500241 /* It's really important to round *towards zero* here */
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500242 iy[j] = MULT16_16_Q15(X[j],rcp);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500243#else
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500244 iy[j] = floor(rcp*X[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500245#endif
Jean-Marc Valinc7635b42008-12-04 23:26:32 -0500246 y[j] = SHL16(iy[j],yshift);
247 yy = MAC16_16(yy, y[j],y[j]);
248 xy = MAC16_16(xy, X[j],y[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500249 y[j] *= 2;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500250 pulsesLeft -= iy[j];
251 } while (++j<N);
252 }
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500253 celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500254
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400255 while (pulsesLeft > 0)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100256 {
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100257 int pulsesAtOnce=1;
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100258 int best_id;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400259 celt_word16 magnitude;
260 celt_word32 best_num = -VERY_LARGE16;
261 celt_word16 best_den = 0;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000262#ifdef FIXED_POINT
263 int rshift;
264#endif
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100265 /* Decide on how many pulses to find at once */
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100266 pulsesAtOnce = (pulsesLeft*N_1)>>9; /* pulsesLeft/N */
Jean-Marc Valincab576e2008-02-12 17:21:14 +1100267 if (pulsesAtOnce<1)
268 pulsesAtOnce = 1;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000269#ifdef FIXED_POINT
270 rshift = yshift+1+celt_ilog2(K-pulsesLeft+pulsesAtOnce);
271#endif
Jean-Marc Valined317c92008-04-15 17:31:23 +1000272 magnitude = SHL16(pulsesAtOnce, yshift);
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100273
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100274 best_id = 0;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000275 /* The squared magnitude term gets added anyway, so we might as well
276 add it outside the loop */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400277 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100278 /* Choose between fast and accurate strategy depending on where we are in the search */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000279 /* This should ensure that anything we can process will have a better score */
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400280 j=0;
281 do {
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400282 celt_word16 Rxy, Ryy;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400283 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500284 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400285 /* Temporary sums of the new pulse(s) */
286 Rxy = EXTRACT16(SHR32(MAC16_16(xy, s,X[j]),rshift));
287 /* We're multiplying y[j] by two so we don't have to do it here */
288 Ryy = EXTRACT16(SHR32(MAC16_16(yy, s,y[j]),rshift));
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100289
Jean-Marc Valined317c92008-04-15 17:31:23 +1000290 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400291 Rxy is positive because the sign is pre-computed) */
292 Rxy = MULT16_16_Q15(Rxy,Rxy);
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100293 /* The idea is to check for num/den >= best_num/best_den, but that way
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400294 we can do it without any division */
295 /* OPT: Make sure to use conditional moves here */
296 if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
297 {
298 best_den = Ryy;
299 best_num = Rxy;
300 best_id = j;
301 }
302 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100303
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100304 j = best_id;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500305 is = pulsesAtOnce;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100306 s = SHL16(is, yshift);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100307
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100308 /* Updating the sums of the new pulse(s) */
309 xy = xy + MULT16_16(s,X[j]);
Jean-Marc Valined317c92008-04-15 17:31:23 +1000310 /* We're multiplying y[j] by two so we don't have to do it here */
311 yy = yy + MULT16_16(s,y[j]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100312
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100313 /* Only now that we've made the final choice, update y/iy */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000314 /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
315 y[j] += 2*s;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100316 iy[j] += is;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100317 pulsesLeft -= pulsesAtOnce;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100318 }
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500319 j=0;
320 do {
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500321 X[j] = MULT16_16(signx[j],X[j]);
322 if (signx[j] < 0)
323 iy[j] = -iy[j];
324 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100325 encode_pulses(iy, N, K, enc);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100326
Jean-Marc Valina4833ff2008-01-10 15:34:00 +1100327 /* Recompute the gain in one pass to reduce the encoder-decoder mismatch
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100328 due to the recursive computation used in quantisation. */
Jean-Marc Valinf7a1e162009-10-07 06:56:03 -0400329 normalise_residual(iy, X, N, K, EXTRACT16(SHR32(yy,2*yshift)));
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100330 if (spread)
331 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100332 RESTORE_STACK;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100333}
334
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100335
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +1100336/** Decode pulse vector and combine the result with the pitch vector to produce
337 the final normalised signal in the current band. */
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400338void alg_unquant(celt_norm *X, int N, int K, int spread, ec_dec *dec)
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100339{
Jean-Marc Valinf6dc1eb2009-10-06 20:08:49 -0400340 int i;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400341 celt_word32 Ryy;
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100342 VARDECL(int, iy);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100343 SAVE_STACK;
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400344 K = get_pulses(K);
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +1100345 ALLOC(iy, N, int);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100346 decode_pulses(iy, N, K, dec);
Jean-Marc Valinf6dc1eb2009-10-06 20:08:49 -0400347 Ryy = 0;
348 i=0;
349 do {
350 Ryy = MAC16_16(Ryy, iy[i], iy[i]);
351 } while (++i < N);
Jean-Marc Valinf7a1e162009-10-07 06:56:03 -0400352 normalise_residual(iy, X, N, K, Ryy);
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100353 if (spread)
354 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100355 RESTORE_STACK;
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100356}
357
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400358celt_word16 renormalise_vector(celt_norm *X, celt_word16 value, int N, int stride)
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400359{
360 int i;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400361 celt_word32 E = EPSILON;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400362 celt_word16 g;
Jean-Marc Valin137f3362010-04-14 17:42:22 -0400363 celt_word32 t;
Jean-Marc Valin234969c2009-10-17 22:12:42 -0400364 celt_norm *xptr = X;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400365 for (i=0;i<N;i++)
366 {
367 E = MAC16_16(E, *xptr, *xptr);
368 xptr += stride;
369 }
Jean-Marc Valincd29b022009-07-01 09:59:21 -0400370#ifdef FIXED_POINT
Jean-Marc Valin3a4a4632010-03-15 22:55:51 -0400371 int k = celt_ilog2(E)>>1;
Jean-Marc Valincd29b022009-07-01 09:59:21 -0400372#endif
Jean-Marc Valin137f3362010-04-14 17:42:22 -0400373 t = VSHR32(E, (k-7)<<1);
Jean-Marc Valin3a4a4632010-03-15 22:55:51 -0400374 g = MULT16_16_Q15(value, celt_rsqrt_norm(t));
375
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400376 xptr = X;
377 for (i=0;i<N;i++)
378 {
Jean-Marc Valin3a4a4632010-03-15 22:55:51 -0400379 *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400380 xptr += stride;
381 }
Jean-Marc Valin3a4a4632010-03-15 22:55:51 -0400382 return celt_sqrt(E);
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400383}
384
Jean-Marc Valin3a0bc3d2010-02-21 15:10:22 -0500385static void fold(const CELTMode *m, int start, int N, const celt_norm * restrict Y, celt_norm * restrict P, int N0, int B)
Jean-Marc Valin4841a0a2007-12-03 13:54:30 +1100386{
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400387 int j;
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400388 int id = N0 % B;
Jean-Marc Valin3a0bc3d2010-02-21 15:10:22 -0500389 while (id < m->eBands[start])
390 id += B;
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400391 /* Here, we assume that id will never be greater than N0, i.e. that
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400392 no band is wider than N0. In the unlikely case it happens, we set
393 everything to zero */
Jean-Marc Valin4e5b7bc2009-07-03 15:09:07 -0400394 /*{
395 int offset = (N0*C - (id+C*N))/2;
396 if (offset > C*N0/16)
397 offset = C*N0/16;
398 offset -= offset % (C*B);
399 if (offset < 0)
400 offset = 0;
401 //printf ("%d\n", offset);
402 id += offset;
403 }*/
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400404 if (id+N>N0)
405 for (j=0;j<N;j++)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400406 P[j] = 0;
407 else
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400408 for (j=0;j<N;j++)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400409 P[j] = Y[id++];
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400410}
411
Jean-Marc Valin3a0bc3d2010-02-21 15:10:22 -0500412void intra_fold(const CELTMode *m, int start, int N, const celt_norm * restrict Y, celt_norm * restrict P, int N0, int B)
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400413{
Jean-Marc Valin3a0bc3d2010-02-21 15:10:22 -0500414 fold(m, start, N, Y, P, N0, B);
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400415 renormalise_vector(P, Q15ONE, N, 1);
Jean-Marc Valin0e20ca02008-02-11 15:33:53 +1100416}
417