/** Decode pulse vector and combine the result with the pitch vector to produce * the final normalised signal in the current band. */ internal static uint alg_unquant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder dec, int gain) { int Ryy; uint collapse_mask; int[] iy = new int[N]; Inlines.OpusAssert(K > 0, "alg_unquant() needs at least one pulse"); Inlines.OpusAssert(N > 1, "alg_unquant() needs at least two dimensions"); Ryy = CWRS.decode_pulses(iy, N, K, dec); normalise_residual(iy, X, X_ptr, N, Ryy, gain); exp_rotation(X, X_ptr, N, -1, B, K, spread); collapse_mask = extract_collapse_mask(iy, N, B); return(collapse_mask); }
internal static uint alg_quant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc ) { int[] y = new int[N]; int[] iy = new int[N]; int[] signx = new int[N]; int i, j; int s; int pulsesLeft; int sum; int xy; int yy; uint collapse_mask; Inlines.OpusAssert(K > 0, "alg_quant() needs at least one pulse"); Inlines.OpusAssert(N > 1, "alg_quant() needs at least two dimensions"); exp_rotation(X, X_ptr, N, 1, B, K, spread); /* Get rid of the sign */ sum = 0; j = 0; do { int xpj = X_ptr + j; /* OPT: Make sure the following two lines result in conditional moves * rather than branches. */ signx[j] = X[xpj] > 0 ? 1 : -1; X[xpj] = Inlines.ABS16(X[xpj]); iy[j] = 0; y[j] = 0; } while (++j < N); xy = yy = 0; pulsesLeft = K; /* Do a pre-search by projecting on the pyramid */ if (K > (N >> 1)) { int rcp; j = 0; do { sum += X[X_ptr + j]; } while (++j < N); /* If X is too small, just replace it with a pulse at 0 */ /* Prevents infinities and NaNs from causing too many pulses * to be allocated. 64 is an approximation of infinity here. */ if (sum <= K) { X[X_ptr] = ((short)(0.5 + (1.0f) * (((int)1) << (14)))) /*Inlines.QCONST16(1.0f, 14)*/; j = X_ptr + 1; do { X[j] = 0; } while (++j < N + X_ptr); sum = ((short)(0.5 + (1.0f) * (((int)1) << (14)))) /*Inlines.QCONST16(1.0f, 14)*/; } rcp = Inlines.EXTRACT16(Inlines.MULT16_32_Q16((K - 1), Inlines.celt_rcp(sum))); j = 0; do { /* It's really important to round *towards zero* here */ iy[j] = Inlines.MULT16_16_Q15(X[X_ptr + j], rcp); y[j] = (int)iy[j]; yy = (Inlines.MAC16_16(yy, y[j], y[j])); xy = Inlines.MAC16_16(xy, X[X_ptr + j], y[j]); y[j] *= 2; pulsesLeft -= iy[j]; } while (++j < N); } Inlines.OpusAssert(pulsesLeft >= 1, "Allocated too many pulses in the quick pass"); /* This should never happen, but just in case it does (e.g. on silence) * we fill the first bin with pulses. */ if (pulsesLeft > N + 3) { int tmp = (int)pulsesLeft; yy = (Inlines.MAC16_16(yy, tmp, tmp)); yy = (Inlines.MAC16_16(yy, tmp, y[0])); iy[0] += pulsesLeft; pulsesLeft = 0; } s = 1; for (i = 0; i < pulsesLeft; i++) { int best_id; int best_num = 0 - CeltConstants.VERY_LARGE16; int best_den = 0; int rshift = 1 + Inlines.celt_ilog2(K - pulsesLeft + i + 1); best_id = 0; /* The squared magnitude term gets added anyway, so we might as well * add it outside the loop */ yy = Inlines.ADD16(yy, 1); // opus bug - was add32 j = 0; do { int Rxy, Ryy; /* Temporary sums of the new pulse(s) */ Rxy = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + j])), rshift)); /* We're multiplying y[j] by two so we don't have to do it here */ Ryy = Inlines.ADD16(yy, y[j]); /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that * Rxy is positive because the sign is pre-computed) */ Rxy = Inlines.MULT16_16_Q15(Rxy, Rxy); /* The idea is to check for num/den >= best_num/best_den, but that way * we can do it without any division */ /* OPT: Make sure to use conditional moves here */ if (Inlines.MULT16_16(best_den, Rxy) > Inlines.MULT16_16(Ryy, best_num)) { best_den = Ryy; best_num = Rxy; best_id = j; } } while (++j < N); /* Updating the sums of the new pulse(s) */ xy = Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + best_id])); /* We're multiplying y[j] by two so we don't have to do it here */ yy = Inlines.ADD16(yy, y[best_id]); /* Only now that we've made the final choice, update y/iy */ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */ y[best_id] = (y[best_id] + (2 * s)); iy[best_id]++; } /* Put the original sign back */ j = 0; do { X[X_ptr + j] = (Inlines.MULT16_16(signx[j], X[X_ptr + j])); /* OPT: Make sure your compiler uses a conditional move here rather than * a branch. */ iy[j] = signx[j] < 0 ? -iy[j] : iy[j]; } while (++j < N); CWRS.encode_pulses(iy, N, K, enc); collapse_mask = extract_collapse_mask(iy, N, B); return(collapse_mask); }