blob: d5c0206fc49ac19d3602b769f7b18873f6210f0c [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 Valin41af4212007-11-30 18:35:37 +110041
Jean-Marc Valin35a1f882008-03-26 10:34:23 +110042/** Takes the pitch vector and the decoded residual vector, computes the gain
43 that will give ||p+g*y||=1 and mixes the residual with the pitch. */
Jean-Marc Valin5de868c2008-03-25 22:38:58 +110044static void mix_pitch_and_residual(int * restrict iy, celt_norm_t * restrict X, int N, int K, const celt_norm_t * restrict P)
Jean-Marc Valind4018c32008-02-27 10:09:48 +110045{
46 int i;
Jean-Marc Valinb50c5412008-02-27 17:05:43 +110047 celt_word32_t Ryp, Ryy, Rpp;
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -040048 celt_word16_t ryp, ryy, rpp;
Jean-Marc Valina847b772008-02-27 17:46:49 +110049 celt_word32_t g;
Jean-Marc Valin31b79d12008-03-12 17:17:23 +110050 VARDECL(celt_norm_t, y);
Jean-Marc Valind9de5932008-03-05 08:11:57 +110051#ifdef FIXED_POINT
52 int yshift;
53#endif
Jean-Marc Valin8600f692008-02-29 15:14:12 +110054 SAVE_STACK;
Jean-Marc Valind17edd32008-02-27 16:52:30 +110055#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +110056 yshift = 13-celt_ilog2(K);
Jean-Marc Valind17edd32008-02-27 16:52:30 +110057#endif
58 ALLOC(y, N, celt_norm_t);
Jean-Marc Valind4018c32008-02-27 10:09:48 +110059
Jean-Marc Valinb50c5412008-02-27 17:05:43 +110060 Rpp = 0;
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100061 i=0;
62 do {
Jean-Marc Valinb50c5412008-02-27 17:05:43 +110063 Rpp = MAC16_16(Rpp,P[i],P[i]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +110064 y[i] = SHL16(iy[i],yshift);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100065 } while (++i < N);
66
Jean-Marc Valind4018c32008-02-27 10:09:48 +110067 Ryp = 0;
Jean-Marc Valinb50c5412008-02-27 17:05:43 +110068 Ryy = 0;
Jean-Marc Valindf7ab432008-03-26 18:03:22 +110069 /* If this doesn't generate a dual MAC (on supported archs), fire the compiler guy */
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100070 i=0;
71 do {
Jean-Marc Valindf7ab432008-03-26 18:03:22 +110072 Ryp = MAC16_16(Ryp, y[i], P[i]);
73 Ryy = MAC16_16(Ryy, y[i], y[i]);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100074 } while (++i < N);
75
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -040076 ryp = ROUND16(Ryp,14);
77 ryy = ROUND16(Ryy,14);
78 rpp = ROUND16(Rpp,14);
Jean-Marc Valin1ca07222008-02-27 17:23:04 +110079 /* g = (sqrt(Ryp^2 + Ryy - Rpp*Ryy)-Ryp)/Ryy */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -040080 g = MULT16_32_Q15(celt_sqrt(MAC16_16(Ryy, ryp,ryp) - MULT16_16(ryy,rpp)) - ryp,
81 celt_rcp(SHR32(Ryy,9)));
Jean-Marc Valind4018c32008-02-27 10:09:48 +110082
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100083 i=0;
84 do
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -040085 X[i] = ADD16(P[i], ROUND16(MULT16_16(y[i], g),11));
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100086 while (++i < N);
87
Jean-Marc Valin8600f692008-02-29 15:14:12 +110088 RESTORE_STACK;
Jean-Marc Valind4018c32008-02-27 10:09:48 +110089}
90
Jean-Marc Valin41af4212007-11-30 18:35:37 +110091
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -050092void alg_quant(celt_norm_t *X, celt_mask_t *W, int N, int K, celt_norm_t *P, ec_enc *enc)
Jean-Marc Valin41af4212007-11-30 18:35:37 +110093{
Jean-Marc Valin44c63352008-03-25 21:28:40 +110094 VARDECL(celt_norm_t, y);
95 VARDECL(int, iy);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -040096 VARDECL(celt_word16_t, signx);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +100097 int j, is;
Jean-Marc Valin44c63352008-03-25 21:28:40 +110098 celt_word16_t s;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +110099 int pulsesLeft;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100100 celt_word32_t sum;
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100101 celt_word32_t xy, yy, yp;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100102 celt_word16_t Rpp;
Jean-Marc Valinf9584772008-03-27 12:22:44 +1100103 int N_1; /* Inverse of N, in Q14 format (even for float) */
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100104#ifdef FIXED_POINT
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100105 int yshift;
106#endif
107 SAVE_STACK;
108
109#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100110 yshift = 13-celt_ilog2(K);
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100111#endif
Jean-Marc Valin9d8d9b32008-02-27 16:17:39 +1100112
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100113 ALLOC(y, N, celt_norm_t);
114 ALLOC(iy, N, int);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400115 ALLOC(signx, N, celt_word16_t);
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100116 N_1 = 512/N;
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000117
118 sum = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000119 j=0; do {
Jean-Marc Valinbf2d6482008-05-23 16:57:34 +1000120 X[j] -= P[j];
Jean-Marc Valin49134382008-03-25 16:07:05 +1100121 if (X[j]>0)
122 signx[j]=1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500123 else {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100124 signx[j]=-1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500125 X[j]=-X[j];
126 P[j]=-P[j];
127 }
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000128 iy[j] = 0;
129 y[j] = 0;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100130 sum = MAC16_16(sum, P[j],P[j]);
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000131 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100132 Rpp = ROUND16(sum, NORM_SHIFT);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100133
Jean-Marc Valin4ff068e2008-03-15 23:34:39 +1100134 celt_assert2(Rpp<=NORM_SCALING, "Rpp should never have a norm greater than unity");
Jean-Marc Valinb60340f2008-02-26 15:41:51 +1100135
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100136 xy = yy = yp = 0;
Jean-Marc Valin0d587d82008-02-14 21:29:50 +1100137
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100138 pulsesLeft = K;
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500139
140 /* Do a pre-search by projecting on the pyramid */
Jean-Marc Valina733f082008-12-04 22:52:26 -0500141 if (K > (N>>1))
142 {
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500143 celt_word16_t rcp;
Gregory Maxwell61832f12008-12-22 18:15:42 -0500144 sum=0;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500145 j=0; do {
146 sum += X[j];
147 } while (++j<N);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400148
149#ifdef FIXED_POINT
150 if (sum <= K)
151#else
152 if (sum <= EPSILON)
153#endif
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500154 {
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400155 X[0] = QCONST16(1.f,14);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400156 j=1; do
157 X[j]=0;
158 while (++j<N);
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400159 sum = QCONST16(1.f,14);
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500160 }
161 /* Do we have sufficient accuracy here? */
162 rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
Jean-Marc Valina733f082008-12-04 22:52:26 -0500163 j=0; do {
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500164#ifdef FIXED_POINT
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500165 /* It's really important to round *towards zero* here */
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500166 iy[j] = MULT16_16_Q15(X[j],rcp);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500167#else
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500168 iy[j] = floor(rcp*X[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500169#endif
Jean-Marc Valinc7635b42008-12-04 23:26:32 -0500170 y[j] = SHL16(iy[j],yshift);
171 yy = MAC16_16(yy, y[j],y[j]);
172 xy = MAC16_16(xy, X[j],y[j]);
Jean-Marc Valina733f082008-12-04 22:52:26 -0500173 yp += P[j]*y[j];
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500174 y[j] *= 2;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500175 pulsesLeft -= iy[j];
176 } while (++j<N);
177 }
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500178 celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500179
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400180 while (pulsesLeft > 1)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100181 {
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100182 int pulsesAtOnce=1;
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100183 int best_id;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000184 celt_word16_t magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400185 celt_word32_t best_num = -VERY_LARGE16;
186 celt_word16_t best_den = 0;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000187#ifdef FIXED_POINT
188 int rshift;
189#endif
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100190 /* Decide on how many pulses to find at once */
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100191 pulsesAtOnce = (pulsesLeft*N_1)>>9; /* pulsesLeft/N */
Jean-Marc Valincab576e2008-02-12 17:21:14 +1100192 if (pulsesAtOnce<1)
193 pulsesAtOnce = 1;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000194#ifdef FIXED_POINT
195 rshift = yshift+1+celt_ilog2(K-pulsesLeft+pulsesAtOnce);
196#endif
Jean-Marc Valined317c92008-04-15 17:31:23 +1000197 magnitude = SHL16(pulsesAtOnce, yshift);
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100198
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100199 best_id = 0;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000200 /* The squared magnitude term gets added anyway, so we might as well
201 add it outside the loop */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400202 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100203 /* Choose between fast and accurate strategy depending on where we are in the search */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000204 /* This should ensure that anything we can process will have a better score */
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400205 j=0;
206 do {
207 celt_word16_t Rxy, Ryy;
208 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500209 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400210 /* Temporary sums of the new pulse(s) */
211 Rxy = EXTRACT16(SHR32(MAC16_16(xy, s,X[j]),rshift));
212 /* We're multiplying y[j] by two so we don't have to do it here */
213 Ryy = EXTRACT16(SHR32(MAC16_16(yy, s,y[j]),rshift));
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100214
Jean-Marc Valined317c92008-04-15 17:31:23 +1000215 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400216 Rxy is positive because the sign is pre-computed) */
217 Rxy = MULT16_16_Q15(Rxy,Rxy);
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100218 /* The idea is to check for num/den >= best_num/best_den, but that way
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400219 we can do it without any division */
220 /* OPT: Make sure to use conditional moves here */
221 if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
222 {
223 best_den = Ryy;
224 best_num = Rxy;
225 best_id = j;
226 }
227 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100228
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100229 j = best_id;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500230 is = pulsesAtOnce;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100231 s = SHL16(is, yshift);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100232
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100233 /* Updating the sums of the new pulse(s) */
234 xy = xy + MULT16_16(s,X[j]);
Jean-Marc Valined317c92008-04-15 17:31:23 +1000235 /* We're multiplying y[j] by two so we don't have to do it here */
236 yy = yy + MULT16_16(s,y[j]);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100237 yp = yp + MULT16_16(s, P[j]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100238
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100239 /* Only now that we've made the final choice, update y/iy */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000240 /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
241 y[j] += 2*s;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100242 iy[j] += is;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100243 pulsesLeft -= pulsesAtOnce;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100244 }
245
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500246 if (pulsesLeft > 0)
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400247 {
248 celt_word16_t g;
249 celt_word16_t best_num = -VERY_LARGE16;
250 celt_word16_t best_den = 0;
251 int best_id = 0;
Jean-Marc Valin0ec7c142008-09-22 10:25:46 -0400252 celt_word16_t magnitude = SHL16(1, yshift);
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400253
254 /* The squared magnitude term gets added anyway, so we might as well
255 add it outside the loop */
Jean-Marc Valin0ec7c142008-09-22 10:25:46 -0400256 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400257 j=0;
258 do {
259 celt_word16_t Rxy, Ryy, Ryp;
260 celt_word16_t num;
261 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500262 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400263 /* Temporary sums of the new pulse(s) */
264 Rxy = ROUND16(MAC16_16(xy, s,X[j]), 14);
265 /* We're multiplying y[j] by two so we don't have to do it here */
266 Ryy = ROUND16(MAC16_16(yy, s,y[j]), 14);
267 Ryp = ROUND16(MAC16_16(yp, s,P[j]), 14);
268
269 /* Compute the gain such that ||p + g*y|| = 1
270 ...but instead, we compute g*Ryy to avoid dividing */
271 g = celt_psqrt(MULT16_16(Ryp,Ryp) + MULT16_16(Ryy,QCONST16(1.f,14)-Rpp)) - Ryp;
272 /* Knowing that gain, what's the error: (x-g*y)^2
273 (result is negated and we discard x^2 because it's constant) */
274 /* score = 2*g*Rxy - g*g*Ryy;*/
275#ifdef FIXED_POINT
276 /* No need to multiply Rxy by 2 because we did it earlier */
277 num = MULT16_16_Q15(ADD16(SUB16(Rxy,g),Rxy),g);
278#else
279 num = g*(2*Rxy-g);
280#endif
281 if (MULT16_16(best_den, num) > MULT16_16(Ryy, best_num))
282 {
283 best_den = Ryy;
284 best_num = num;
285 best_id = j;
286 }
287 } while (++j<N);
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500288 iy[best_id] += 1;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400289 }
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500290 j=0;
291 do {
292 P[j] = MULT16_16(signx[j],P[j]);
293 X[j] = MULT16_16(signx[j],X[j]);
294 if (signx[j] < 0)
295 iy[j] = -iy[j];
296 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100297 encode_pulses(iy, N, K, enc);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100298
Jean-Marc Valina4833ff2008-01-10 15:34:00 +1100299 /* Recompute the gain in one pass to reduce the encoder-decoder mismatch
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100300 due to the recursive computation used in quantisation. */
301 mix_pitch_and_residual(iy, X, N, K, P);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100302 RESTORE_STACK;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100303}
304
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100305
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +1100306/** Decode pulse vector and combine the result with the pitch vector to produce
307 the final normalised signal in the current band. */
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100308void alg_unquant(celt_norm_t *X, int N, int K, celt_norm_t *P, ec_dec *dec)
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100309{
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100310 VARDECL(int, iy);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100311 SAVE_STACK;
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +1100312 ALLOC(iy, N, int);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100313 decode_pulses(iy, N, K, dec);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100314 mix_pitch_and_residual(iy, X, N, K, P);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100315 RESTORE_STACK;
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100316}
317
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400318celt_word16_t renormalise_vector(celt_norm_t *X, celt_word16_t value, int N, int stride)
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400319{
320 int i;
321 celt_word32_t E = EPSILON;
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400322 celt_word16_t rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400323 celt_word16_t g;
324 celt_norm_t *xptr = X;
325 for (i=0;i<N;i++)
326 {
327 E = MAC16_16(E, *xptr, *xptr);
328 xptr += stride;
329 }
330
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400331 rE = celt_sqrt(E);
Jean-Marc Valincd29b022009-07-01 09:59:21 -0400332#ifdef FIXED_POINT
333 if (rE <= 128)
334 g = Q15ONE;
335 else
336#endif
337 g = MULT16_16_Q15(value,celt_rcp(SHL32(rE,9)));
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400338 xptr = X;
339 for (i=0;i<N;i++)
340 {
341 *xptr = PSHR32(MULT16_16(g, *xptr),8);
342 xptr += stride;
343 }
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400344 return rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400345}
346
347static void fold(const CELTMode *m, int N, celt_norm_t *Y, celt_norm_t * restrict P, int N0, int B)
Jean-Marc Valin4841a0a2007-12-03 13:54:30 +1100348{
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400349 int j;
Jean-Marc Valinba11d782008-04-21 21:59:37 +1000350 const int C = CHANNELS(m);
Jean-Marc Valin9edb7b42009-06-15 11:22:01 -0400351 int id = (N0*C) % (C*B);
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400352 /* Here, we assume that id will never be greater than N0, i.e. that
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400353 no band is wider than N0. In the unlikely case it happens, we set
354 everything to zero */
Jean-Marc Valin4e5b7bc2009-07-03 15:09:07 -0400355 /*{
356 int offset = (N0*C - (id+C*N))/2;
357 if (offset > C*N0/16)
358 offset = C*N0/16;
359 offset -= offset % (C*B);
360 if (offset < 0)
361 offset = 0;
362 //printf ("%d\n", offset);
363 id += offset;
364 }*/
Jean-Marc Valin9edb7b42009-06-15 11:22:01 -0400365 if (id+C*N>N0*C)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400366 for (j=0;j<C*N;j++)
367 P[j] = 0;
368 else
369 for (j=0;j<C*N;j++)
370 P[j] = Y[id++];
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400371}
372
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400373void intra_fold(const CELTMode *m, celt_norm_t * restrict x, int N, int *pulses, celt_norm_t *Y, celt_norm_t * restrict P, int N0, int B)
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400374{
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400375 int c;
Jean-Marc Valin9455d1b2008-03-07 17:17:37 +1100376 celt_word16_t pred_gain;
Jean-Marc Valinba11d782008-04-21 21:59:37 +1000377 const int C = CHANNELS(m);
Jean-Marc Valin896471d2008-11-06 21:55:41 -0500378
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400379 fold(m, N, Y, P, N0, B);
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400380 c=0;
381 do {
382 int K = pulses[c];
383 if (K==0)
384 pred_gain = Q15ONE;
385 else
386 pred_gain = celt_div((celt_word32_t)MULT16_16(Q15_ONE,N),(celt_word32_t)(N+2*K*(K+1)));
387
388 renormalise_vector(P+c, pred_gain, N, C);
389 } while (++c < C);
Jean-Marc Valin0e20ca02008-02-11 15:33:53 +1100390}
391