예제 #1
0
        internal static int stereo_itheta(int[] X, int X_ptr, int[] Y, int Y_ptr, int stereo, int N)
        {
            int i;
            int itheta;
            int mid, side;
            int Emid, Eside;

            Emid = Eside = CeltConstants.EPSILON;
            if (stereo != 0)
            {
                for (i = 0; i < N; i++)
                {
                    int m, s;
                    m     = Inlines.ADD16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
                    s     = Inlines.SUB16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
                    Emid  = Inlines.MAC16_16(Emid, m, m);
                    Eside = Inlines.MAC16_16(Eside, s, s);
                }
            }
            else
            {
                Emid  += Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N);
                Eside += Kernels.celt_inner_prod(Y, Y_ptr, Y, Y_ptr, N);
            }
            mid  = (Inlines.celt_sqrt(Emid));
            side = (Inlines.celt_sqrt(Eside));
            /* 0.63662 = 2/pi */
            itheta = Inlines.MULT16_16_Q15(((short)(0.5 + (0.63662f) * (((int)1) << (15)))) /*Inlines.QCONST16(0.63662f, 15)*/, Inlines.celt_atan2p(side, mid));

            return(itheta);
        }
예제 #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);
        }