annotate src/opus-1.3/celt/vq.c @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 4664ac0c1032
children
rev   line source
cannam@154 1 /* Copyright (c) 2007-2008 CSIRO
cannam@154 2 Copyright (c) 2007-2009 Xiph.Org Foundation
cannam@154 3 Written by Jean-Marc Valin */
cannam@154 4 /*
cannam@154 5 Redistribution and use in source and binary forms, with or without
cannam@154 6 modification, are permitted provided that the following conditions
cannam@154 7 are met:
cannam@154 8
cannam@154 9 - Redistributions of source code must retain the above copyright
cannam@154 10 notice, this list of conditions and the following disclaimer.
cannam@154 11
cannam@154 12 - Redistributions in binary form must reproduce the above copyright
cannam@154 13 notice, this list of conditions and the following disclaimer in the
cannam@154 14 documentation and/or other materials provided with the distribution.
cannam@154 15
cannam@154 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
cannam@154 17 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
cannam@154 18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
cannam@154 19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
cannam@154 20 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
cannam@154 21 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
cannam@154 22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
cannam@154 23 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
cannam@154 24 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
cannam@154 25 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
cannam@154 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cannam@154 27 */
cannam@154 28
cannam@154 29 #ifdef HAVE_CONFIG_H
cannam@154 30 #include "config.h"
cannam@154 31 #endif
cannam@154 32
cannam@154 33 #include "mathops.h"
cannam@154 34 #include "cwrs.h"
cannam@154 35 #include "vq.h"
cannam@154 36 #include "arch.h"
cannam@154 37 #include "os_support.h"
cannam@154 38 #include "bands.h"
cannam@154 39 #include "rate.h"
cannam@154 40 #include "pitch.h"
cannam@154 41
cannam@154 42 #ifndef OVERRIDE_vq_exp_rotation1
cannam@154 43 static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
cannam@154 44 {
cannam@154 45 int i;
cannam@154 46 opus_val16 ms;
cannam@154 47 celt_norm *Xptr;
cannam@154 48 Xptr = X;
cannam@154 49 ms = NEG16(s);
cannam@154 50 for (i=0;i<len-stride;i++)
cannam@154 51 {
cannam@154 52 celt_norm x1, x2;
cannam@154 53 x1 = Xptr[0];
cannam@154 54 x2 = Xptr[stride];
cannam@154 55 Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
cannam@154 56 *Xptr++ = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
cannam@154 57 }
cannam@154 58 Xptr = &X[len-2*stride-1];
cannam@154 59 for (i=len-2*stride-1;i>=0;i--)
cannam@154 60 {
cannam@154 61 celt_norm x1, x2;
cannam@154 62 x1 = Xptr[0];
cannam@154 63 x2 = Xptr[stride];
cannam@154 64 Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15));
cannam@154 65 *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
cannam@154 66 }
cannam@154 67 }
cannam@154 68 #endif /* OVERRIDE_vq_exp_rotation1 */
cannam@154 69
cannam@154 70 void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
cannam@154 71 {
cannam@154 72 static const int SPREAD_FACTOR[3]={15,10,5};
cannam@154 73 int i;
cannam@154 74 opus_val16 c, s;
cannam@154 75 opus_val16 gain, theta;
cannam@154 76 int stride2=0;
cannam@154 77 int factor;
cannam@154 78
cannam@154 79 if (2*K>=len || spread==SPREAD_NONE)
cannam@154 80 return;
cannam@154 81 factor = SPREAD_FACTOR[spread-1];
cannam@154 82
cannam@154 83 gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
cannam@154 84 theta = HALF16(MULT16_16_Q15(gain,gain));
cannam@154 85
cannam@154 86 c = celt_cos_norm(EXTEND32(theta));
cannam@154 87 s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
cannam@154 88
cannam@154 89 if (len>=8*stride)
cannam@154 90 {
cannam@154 91 stride2 = 1;
cannam@154 92 /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
cannam@154 93 It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
cannam@154 94 while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
cannam@154 95 stride2++;
cannam@154 96 }
cannam@154 97 /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
cannam@154 98 extract_collapse_mask().*/
cannam@154 99 len = celt_udiv(len, stride);
cannam@154 100 for (i=0;i<stride;i++)
cannam@154 101 {
cannam@154 102 if (dir < 0)
cannam@154 103 {
cannam@154 104 if (stride2)
cannam@154 105 exp_rotation1(X+i*len, len, stride2, s, c);
cannam@154 106 exp_rotation1(X+i*len, len, 1, c, s);
cannam@154 107 } else {
cannam@154 108 exp_rotation1(X+i*len, len, 1, c, -s);
cannam@154 109 if (stride2)
cannam@154 110 exp_rotation1(X+i*len, len, stride2, s, -c);
cannam@154 111 }
cannam@154 112 }
cannam@154 113 }
cannam@154 114
cannam@154 115 /** Takes the pitch vector and the decoded residual vector, computes the gain
cannam@154 116 that will give ||p+g*y||=1 and mixes the residual with the pitch. */
cannam@154 117 static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X,
cannam@154 118 int N, opus_val32 Ryy, opus_val16 gain)
cannam@154 119 {
cannam@154 120 int i;
cannam@154 121 #ifdef FIXED_POINT
cannam@154 122 int k;
cannam@154 123 #endif
cannam@154 124 opus_val32 t;
cannam@154 125 opus_val16 g;
cannam@154 126
cannam@154 127 #ifdef FIXED_POINT
cannam@154 128 k = celt_ilog2(Ryy)>>1;
cannam@154 129 #endif
cannam@154 130 t = VSHR32(Ryy, 2*(k-7));
cannam@154 131 g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
cannam@154 132
cannam@154 133 i=0;
cannam@154 134 do
cannam@154 135 X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
cannam@154 136 while (++i < N);
cannam@154 137 }
cannam@154 138
cannam@154 139 static unsigned extract_collapse_mask(int *iy, int N, int B)
cannam@154 140 {
cannam@154 141 unsigned collapse_mask;
cannam@154 142 int N0;
cannam@154 143 int i;
cannam@154 144 if (B<=1)
cannam@154 145 return 1;
cannam@154 146 /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
cannam@154 147 exp_rotation().*/
cannam@154 148 N0 = celt_udiv(N, B);
cannam@154 149 collapse_mask = 0;
cannam@154 150 i=0; do {
cannam@154 151 int j;
cannam@154 152 unsigned tmp=0;
cannam@154 153 j=0; do {
cannam@154 154 tmp |= iy[i*N0+j];
cannam@154 155 } while (++j<N0);
cannam@154 156 collapse_mask |= (tmp!=0)<<i;
cannam@154 157 } while (++i<B);
cannam@154 158 return collapse_mask;
cannam@154 159 }
cannam@154 160
cannam@154 161 opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch)
cannam@154 162 {
cannam@154 163 VARDECL(celt_norm, y);
cannam@154 164 VARDECL(int, signx);
cannam@154 165 int i, j;
cannam@154 166 int pulsesLeft;
cannam@154 167 opus_val32 sum;
cannam@154 168 opus_val32 xy;
cannam@154 169 opus_val16 yy;
cannam@154 170 SAVE_STACK;
cannam@154 171
cannam@154 172 (void)arch;
cannam@154 173 ALLOC(y, N, celt_norm);
cannam@154 174 ALLOC(signx, N, int);
cannam@154 175
cannam@154 176 /* Get rid of the sign */
cannam@154 177 sum = 0;
cannam@154 178 j=0; do {
cannam@154 179 signx[j] = X[j]<0;
cannam@154 180 /* OPT: Make sure the compiler doesn't use a branch on ABS16(). */
cannam@154 181 X[j] = ABS16(X[j]);
cannam@154 182 iy[j] = 0;
cannam@154 183 y[j] = 0;
cannam@154 184 } while (++j<N);
cannam@154 185
cannam@154 186 xy = yy = 0;
cannam@154 187
cannam@154 188 pulsesLeft = K;
cannam@154 189
cannam@154 190 /* Do a pre-search by projecting on the pyramid */
cannam@154 191 if (K > (N>>1))
cannam@154 192 {
cannam@154 193 opus_val16 rcp;
cannam@154 194 j=0; do {
cannam@154 195 sum += X[j];
cannam@154 196 } while (++j<N);
cannam@154 197
cannam@154 198 /* If X is too small, just replace it with a pulse at 0 */
cannam@154 199 #ifdef FIXED_POINT
cannam@154 200 if (sum <= K)
cannam@154 201 #else
cannam@154 202 /* Prevents infinities and NaNs from causing too many pulses
cannam@154 203 to be allocated. 64 is an approximation of infinity here. */
cannam@154 204 if (!(sum > EPSILON && sum < 64))
cannam@154 205 #endif
cannam@154 206 {
cannam@154 207 X[0] = QCONST16(1.f,14);
cannam@154 208 j=1; do
cannam@154 209 X[j]=0;
cannam@154 210 while (++j<N);
cannam@154 211 sum = QCONST16(1.f,14);
cannam@154 212 }
cannam@154 213 #ifdef FIXED_POINT
cannam@154 214 rcp = EXTRACT16(MULT16_32_Q16(K, celt_rcp(sum)));
cannam@154 215 #else
cannam@154 216 /* Using K+e with e < 1 guarantees we cannot get more than K pulses. */
cannam@154 217 rcp = EXTRACT16(MULT16_32_Q16(K+0.8f, celt_rcp(sum)));
cannam@154 218 #endif
cannam@154 219 j=0; do {
cannam@154 220 #ifdef FIXED_POINT
cannam@154 221 /* It's really important to round *towards zero* here */
cannam@154 222 iy[j] = MULT16_16_Q15(X[j],rcp);
cannam@154 223 #else
cannam@154 224 iy[j] = (int)floor(rcp*X[j]);
cannam@154 225 #endif
cannam@154 226 y[j] = (celt_norm)iy[j];
cannam@154 227 yy = MAC16_16(yy, y[j],y[j]);
cannam@154 228 xy = MAC16_16(xy, X[j],y[j]);
cannam@154 229 y[j] *= 2;
cannam@154 230 pulsesLeft -= iy[j];
cannam@154 231 } while (++j<N);
cannam@154 232 }
cannam@154 233 celt_sig_assert(pulsesLeft>=0);
cannam@154 234
cannam@154 235 /* This should never happen, but just in case it does (e.g. on silence)
cannam@154 236 we fill the first bin with pulses. */
cannam@154 237 #ifdef FIXED_POINT_DEBUG
cannam@154 238 celt_sig_assert(pulsesLeft<=N+3);
cannam@154 239 #endif
cannam@154 240 if (pulsesLeft > N+3)
cannam@154 241 {
cannam@154 242 opus_val16 tmp = (opus_val16)pulsesLeft;
cannam@154 243 yy = MAC16_16(yy, tmp, tmp);
cannam@154 244 yy = MAC16_16(yy, tmp, y[0]);
cannam@154 245 iy[0] += pulsesLeft;
cannam@154 246 pulsesLeft=0;
cannam@154 247 }
cannam@154 248
cannam@154 249 for (i=0;i<pulsesLeft;i++)
cannam@154 250 {
cannam@154 251 opus_val16 Rxy, Ryy;
cannam@154 252 int best_id;
cannam@154 253 opus_val32 best_num;
cannam@154 254 opus_val16 best_den;
cannam@154 255 #ifdef FIXED_POINT
cannam@154 256 int rshift;
cannam@154 257 #endif
cannam@154 258 #ifdef FIXED_POINT
cannam@154 259 rshift = 1+celt_ilog2(K-pulsesLeft+i+1);
cannam@154 260 #endif
cannam@154 261 best_id = 0;
cannam@154 262 /* The squared magnitude term gets added anyway, so we might as well
cannam@154 263 add it outside the loop */
cannam@154 264 yy = ADD16(yy, 1);
cannam@154 265
cannam@154 266 /* Calculations for position 0 are out of the loop, in part to reduce
cannam@154 267 mispredicted branches (since the if condition is usually false)
cannam@154 268 in the loop. */
cannam@154 269 /* Temporary sums of the new pulse(s) */
cannam@154 270 Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[0])),rshift));
cannam@154 271 /* We're multiplying y[j] by two so we don't have to do it here */
cannam@154 272 Ryy = ADD16(yy, y[0]);
cannam@154 273
cannam@154 274 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
cannam@154 275 Rxy is positive because the sign is pre-computed) */
cannam@154 276 Rxy = MULT16_16_Q15(Rxy,Rxy);
cannam@154 277 best_den = Ryy;
cannam@154 278 best_num = Rxy;
cannam@154 279 j=1;
cannam@154 280 do {
cannam@154 281 /* Temporary sums of the new pulse(s) */
cannam@154 282 Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
cannam@154 283 /* We're multiplying y[j] by two so we don't have to do it here */
cannam@154 284 Ryy = ADD16(yy, y[j]);
cannam@154 285
cannam@154 286 /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
cannam@154 287 Rxy is positive because the sign is pre-computed) */
cannam@154 288 Rxy = MULT16_16_Q15(Rxy,Rxy);
cannam@154 289 /* The idea is to check for num/den >= best_num/best_den, but that way
cannam@154 290 we can do it without any division */
cannam@154 291 /* OPT: It's not clear whether a cmov is faster than a branch here
cannam@154 292 since the condition is more often false than true and using
cannam@154 293 a cmov introduces data dependencies across iterations. The optimal
cannam@154 294 choice may be architecture-dependent. */
cannam@154 295 if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)))
cannam@154 296 {
cannam@154 297 best_den = Ryy;
cannam@154 298 best_num = Rxy;
cannam@154 299 best_id = j;
cannam@154 300 }
cannam@154 301 } while (++j<N);
cannam@154 302
cannam@154 303 /* Updating the sums of the new pulse(s) */
cannam@154 304 xy = ADD32(xy, EXTEND32(X[best_id]));
cannam@154 305 /* We're multiplying y[j] by two so we don't have to do it here */
cannam@154 306 yy = ADD16(yy, y[best_id]);
cannam@154 307
cannam@154 308 /* Only now that we've made the final choice, update y/iy */
cannam@154 309 /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
cannam@154 310 y[best_id] += 2;
cannam@154 311 iy[best_id]++;
cannam@154 312 }
cannam@154 313
cannam@154 314 /* Put the original sign back */
cannam@154 315 j=0;
cannam@154 316 do {
cannam@154 317 /*iy[j] = signx[j] ? -iy[j] : iy[j];*/
cannam@154 318 /* OPT: The is more likely to be compiled without a branch than the code above
cannam@154 319 but has the same performance otherwise. */
cannam@154 320 iy[j] = (iy[j]^-signx[j]) + signx[j];
cannam@154 321 } while (++j<N);
cannam@154 322 RESTORE_STACK;
cannam@154 323 return yy;
cannam@154 324 }
cannam@154 325
cannam@154 326 unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc,
cannam@154 327 opus_val16 gain, int resynth, int arch)
cannam@154 328 {
cannam@154 329 VARDECL(int, iy);
cannam@154 330 opus_val16 yy;
cannam@154 331 unsigned collapse_mask;
cannam@154 332 SAVE_STACK;
cannam@154 333
cannam@154 334 celt_assert2(K>0, "alg_quant() needs at least one pulse");
cannam@154 335 celt_assert2(N>1, "alg_quant() needs at least two dimensions");
cannam@154 336
cannam@154 337 /* Covers vectorization by up to 4. */
cannam@154 338 ALLOC(iy, N+3, int);
cannam@154 339
cannam@154 340 exp_rotation(X, N, 1, B, K, spread);
cannam@154 341
cannam@154 342 yy = op_pvq_search(X, iy, K, N, arch);
cannam@154 343
cannam@154 344 encode_pulses(iy, N, K, enc);
cannam@154 345
cannam@154 346 if (resynth)
cannam@154 347 {
cannam@154 348 normalise_residual(iy, X, N, yy, gain);
cannam@154 349 exp_rotation(X, N, -1, B, K, spread);
cannam@154 350 }
cannam@154 351
cannam@154 352 collapse_mask = extract_collapse_mask(iy, N, B);
cannam@154 353 RESTORE_STACK;
cannam@154 354 return collapse_mask;
cannam@154 355 }
cannam@154 356
cannam@154 357 /** Decode pulse vector and combine the result with the pitch vector to produce
cannam@154 358 the final normalised signal in the current band. */
cannam@154 359 unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
cannam@154 360 ec_dec *dec, opus_val16 gain)
cannam@154 361 {
cannam@154 362 opus_val32 Ryy;
cannam@154 363 unsigned collapse_mask;
cannam@154 364 VARDECL(int, iy);
cannam@154 365 SAVE_STACK;
cannam@154 366
cannam@154 367 celt_assert2(K>0, "alg_unquant() needs at least one pulse");
cannam@154 368 celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
cannam@154 369 ALLOC(iy, N, int);
cannam@154 370 Ryy = decode_pulses(iy, N, K, dec);
cannam@154 371 normalise_residual(iy, X, N, Ryy, gain);
cannam@154 372 exp_rotation(X, N, -1, B, K, spread);
cannam@154 373 collapse_mask = extract_collapse_mask(iy, N, B);
cannam@154 374 RESTORE_STACK;
cannam@154 375 return collapse_mask;
cannam@154 376 }
cannam@154 377
cannam@154 378 #ifndef OVERRIDE_renormalise_vector
cannam@154 379 void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch)
cannam@154 380 {
cannam@154 381 int i;
cannam@154 382 #ifdef FIXED_POINT
cannam@154 383 int k;
cannam@154 384 #endif
cannam@154 385 opus_val32 E;
cannam@154 386 opus_val16 g;
cannam@154 387 opus_val32 t;
cannam@154 388 celt_norm *xptr;
cannam@154 389 E = EPSILON + celt_inner_prod(X, X, N, arch);
cannam@154 390 #ifdef FIXED_POINT
cannam@154 391 k = celt_ilog2(E)>>1;
cannam@154 392 #endif
cannam@154 393 t = VSHR32(E, 2*(k-7));
cannam@154 394 g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
cannam@154 395
cannam@154 396 xptr = X;
cannam@154 397 for (i=0;i<N;i++)
cannam@154 398 {
cannam@154 399 *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
cannam@154 400 xptr++;
cannam@154 401 }
cannam@154 402 /*return celt_sqrt(E);*/
cannam@154 403 }
cannam@154 404 #endif /* OVERRIDE_renormalise_vector */
cannam@154 405
cannam@154 406 int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int arch)
cannam@154 407 {
cannam@154 408 int i;
cannam@154 409 int itheta;
cannam@154 410 opus_val16 mid, side;
cannam@154 411 opus_val32 Emid, Eside;
cannam@154 412
cannam@154 413 Emid = Eside = EPSILON;
cannam@154 414 if (stereo)
cannam@154 415 {
cannam@154 416 for (i=0;i<N;i++)
cannam@154 417 {
cannam@154 418 celt_norm m, s;
cannam@154 419 m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
cannam@154 420 s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
cannam@154 421 Emid = MAC16_16(Emid, m, m);
cannam@154 422 Eside = MAC16_16(Eside, s, s);
cannam@154 423 }
cannam@154 424 } else {
cannam@154 425 Emid += celt_inner_prod(X, X, N, arch);
cannam@154 426 Eside += celt_inner_prod(Y, Y, N, arch);
cannam@154 427 }
cannam@154 428 mid = celt_sqrt(Emid);
cannam@154 429 side = celt_sqrt(Eside);
cannam@154 430 #ifdef FIXED_POINT
cannam@154 431 /* 0.63662 = 2/pi */
cannam@154 432 itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
cannam@154 433 #else
cannam@154 434 itheta = (int)floor(.5f+16384*0.63662f*fast_atan2f(side,mid));
cannam@154 435 #endif
cannam@154 436
cannam@154 437 return itheta;
cannam@154 438 }