Exemplo n.º 1
0
        /** 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);
        }
Exemplo n.º 2
0
        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);
        }