blob: 1d14c2c17d44bad5254adcb8933b344210a8cbde [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 Valina7750b92009-08-29 22:52:03 +010043static void exp_rotation(celt_norm_t *X, int len, int dir, int stride, int K)
44{
45 int i, k, iter;
46 celt_word16_t c, s;
47 celt_word16_t gain, theta;
48 celt_norm_t *Xptr;
49 gain = celt_div((celt_word32_t)MULT16_16(Q15_ONE,len),(celt_word32_t)(len+2*K*((K>>1)+1)));
50 /* FIXME: Make that HALF16 instead of HALF32 */
51 theta = SUB16(Q15ONE, HALF32(MULT16_16_Q15(gain,gain)));
52 /*if (len==30)
53 {
54 for (i=0;i<len;i++)
55 X[i] = 0;
56 X[14] = 1;
57}*/
58 c = celt_cos_norm(EXTEND32(theta));
59 s = dir*celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
60 if (stride == 1)
61 stride = 2;
62 iter = 1;
63 for (k=0;k<iter;k++)
64 {
65 /* We could use MULT16_16_P15 instead of MULT16_16_Q15 for more accuracy,
66 but at this point, I really don't think it's necessary */
67 Xptr = X;
68 for (i=0;i<len-stride;i++)
69 {
70 celt_norm_t x1, x2;
71 x1 = Xptr[0];
72 x2 = Xptr[stride];
73 Xptr[stride] = MULT16_16_Q15(c,x2) + MULT16_16_Q15(s,x1);
74 *Xptr++ = MULT16_16_Q15(c,x1) - MULT16_16_Q15(s,x2);
75 }
76 Xptr = &X[len-2*stride-1];
77 for (i=len-2*stride-1;i>=0;i--)
78 {
79 celt_norm_t x1, x2;
80 x1 = Xptr[0];
81 x2 = Xptr[stride];
82 Xptr[stride] = MULT16_16_Q15(c,x2) + MULT16_16_Q15(s,x1);
83 *Xptr-- = MULT16_16_Q15(c,x1) - MULT16_16_Q15(s,x2);
84 }
85 }
86 /*if (len==30)
87 {
88 for (i=0;i<len;i++)
89 printf ("%f ", X[i]);
90 printf ("\n");
91 exit(0);
92}*/
93}
94
95
Jean-Marc Valin35a1f882008-03-26 10:34:23 +110096/** Takes the pitch vector and the decoded residual vector, computes the gain
97 that will give ||p+g*y||=1 and mixes the residual with the pitch. */
Jean-Marc Valin5de868c2008-03-25 22:38:58 +110098static 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 +110099{
100 int i;
Jean-Marc Valinb50c5412008-02-27 17:05:43 +1100101 celt_word32_t Ryp, Ryy, Rpp;
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400102 celt_word16_t ryp, ryy, rpp;
Jean-Marc Valina847b772008-02-27 17:46:49 +1100103 celt_word32_t g;
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100104 VARDECL(celt_norm_t, y);
Jean-Marc Valind9de5932008-03-05 08:11:57 +1100105#ifdef FIXED_POINT
106 int yshift;
107#endif
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100108 SAVE_STACK;
Jean-Marc Valind17edd32008-02-27 16:52:30 +1100109#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100110 yshift = 13-celt_ilog2(K);
Jean-Marc Valind17edd32008-02-27 16:52:30 +1100111#endif
112 ALLOC(y, N, celt_norm_t);
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100113
Jean-Marc Valinb50c5412008-02-27 17:05:43 +1100114 Rpp = 0;
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000115 i=0;
116 do {
Jean-Marc Valinb50c5412008-02-27 17:05:43 +1100117 Rpp = MAC16_16(Rpp,P[i],P[i]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100118 y[i] = SHL16(iy[i],yshift);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000119 } while (++i < N);
120
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100121 Ryp = 0;
Jean-Marc Valinb50c5412008-02-27 17:05:43 +1100122 Ryy = 0;
Jean-Marc Valindf7ab432008-03-26 18:03:22 +1100123 /* If this doesn't generate a dual MAC (on supported archs), fire the compiler guy */
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000124 i=0;
125 do {
Jean-Marc Valindf7ab432008-03-26 18:03:22 +1100126 Ryp = MAC16_16(Ryp, y[i], P[i]);
127 Ryy = MAC16_16(Ryy, y[i], y[i]);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000128 } while (++i < N);
129
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400130 ryp = ROUND16(Ryp,14);
131 ryy = ROUND16(Ryy,14);
132 rpp = ROUND16(Rpp,14);
Jean-Marc Valin1ca07222008-02-27 17:23:04 +1100133 /* g = (sqrt(Ryp^2 + Ryy - Rpp*Ryy)-Ryp)/Ryy */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400134 g = MULT16_32_Q15(celt_sqrt(MAC16_16(Ryy, ryp,ryp) - MULT16_16(ryy,rpp)) - ryp,
135 celt_rcp(SHR32(Ryy,9)));
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100136
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000137 i=0;
138 do
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400139 X[i] = ADD16(P[i], ROUND16(MULT16_16(y[i], g),11));
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000140 while (++i < N);
141
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100142 RESTORE_STACK;
Jean-Marc Valind4018c32008-02-27 10:09:48 +1100143}
144
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100145
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100146void alg_quant(celt_norm_t *X, celt_mask_t *W, int N, int K, int spread, celt_norm_t *P, ec_enc *enc)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100147{
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100148 VARDECL(celt_norm_t, y);
149 VARDECL(int, iy);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400150 VARDECL(celt_word16_t, signx);
Jean-Marc Valin6ea8bae2008-04-15 08:01:33 +1000151 int j, is;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100152 celt_word16_t s;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100153 int pulsesLeft;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100154 celt_word32_t sum;
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100155 celt_word32_t xy, yy, yp;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100156 celt_word16_t Rpp;
Jean-Marc Valinf9584772008-03-27 12:22:44 +1100157 int N_1; /* Inverse of N, in Q14 format (even for float) */
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100158#ifdef FIXED_POINT
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100159 int yshift;
160#endif
161 SAVE_STACK;
162
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400163 K = get_pulses(K);
Jean-Marc Valind748cd52008-03-01 07:27:03 +1100164#ifdef FIXED_POINT
Jean-Marc Valin98c86c72008-03-27 08:40:45 +1100165 yshift = 13-celt_ilog2(K);
Jean-Marc Valinf675adc2008-02-28 12:15:17 +1100166#endif
Jean-Marc Valin9d8d9b32008-02-27 16:17:39 +1100167
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100168 ALLOC(y, N, celt_norm_t);
169 ALLOC(iy, N, int);
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400170 ALLOC(signx, N, celt_word16_t);
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100171 N_1 = 512/N;
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100172
173 if (spread)
174 exp_rotation(X, N, 1, spread, K);
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000175
176 sum = 0;
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000177 j=0; do {
Jean-Marc Valinbf2d6482008-05-23 16:57:34 +1000178 X[j] -= P[j];
Jean-Marc Valin49134382008-03-25 16:07:05 +1100179 if (X[j]>0)
180 signx[j]=1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500181 else {
Jean-Marc Valin49134382008-03-25 16:07:05 +1100182 signx[j]=-1;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500183 X[j]=-X[j];
184 P[j]=-P[j];
185 }
Jean-Marc Valin3d152a52008-04-15 07:46:48 +1000186 iy[j] = 0;
187 y[j] = 0;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100188 sum = MAC16_16(sum, P[j],P[j]);
Jean-Marc Valindff9b7e2008-04-21 11:43:51 +1000189 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100190 Rpp = ROUND16(sum, NORM_SHIFT);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100191
Jean-Marc Valin4ff068e2008-03-15 23:34:39 +1100192 celt_assert2(Rpp<=NORM_SCALING, "Rpp should never have a norm greater than unity");
Jean-Marc Valinb60340f2008-02-26 15:41:51 +1100193
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100194 xy = yy = yp = 0;
Jean-Marc Valin0d587d82008-02-14 21:29:50 +1100195
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100196 pulsesLeft = K;
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500197
198 /* Do a pre-search by projecting on the pyramid */
Jean-Marc Valina733f082008-12-04 22:52:26 -0500199 if (K > (N>>1))
200 {
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500201 celt_word16_t rcp;
Gregory Maxwell61832f12008-12-22 18:15:42 -0500202 sum=0;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500203 j=0; do {
204 sum += X[j];
205 } while (++j<N);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400206
207#ifdef FIXED_POINT
208 if (sum <= K)
209#else
210 if (sum <= EPSILON)
211#endif
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500212 {
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400213 X[0] = QCONST16(1.f,14);
Jean-Marc Valin6d454d82009-06-30 10:31:00 -0400214 j=1; do
215 X[j]=0;
216 while (++j<N);
Jean-Marc Valinda1156a2009-07-01 01:27:48 -0400217 sum = QCONST16(1.f,14);
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500218 }
219 /* Do we have sufficient accuracy here? */
220 rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
Jean-Marc Valina733f082008-12-04 22:52:26 -0500221 j=0; do {
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500222#ifdef FIXED_POINT
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500223 /* It's really important to round *towards zero* here */
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500224 iy[j] = MULT16_16_Q15(X[j],rcp);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500225#else
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500226 iy[j] = floor(rcp*X[j]);
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500227#endif
Jean-Marc Valinc7635b42008-12-04 23:26:32 -0500228 y[j] = SHL16(iy[j],yshift);
229 yy = MAC16_16(yy, y[j],y[j]);
230 xy = MAC16_16(xy, X[j],y[j]);
Jean-Marc Valina733f082008-12-04 22:52:26 -0500231 yp += P[j]*y[j];
Jean-Marc Valin09dc5a12008-12-05 00:28:28 -0500232 y[j] *= 2;
Jean-Marc Valina733f082008-12-04 22:52:26 -0500233 pulsesLeft -= iy[j];
234 } while (++j<N);
235 }
Jean-Marc Valin137241d2008-12-06 23:44:55 -0500236 celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500237
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400238 while (pulsesLeft > 1)
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100239 {
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100240 int pulsesAtOnce=1;
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100241 int best_id;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000242 celt_word16_t magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400243 celt_word32_t best_num = -VERY_LARGE16;
244 celt_word16_t best_den = 0;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000245#ifdef FIXED_POINT
246 int rshift;
247#endif
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100248 /* Decide on how many pulses to find at once */
Jean-Marc Valin124d1cd2008-03-28 00:33:04 +1100249 pulsesAtOnce = (pulsesLeft*N_1)>>9; /* pulsesLeft/N */
Jean-Marc Valincab576e2008-02-12 17:21:14 +1100250 if (pulsesAtOnce<1)
251 pulsesAtOnce = 1;
Jean-Marc Valin0bc5f7f2008-04-20 17:16:18 +1000252#ifdef FIXED_POINT
253 rshift = yshift+1+celt_ilog2(K-pulsesLeft+pulsesAtOnce);
254#endif
Jean-Marc Valined317c92008-04-15 17:31:23 +1000255 magnitude = SHL16(pulsesAtOnce, yshift);
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100256
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100257 best_id = 0;
Jean-Marc Valined317c92008-04-15 17:31:23 +1000258 /* The squared magnitude term gets added anyway, so we might as well
259 add it outside the loop */
Jean-Marc Valin1dab60c2008-09-16 13:29:37 -0400260 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100261 /* Choose between fast and accurate strategy depending on where we are in the search */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000262 /* This should ensure that anything we can process will have a better score */
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400263 j=0;
264 do {
265 celt_word16_t Rxy, Ryy;
266 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500267 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400268 /* Temporary sums of the new pulse(s) */
269 Rxy = EXTRACT16(SHR32(MAC16_16(xy, s,X[j]),rshift));
270 /* We're multiplying y[j] by two so we don't have to do it here */
271 Ryy = EXTRACT16(SHR32(MAC16_16(yy, s,y[j]),rshift));
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100272
Jean-Marc Valined317c92008-04-15 17:31:23 +1000273 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400274 Rxy is positive because the sign is pre-computed) */
275 Rxy = MULT16_16_Q15(Rxy,Rxy);
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100276 /* The idea is to check for num/den >= best_num/best_den, but that way
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400277 we can do it without any division */
278 /* OPT: Make sure to use conditional moves here */
279 if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
280 {
281 best_den = Ryy;
282 best_num = Rxy;
283 best_id = j;
284 }
285 } while (++j<N);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100286
Jean-Marc Valin35a1f882008-03-26 10:34:23 +1100287 j = best_id;
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500288 is = pulsesAtOnce;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100289 s = SHL16(is, yshift);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100290
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100291 /* Updating the sums of the new pulse(s) */
292 xy = xy + MULT16_16(s,X[j]);
Jean-Marc Valined317c92008-04-15 17:31:23 +1000293 /* We're multiplying y[j] by two so we don't have to do it here */
294 yy = yy + MULT16_16(s,y[j]);
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100295 yp = yp + MULT16_16(s, P[j]);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100296
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100297 /* Only now that we've made the final choice, update y/iy */
Jean-Marc Valined317c92008-04-15 17:31:23 +1000298 /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
299 y[j] += 2*s;
Jean-Marc Valin44c63352008-03-25 21:28:40 +1100300 iy[j] += is;
Jean-Marc Valin846d4e22008-02-12 13:48:48 +1100301 pulsesLeft -= pulsesAtOnce;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100302 }
303
Jean-Marc Valin8256ed42008-12-12 20:50:56 -0500304 if (pulsesLeft > 0)
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400305 {
306 celt_word16_t g;
307 celt_word16_t best_num = -VERY_LARGE16;
308 celt_word16_t best_den = 0;
309 int best_id = 0;
Jean-Marc Valin0ec7c142008-09-22 10:25:46 -0400310 celt_word16_t magnitude = SHL16(1, yshift);
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400311
312 /* The squared magnitude term gets added anyway, so we might as well
313 add it outside the loop */
Jean-Marc Valin0ec7c142008-09-22 10:25:46 -0400314 yy = MAC16_16(yy, magnitude,magnitude);
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400315 j=0;
316 do {
317 celt_word16_t Rxy, Ryy, Ryp;
318 celt_word16_t num;
319 /* Select sign based on X[j] alone */
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500320 s = magnitude;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400321 /* Temporary sums of the new pulse(s) */
322 Rxy = ROUND16(MAC16_16(xy, s,X[j]), 14);
323 /* We're multiplying y[j] by two so we don't have to do it here */
324 Ryy = ROUND16(MAC16_16(yy, s,y[j]), 14);
325 Ryp = ROUND16(MAC16_16(yp, s,P[j]), 14);
326
327 /* Compute the gain such that ||p + g*y|| = 1
328 ...but instead, we compute g*Ryy to avoid dividing */
329 g = celt_psqrt(MULT16_16(Ryp,Ryp) + MULT16_16(Ryy,QCONST16(1.f,14)-Rpp)) - Ryp;
330 /* Knowing that gain, what's the error: (x-g*y)^2
331 (result is negated and we discard x^2 because it's constant) */
332 /* score = 2*g*Rxy - g*g*Ryy;*/
333#ifdef FIXED_POINT
334 /* No need to multiply Rxy by 2 because we did it earlier */
335 num = MULT16_16_Q15(ADD16(SUB16(Rxy,g),Rxy),g);
336#else
337 num = g*(2*Rxy-g);
338#endif
339 if (MULT16_16(best_den, num) > MULT16_16(Ryy, best_num))
340 {
341 best_den = Ryy;
342 best_num = num;
343 best_id = j;
344 }
345 } while (++j<N);
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500346 iy[best_id] += 1;
Jean-Marc Valin7bb339d2008-09-21 21:11:39 -0400347 }
Jean-Marc Valin6cde5dd2008-12-04 21:21:41 -0500348 j=0;
349 do {
350 P[j] = MULT16_16(signx[j],P[j]);
351 X[j] = MULT16_16(signx[j],X[j]);
352 if (signx[j] < 0)
353 iy[j] = -iy[j];
354 } while (++j<N);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100355 encode_pulses(iy, N, K, enc);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100356
Jean-Marc Valina4833ff2008-01-10 15:34:00 +1100357 /* Recompute the gain in one pass to reduce the encoder-decoder mismatch
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100358 due to the recursive computation used in quantisation. */
359 mix_pitch_and_residual(iy, X, N, K, P);
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100360 if (spread)
361 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100362 RESTORE_STACK;
Jean-Marc Valin41af4212007-11-30 18:35:37 +1100363}
364
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100365
Jean-Marc Valin879fbfd2008-02-20 17:17:13 +1100366/** Decode pulse vector and combine the result with the pitch vector to produce
367 the final normalised signal in the current band. */
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100368void alg_unquant(celt_norm_t *X, int N, int K, int spread, celt_norm_t *P, ec_dec *dec)
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100369{
Jean-Marc Valin31b79d12008-03-12 17:17:23 +1100370 VARDECL(int, iy);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100371 SAVE_STACK;
Jean-Marc Valin164a2292009-07-22 07:48:35 -0400372 K = get_pulses(K);
Jean-Marc Valin9a0bba12008-02-20 14:08:50 +1100373 ALLOC(iy, N, int);
Jean-Marc Valin5fa59952008-02-14 13:50:44 +1100374 decode_pulses(iy, N, K, dec);
Jean-Marc Valinbd718ba2008-03-25 14:15:41 +1100375 mix_pitch_and_residual(iy, X, N, K, P);
Jean-Marc Valina7750b92009-08-29 22:52:03 +0100376 if (spread)
377 exp_rotation(X, N, -1, spread, K);
Jean-Marc Valin8600f692008-02-29 15:14:12 +1100378 RESTORE_STACK;
Jean-Marc Valin0d227d82007-12-31 16:12:12 +1100379}
380
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400381celt_word16_t renormalise_vector(celt_norm_t *X, celt_word16_t value, int N, int stride)
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400382{
383 int i;
384 celt_word32_t E = EPSILON;
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400385 celt_word16_t rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400386 celt_word16_t g;
387 celt_norm_t *xptr = X;
388 for (i=0;i<N;i++)
389 {
390 E = MAC16_16(E, *xptr, *xptr);
391 xptr += stride;
392 }
393
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400394 rE = celt_sqrt(E);
Jean-Marc Valincd29b022009-07-01 09:59:21 -0400395#ifdef FIXED_POINT
396 if (rE <= 128)
397 g = Q15ONE;
398 else
399#endif
400 g = MULT16_16_Q15(value,celt_rcp(SHL32(rE,9)));
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400401 xptr = X;
402 for (i=0;i<N;i++)
403 {
404 *xptr = PSHR32(MULT16_16(g, *xptr),8);
405 xptr += stride;
406 }
Jean-Marc Valinca53b7c2009-03-26 20:23:14 -0400407 return rE;
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400408}
409
410static 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 +1100411{
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400412 int j;
Jean-Marc Valinba11d782008-04-21 21:59:37 +1000413 const int C = CHANNELS(m);
Jean-Marc Valin9edb7b42009-06-15 11:22:01 -0400414 int id = (N0*C) % (C*B);
Jean-Marc Valindf38f2b2008-07-20 20:36:54 -0400415 /* Here, we assume that id will never be greater than N0, i.e. that
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400416 no band is wider than N0. In the unlikely case it happens, we set
417 everything to zero */
Jean-Marc Valin4e5b7bc2009-07-03 15:09:07 -0400418 /*{
419 int offset = (N0*C - (id+C*N))/2;
420 if (offset > C*N0/16)
421 offset = C*N0/16;
422 offset -= offset % (C*B);
423 if (offset < 0)
424 offset = 0;
425 //printf ("%d\n", offset);
426 id += offset;
427 }*/
Jean-Marc Valin9edb7b42009-06-15 11:22:01 -0400428 if (id+C*N>N0*C)
Jean-Marc Valin5eef2642008-08-06 23:06:31 -0400429 for (j=0;j<C*N;j++)
430 P[j] = 0;
431 else
432 for (j=0;j<C*N;j++)
433 P[j] = Y[id++];
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400434}
435
Jean-Marc Valin3aa3afe2009-09-11 20:28:29 -0400436void intra_fold(const CELTMode *m, celt_norm_t * restrict x, int N, celt_norm_t *Y, celt_norm_t * restrict P, int N0, int B)
Jean-Marc Valin2c733062008-07-17 16:22:23 -0400437{
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400438 int c;
Jean-Marc Valinba11d782008-04-21 21:59:37 +1000439 const int C = CHANNELS(m);
Jean-Marc Valin896471d2008-11-06 21:55:41 -0500440
Jean-Marc Valin6361ad82008-07-20 23:14:31 -0400441 fold(m, N, Y, P, N0, B);
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400442 c=0;
443 do {
Jean-Marc Valin3aa3afe2009-09-11 20:28:29 -0400444 renormalise_vector(P+c, Q15ONE, N, C);
Jean-Marc Valin798ab382009-07-12 20:41:29 -0400445 } while (++c < C);
Jean-Marc Valin0e20ca02008-02-11 15:33:53 +1100446}
447