Ejemplo n.º 1
0
        internal static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start,
                                               int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance,
                                               int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits,
                                               int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth)
        {
            int psum;
            int lo, hi;
            int i, j;
            int logM;
            int stereo;
            int codedBands = -1;
            int alloc_floor;
            int left, percoeff;
            int done;
            int balance;


            alloc_floor = C << EntropyCoder.BITRES;
            stereo      = C > 1 ? 1 : 0;

            logM = LM << EntropyCoder.BITRES;
            lo   = 0;
            hi   = 1 << ALLOC_STEPS;
            for (i = 0; i < ALLOC_STEPS; i++)
            {
                int mid = (lo + hi) >> 1;
                psum = 0;
                done = 0;
                for (j = end; j-- > start;)
                {
                    int tmp = bits1[j] + (mid * (int)bits2[j] >> ALLOC_STEPS);
                    if (tmp >= thresh[j] || done != 0)
                    {
                        done = 1;
                        /* Don't allocate more than we can actually use */
                        psum += Inlines.IMIN(tmp, cap[j]);
                    }
                    else
                    {
                        if (tmp >= alloc_floor)
                        {
                            psum += alloc_floor;
                        }
                    }
                }
                if (psum > total)
                {
                    hi = mid;
                }
                else
                {
                    lo = mid;
                }
            }
            psum = 0;
            /*printf ("interp bisection gave %d\n", lo);*/
            done = 0;
            for (j = end; j-- > start;)
            {
                int tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS);
                if (tmp < thresh[j] && done == 0)
                {
                    if (tmp >= alloc_floor)
                    {
                        tmp = alloc_floor;
                    }
                    else
                    {
                        tmp = 0;
                    }
                }
                else
                {
                    done = 1;
                }

                /* Don't allocate more than we can actually use */
                tmp     = Inlines.IMIN(tmp, cap[j]);
                bits[j] = tmp;
                psum   += tmp;
            }

            /* Decide which bands to skip, working backwards from the end. */
            for (codedBands = end; ; codedBands--)
            {
                int band_width;
                int band_bits;
                int rem;
                j = codedBands - 1;

                /* Never skip the first band, nor a band that has been boosted by
                 *  dynalloc.
                 * In the first case, we'd be coding a bit to signal we're going to waste
                 *  all the other bits.
                 * In the second case, we'd be coding a bit to redistribute all the bits
                 *  we just signaled should be cocentrated in this band. */
                if (j <= skip_start)
                {
                    /* Give the bit we reserved to end skipping back. */
                    total += skip_rsv;
                    break;
                }

                /*Figure out how many left-over bits we would be adding to this band.
                *  This can include bits we've stolen back from higher, skipped bands.*/
                left       = total - psum;
                percoeff   = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
                left      -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
                rem        = Inlines.IMAX(left - (m.eBands[j] - m.eBands[start]), 0);
                band_width = m.eBands[codedBands] - m.eBands[j];
                band_bits  = (int)(bits[j] + percoeff * band_width + rem);

                /*Only code a skip decision if we're above the threshold for this band.
                 * Otherwise it is force-skipped.
                 * This ensures that we have enough bits to code the skip flag.*/
                if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + (1 << EntropyCoder.BITRES)))
                {
                    if (encode != 0)
                    {
                        /*This if() block is the only part of the allocation function that
                         * is not a mandatory part of the bitstream: any bands we choose to
                         * skip here must be explicitly signaled.*/
                        /*Choose a threshold with some hysteresis to keep bands from
                         * fluctuating in and out.*/
#if FUZZING
                        if ((new Random().Next() & 0x1) == 0)
#else
                        if (codedBands <= start + 2 || (band_bits > ((j < prev ? 7 : 9) * band_width << LM << EntropyCoder.BITRES) >> 4 && j <= signalBandwidth))
#endif
                        {
                            ec.enc_bit_logp(1, 1);
                            break;
                        }
                        ec.enc_bit_logp(0, 1);
                    }
                    else if (ec.dec_bit_logp(1) != 0)
                    {
                        break;
                    }
                    /*We used a bit to skip this band.*/
                    psum      += 1 << EntropyCoder.BITRES;
                    band_bits -= 1 << EntropyCoder.BITRES;
                }
                /*Reclaim the bits originally allocated to this band.*/
                psum -= bits[j] + intensity_rsv;
                if (intensity_rsv > 0)
                {
                    intensity_rsv = LOG2_FRAC_TABLE[j - start];
                }
                psum += intensity_rsv;
                if (band_bits >= alloc_floor)
                {
                    /*If we have enough for a fine energy bit per channel, use it.*/
                    psum   += alloc_floor;
                    bits[j] = alloc_floor;
                }
                else
                {
                    /*Otherwise this band gets nothing at all.*/
                    bits[j] = 0;
                }
            }

            Inlines.OpusAssert(codedBands > start);
            /* Code the intensity and dual stereo parameters. */
            if (intensity_rsv > 0)
            {
                if (encode != 0)
                {
                    intensity = Inlines.IMIN(intensity, codedBands);
                    ec.enc_uint((uint)(intensity - start), (uint)(codedBands + 1 - start));
                }
                else
                {
                    intensity = start + (int)ec.dec_uint((uint)(codedBands + 1 - start));
                }
            }
            else
            {
                intensity = 0;
            }

            if (intensity <= start)
            {
                total          += dual_stereo_rsv;
                dual_stereo_rsv = 0;
            }
            if (dual_stereo_rsv > 0)
            {
                if (encode != 0)
                {
                    ec.enc_bit_logp(dual_stereo, 1);
                }
                else
                {
                    dual_stereo = ec.dec_bit_logp(1);
                }
            }
            else
            {
                dual_stereo = 0;
            }

            /* Allocate the remaining bits */
            left     = total - psum;
            percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
            left    -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
            for (j = start; j < codedBands; j++)
            {
                bits[j] += ((int)percoeff * (m.eBands[j + 1] - m.eBands[j]));
            }
            for (j = start; j < codedBands; j++)
            {
                int tmp = (int)Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]);
                bits[j] += tmp;
                left    -= tmp;
            }
            /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/

            balance = 0;
            for (j = start; j < codedBands; j++)
            {
                int N0, N, den;
                int offset;
                int NClogN;
                int excess, bit;

                Inlines.OpusAssert(bits[j] >= 0);
                N0  = m.eBands[j + 1] - m.eBands[j];
                N   = N0 << LM;
                bit = (int)bits[j] + balance;

                if (N > 1)
                {
                    excess  = Inlines.MAX32(bit - cap[j], 0);
                    bits[j] = bit - excess;

                    /* Compensate for the extra DoF in stereo */
                    den = (C * N + ((C == 2 && N > 2 && (dual_stereo == 0) && j < intensity) ? 1 : 0));

                    NClogN = den * (m.logN[j] + logM);

                    /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
                     * compared to their "fair share" of total/N */
                    offset = (NClogN >> 1) - den * CeltConstants.FINE_OFFSET;

                    /* N=2 is the only point that doesn't match the curve */
                    if (N == 2)
                    {
                        offset += den << EntropyCoder.BITRES >> 2;
                    }

                    /* Changing the offset for allocating the second and third
                     *  fine energy bit */
                    if (bits[j] + offset < den * 2 << EntropyCoder.BITRES)
                    {
                        offset += NClogN >> 2;
                    }
                    else if (bits[j] + offset < den * 3 << EntropyCoder.BITRES)
                    {
                        offset += NClogN >> 3;
                    }

                    /* Divide with rounding */
                    ebits[j] = Inlines.IMAX(0, (bits[j] + offset + (den << (EntropyCoder.BITRES - 1))));
                    ebits[j] = Inlines.celt_udiv(ebits[j], den) >> EntropyCoder.BITRES;

                    /* Make sure not to bust */
                    if (C * ebits[j] > (bits[j] >> EntropyCoder.BITRES))
                    {
                        ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
                    }

                    /* More than that is useless because that's about as far as PVQ can go */
                    ebits[j] = Inlines.IMIN(ebits[j], CeltConstants.MAX_FINE_BITS);

                    /* If we rounded down or capped this band, make it a candidate for the
                     *  final fine energy pass */
                    fine_priority[j] = (ebits[j] * (den << EntropyCoder.BITRES) >= bits[j] + offset) ? 1 : 0;

                    /* Remove the allocated fine bits; the rest are assigned to PVQ */
                    bits[j] -= C * ebits[j] << EntropyCoder.BITRES;
                }
                else
                {
                    /* For N=1, all bits go to fine energy except for a single sign bit */
                    excess           = Inlines.MAX32(0, bit - (C << EntropyCoder.BITRES));
                    bits[j]          = bit - excess;
                    ebits[j]         = 0;
                    fine_priority[j] = 1;
                }

                /* Fine energy can't take advantage of the re-balancing in
                 *  quant_all_bands().
                 * Instead, do the re-balancing here.*/
                if (excess > 0)
                {
                    int extra_fine;
                    int extra_bits;
                    extra_fine       = Inlines.IMIN(excess >> (stereo + EntropyCoder.BITRES), CeltConstants.MAX_FINE_BITS - ebits[j]);
                    ebits[j]        += extra_fine;
                    extra_bits       = extra_fine * C << EntropyCoder.BITRES;
                    fine_priority[j] = (extra_bits >= excess - balance) ? 1 : 0;
                    excess          -= extra_bits;
                }
                balance = excess;

                Inlines.OpusAssert(bits[j] >= 0);
                Inlines.OpusAssert(ebits[j] >= 0);
            }

            /* Save any remaining bits over the cap for the rebalancing in
             *  quant_all_bands(). */
            _balance = balance;

            /* The skipped bands use all their bits for fine energy. */
            for (; j < end; j++)
            {
                ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
                Inlines.OpusAssert(C * ebits[j] << EntropyCoder.BITRES == bits[j]);
                bits[j]          = 0;
                fine_priority[j] = (ebits[j] < 1) ? 1 : 0;
            }

            return(codedBands);
        }
Ejemplo n.º 2
0
 internal static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc)
 {
     Inlines.OpusAssert(_k > 0);
     _enc.enc_uint(icwrs(_n, _y), CELT_PVQ_V(_n, _k));
 }