blob: ec9b1005f7b8bac7750036ab50159a0c7ab28259 [file] [log] [blame]
Jean-Marc Valin35a1f882008-03-26 10:34:23 +11001/* (C) 2007-2008 Jean-Marc Valin, CSIRO
Jean-Marc Valin41af4212007-11-30 18:35:37 +11002*/
3/*
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7
8 - Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 - Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14
15 - Neither the name of the Xiph.org Foundation nor the names of its
16 contributors may be used to endorse or promote products derived from
17 this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*/
31
Jean-Marc Valin02fa9132008-02-20 12:09:29 +110032#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
Jean-Marc Valin3ca9b1d2008-02-27 23:50:31 +110036#include "mathops.h"
Jean-Marc Valin29ccab82007-12-06 15:39:38 +110037#include "cwrs.h"
Jean-Marc Valin9cace642007-12-06 17:44:09 +110038#include "vq.h"
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +110039#include "arch.h"
Jean-Marc Valinb60340f2008-02-26 15:41:51 +110040#include "os_support.h"
Jean-Marc Valin164a2292009-07-22 07:48:35 -040041#include "rate.h"
Jean-Marc Valin41af4212007-11-30 18:35:37 +110042
Jean-Marc Valind5e54362009-09-30 20:50:41 -040043#ifndef M_PI
44#define M_PI 3.141592653
45#endif
46
Jean-Marc Valina7750b92009-08-29 22:52:03 +010047static void exp_rotation(celt_norm_t *X, int len, int dir, int stride, int K)
48{
49 int i, k, iter;
50 celt_word16_t c, s;
51 celt_word16_t gain, theta;
52 celt_norm_t *Xptr;
Jean-Marc Valin75732de2009-09-29 22:35:32 -040053 gain = celt_div((celt_word32_t)MULT16_16(Q15_ONE,len),(celt_word32_t)(3+len+6*K));
Jean-Marc Valina7750b92009-08-29 22:52:03 +010054 /* FIXME: Make that HALF16 instead of HALF32 */
55 theta = SUB16(Q15ONE, HALF32(MULT16_16_Q15(gain,gain)));
56 /*if (len==30)
57 {
58 for (i=0;i<len;i++)
59 X[i] = 0;
60 X[14] = 1;
61}*/
62 c = celt_cos_norm(EXTEND32(theta));
63 s = dir*celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
Jean-Marc Valin75732de2009-09-29 22:35:32 -040064 if (len > 8*stride)
65 stride *= len/(8*stride);
Jean-Marc Valina7750b92009-08-29 22:52:03 +010066 iter = 1;
67 for (k=0;k<iter;k++)
68 {
69 /* We could use MULT16_16_P15 instead of MULT16_16_Q15 for more accuracy,
70 but at this point, I really don't think it's necessary */
71 Xptr = X;
72 for (i=0;i<len-stride;i++)
73 {
74 celt_norm_t x1, x2;
75 x1 = Xptr[0];
76 x2 = Xptr[stride];
77 Xptr[stride] = MULT16_16_Q15(c,x2) + MULT16_16_Q15(s,x1);
78 *Xptr++ = MULT16_16_Q15(c,x1) - MULT16_16_Q15(s,x2);
79 }
80 Xptr = &X[len-2*stride-1];
81 for (i=len-2*stride-1;i>=0;i--)
82 {
83 celt_norm_t x1, x2;
84 x1 = Xptr[0];
85 x2 = Xptr[stride];
86 Xptr[stride] = MULT16_16_Q15(c,x2) + MULT16_16_Q15(s,x1);
87 *Xptr-- = MULT16_16_Q15(c,x1) - MULT16_16_Q15(s,x2);
88 }
89 }
90 /*if (len==30)
91 {
92 for (i=0;i<len;i++)
93 printf ("%f ", X[i]);
94 printf ("\n");
95 exit(0);
96}*/
97}
98
99
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100100/** Takes the pitch vector and the decoded residual vector, computes the gain
101 that will give ||p+g*y||=1 and mixes the residual with the pitch. */
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400102static void mix_pitch_and_residual(int * restrict iy, celt_norm_t * restrict X, int N, int K)
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100103{
104 int i;
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400105 celt_word32_t Ryy;
Jean-Marc Valina847b772008-02-27 17:46:49 +1100106 celt_word32_t g;
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100107 VARDECL(celt_norm_t, y);
Jean-Marc Valind9de5932008-03-05 08:11:57 +1100108#ifdef FIXED_POINT
109 int yshift;
110#endif
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100111 SAVE_STACK;
Jean-Marc Valind17edd32008-02-27 16:52:30 +1100112#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100113 yshift = 13-celt_ilog2(K);
Jean-Marc Valind17edd32008-02-27 16:52:30 +1100114#endif
115 ALLOC(y, N, celt_norm_t);
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100116
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000117 i=0;
Jean-Marc Valinb50c5412008-02-27 17:05:43 +1100118 Ryy = 0;
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000119 do {
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400120 y[i] = SHL16(iy[i],yshift);
Jean-Marc Valindf7ab432008-03-26 18:03:22 +1100121 Ryy = MAC16_16(Ryy, y[i], y[i]);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000122 } while (++i < N);
123
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400124 g = MULT16_32_Q15(celt_sqrt(Ryy), celt_rcp(SHR32(Ryy,9)));
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100125
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000126 i=0;
127 do
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400128 X[i] = ROUND16(MULT16_16(y[i], g),11);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000129 while (++i < N);
130
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100131 RESTORE_STACK;
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100132}
133
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100134
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400135void alg_quant(celt_norm_t *X, int N, int K, int spread, ec_enc *enc)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100136{
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100137 VARDECL(celt_norm_t, y);
138 VARDECL(int, iy);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400139 VARDECL(celt_word16_t, signx);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000140 int j, is;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100141 celt_word16_t s;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100142 int pulsesLeft;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100143 celt_word32_t sum;
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400144 celt_word32_t xy, yy;
Jean-Marc Valinf9584772008-03-27 12:22:44 +1100145 int N_1; /* Inverse of N, in Q14 format (even for float) */
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100146#ifdef FIXED_POINT
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100147 int yshift;
148#endif
149 SAVE_STACK;
150
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400151 K = get_pulses(K);
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100152#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100153 yshift = 13-celt_ilog2(K);
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100154#endif
Jean-Marc Valin9d8d9b32008-02-27 16:17:39 +1100155
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100156 ALLOC(y, N, celt_norm_t);
157 ALLOC(iy, N, int);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400158 ALLOC(signx, N, celt_word16_t);
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100159 N_1 = 512/N;
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100160
161 if (spread)
162 exp_rotation(X, N, 1, spread, K);
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000163
164 sum = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000165 j=0; do {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100166 if (X[j]>0)
167 signx[j]=1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500168 else {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100169 signx[j]=-1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500170 X[j]=-X[j];
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500171 }
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000172 iy[j] = 0;
173 y[j] = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000174 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100175
Jean-Marc Valin4ff068e2008-03-15 23:34:39 +1100176 celt_assert2(Rpp<=NORM_SCALING, "Rpp should never have a norm greater than unity");
Jean-Marc Valinb60340f2008-02-26 15:41:51 +1100177
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400178 xy = yy = 0;
Jean-Marc Valin0d587d82008-02-14 21:29:50 +1100179
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100180 pulsesLeft = K;
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500181
182 /* Do a pre-search by projecting on the pyramid */
Jean-Marc Valina733f082008-12-04 22:52:26 -0500183 if (K > (N>>1))
184 {
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500185 celt_word16_t rcp;
Gregory Maxwell61832f12008-12-22 18:15:42 -0500186 sum=0;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500187 j=0; do {
188 sum += X[j];
189 } while (++j<N);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400190
191#ifdef FIXED_POINT
192 if (sum <= K)
193#else
194 if (sum <= EPSILON)
195#endif
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500196 {
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400197 X[0] = QCONST16(1.f,14);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400198 j=1; do
199 X[j]=0;
200 while (++j<N);
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400201 sum = QCONST16(1.f,14);
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500202 }
203 /* Do we have sufficient accuracy here? */
204 rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
Jean-Marc Valina733f082008-12-04 22:52:26 -0500205 j=0; do {
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500206#ifdef FIXED_POINT
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500207 /* It's really important to round *towards zero* here */
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500208 iy[j] = MULT16_16_Q15(X[j],rcp);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500209#else
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500210 iy[j] = floor(rcp*X[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500211#endif
Jean-Marc Valinc7635b42008-12-04 23:26:32 -0500212 y[j] = SHL16(iy[j],yshift);
213 yy = MAC16_16(yy, y[j],y[j]);
214 xy = MAC16_16(xy, X[j],y[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500215 y[j] *= 2;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500216 pulsesLeft -= iy[j];
217 } while (++j<N);
218 }
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500219 celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500220
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400221 while (pulsesLeft > 0)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100222 {
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100223 int pulsesAtOnce=1;
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100224 int best_id;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000225 celt_word16_t magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400226 celt_word32_t best_num = -VERY_LARGE16;
227 celt_word16_t best_den = 0;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000228#ifdef FIXED_POINT
229 int rshift;
230#endif
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100231 /* Decide on how many pulses to find at once */
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100232 pulsesAtOnce = (pulsesLeft*N_1)>>9; /* pulsesLeft/N */
Jean-Marc Valincab576e2008-02-12 17:21:14 +1100233 if (pulsesAtOnce<1)
234 pulsesAtOnce = 1;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000235#ifdef FIXED_POINT
236 rshift = yshift+1+celt_ilog2(K-pulsesLeft+pulsesAtOnce);
237#endif
Jean-Marc Valined317c92008-04-15 17:31:23 +1000238 magnitude = SHL16(pulsesAtOnce, yshift);
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100239
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100240 best_id = 0;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000241 /* The squared magnitude term gets added anyway, so we might as well
242 add it outside the loop */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400243 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100244 /* Choose between fast and accurate strategy depending on where we are in the search */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000245 /* This should ensure that anything we can process will have a better score */
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400246 j=0;
247 do {
248 celt_word16_t Rxy, Ryy;
249 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500250 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400251 /* Temporary sums of the new pulse(s) */
252 Rxy = EXTRACT16(SHR32(MAC16_16(xy, s,X[j]),rshift));
253 /* We're multiplying y[j] by two so we don't have to do it here */
254 Ryy = EXTRACT16(SHR32(MAC16_16(yy, s,y[j]),rshift));
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100255
Jean-Marc Valined317c92008-04-15 17:31:23 +1000256 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400257 Rxy is positive because the sign is pre-computed) */
258 Rxy = MULT16_16_Q15(Rxy,Rxy);
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100259 /* The idea is to check for num/den >= best_num/best_den, but that way
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400260 we can do it without any division */
261 /* OPT: Make sure to use conditional moves here */
262 if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
263 {
264 best_den = Ryy;
265 best_num = Rxy;
266 best_id = j;
267 }
268 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100269
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100270 j = best_id;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500271 is = pulsesAtOnce;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100272 s = SHL16(is, yshift);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100273
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100274 /* Updating the sums of the new pulse(s) */
275 xy = xy + MULT16_16(s,X[j]);
Jean-Marc Valined317c92008-04-15 17:31:23 +1000276 /* We're multiplying y[j] by two so we don't have to do it here */
277 yy = yy + MULT16_16(s,y[j]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100278
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100279 /* Only now that we've made the final choice, update y/iy */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000280 /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
281 y[j] += 2*s;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100282 iy[j] += is;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100283 pulsesLeft -= pulsesAtOnce;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100284 }
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500285 j=0;
286 do {
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500287 X[j] = MULT16_16(signx[j],X[j]);
288 if (signx[j] < 0)
289 iy[j] = -iy[j];
290 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100291 encode_pulses(iy, N, K, enc);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100292
Jean-Marc Valina4833ff2008-01-10 15:34:00 +1100293 /* Recompute the gain in one pass to reduce the encoder-decoder mismatch
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100294 due to the recursive computation used in quantisation. */
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400295 mix_pitch_and_residual(iy, X, N, K);
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100296 if (spread)
297 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100298 RESTORE_STACK;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100299}
300
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100301
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +1100302/** Decode pulse vector and combine the result with the pitch vector to produce
303 the final normalised signal in the current band. */
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400304void alg_unquant(celt_norm_t *X, int N, int K, int spread, ec_dec *dec)
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100305{
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100306 VARDECL(int, iy);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100307 SAVE_STACK;
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400308 K = get_pulses(K);
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +1100309 ALLOC(iy, N, int);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100310 decode_pulses(iy, N, K, dec);
Jean-Marc Valin095c1782009-09-17 22:38:34 -0400311 mix_pitch_and_residual(iy, X, N, K);
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100312 if (spread)
313 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100314 RESTORE_STACK;
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100315}
316
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400317celt_word16_t renormalise_vector(celt_norm_t *X, celt_word16_t value, int N, int stride)
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400318{
319 int i;
320 celt_word32_t E = EPSILON;
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400321 celt_word16_t rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400322 celt_word16_t g;
323 celt_norm_t *xptr = X;
324 for (i=0;i<N;i++)
325 {
326 E = MAC16_16(E, *xptr, *xptr);
327 xptr += stride;
328 }
329
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400330 rE = celt_sqrt(E);
Jean-Marc Valincd29b022009-07-01 09:59:21 -0400331#ifdef FIXED_POINT
332 if (rE <= 128)
333 g = Q15ONE;
334 else
335#endif
336 g = MULT16_16_Q15(value,celt_rcp(SHL32(rE,9)));
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400337 xptr = X;
338 for (i=0;i<N;i++)
339 {
340 *xptr = PSHR32(MULT16_16(g, *xptr),8);
341 xptr += stride;
342 }
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400343 return rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400344}
345
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400346static void fold(const CELTMode *m, int N, const celt_norm_t * restrict Y, celt_norm_t * restrict P, int N0, int B)
Jean-Marc Valin4841a0a2007-12-03 13:54:30 +1100347{
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400348 int j;
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400349 int id = N0 % B;
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400350 /* Here, we assume that id will never be greater than N0, i.e. that
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400351 no band is wider than N0. In the unlikely case it happens, we set
352 everything to zero */
Jean-Marc Valin4e5b7bc2009-07-03 15:09:07 -0400353 /*{
354 int offset = (N0*C - (id+C*N))/2;
355 if (offset > C*N0/16)
356 offset = C*N0/16;
357 offset -= offset % (C*B);
358 if (offset < 0)
359 offset = 0;
360 //printf ("%d\n", offset);
361 id += offset;
362 }*/
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400363 if (id+N>N0)
364 for (j=0;j<N;j++)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400365 P[j] = 0;
366 else
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400367 for (j=0;j<N;j++)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400368 P[j] = Y[id++];
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400369}
370
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400371void intra_fold(const CELTMode *m, int N, const celt_norm_t * restrict Y, celt_norm_t * restrict P, int N0, int B)
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400372{
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400373 fold(m, N, Y, P, N0, B);
Jean-Marc Valind5e54362009-09-30 20:50:41 -0400374 renormalise_vector(P, Q15ONE, N, 1);
Jean-Marc Valin0e20ca02008-02-11 15:33:53 +1100375}
376