예제 #1
0
        /// <summary>
        ///     <PRE>
        ///         some simple statistics
        ///         bitrate index 0: free bitrate . not allowed in VBR mode
        ///         : bitrates, kbps depending on MPEG version
        ///         bitrate index 15: forbidden
        ///         mode_ext:
        ///         0:  LR
        ///         1:  LR-i
        ///         2:  MS
        ///         3:  MS-i
        ///     </PRE>
        /// </summary>
        private void updateStats(LameInternalFlags gfc)
        {
            int gr, ch;

            Debug.Assert(0 <= gfc.bitrate_index && gfc.bitrate_index < 16);
            Debug.Assert(0 <= gfc.mode_ext && gfc.mode_ext < 4);

            /* count bitrate indices */
            gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][4]++;
            gfc.bitrate_stereoMode_Hist[15][4]++;

            /* count 'em for every mode extension in case of 2 channel encoding */
            if (gfc.channels_out == 2)
            {
                gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][gfc.mode_ext]++;
                gfc.bitrate_stereoMode_Hist[15][gfc.mode_ext]++;
            }

            for (gr = 0; gr < gfc.mode_gr; ++gr)
            {
                for (ch = 0; ch < gfc.channels_out; ++ch)
                {
                    var bt = gfc.l3_side.tt[gr][ch].block_type;
                    if (gfc.l3_side.tt[gr][ch].mixed_block_flag != 0)
                    {
                        bt = 4;
                    }

                    gfc.bitrate_blockType_Hist[gfc.bitrate_index][bt]++;
                    gfc.bitrate_blockType_Hist[gfc.bitrate_index][5]++;
                    gfc.bitrate_blockType_Hist[15][bt]++;
                    gfc.bitrate_blockType_Hist[15][5]++;
                }
            }
        }
예제 #2
0
        private int LongHuffmancodebits(LameInternalFlags gfc, GrInfo gi)
        {
            int bigvalues, bits;
            int region1Start, region2Start;

            bigvalues = gi.big_values;
            Debug.Assert(0 <= bigvalues && bigvalues <= 576);

            var i = gi.region0_count + 1;

            Debug.Assert(0 <= i);
            Debug.Assert(i < gfc.scalefac_band.l.Length);
            region1Start = gfc.scalefac_band.l[i];
            i           += gi.region1_count + 1;
            Debug.Assert(0 <= i);
            Debug.Assert(i < gfc.scalefac_band.l.Length);
            region2Start = gfc.scalefac_band.l[i];

            if (region1Start > bigvalues)
            {
                region1Start = bigvalues;
            }

            if (region2Start > bigvalues)
            {
                region2Start = bigvalues;
            }

            bits  = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi);
            bits += Huffmancode(gfc, gi.table_select[1], region1Start, region2Start, gi);
            bits += Huffmancode(gfc, gi.table_select[2], region2Start, bigvalues, gi);
            return(bits);
        }
예제 #3
0
        internal void bitpressure_strategy(LameInternalFlags gfc, float[][][] l3_xmin, int[][] min_bits, int[][] max_bits)
        {
            for (var gr = 0; gr < gfc.mode_gr; gr++)
            {
                for (var ch = 0; ch < gfc.channels_out; ch++)
                {
                    var gi       = gfc.l3_side.tt[gr][ch];
                    var pxmin    = l3_xmin[gr][ch];
                    var pxminPos = 0;
                    for (var sfb = 0; sfb < gi.psy_lmax; sfb++)
                    {
                        pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_l / Encoder.SBMAX_l);
                    }

                    if (gi.block_type == Encoder.SHORT_TYPE)
                    {
                        for (var sfb = gi.sfb_smin; sfb < Encoder.SBMAX_s; sfb++)
                        {
                            pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s);
                            pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s);
                            pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s);
                        }
                    }

                    max_bits[gr][ch] = (int)Math.Max(min_bits[gr][ch], 0.9 * max_bits[gr][ch]);
                }
            }
        }
예제 #4
0
        /// <summary>
        ///     write j bits into the bit stream, ignoring frame headers
        /// </summary>
        private void putbits_noheaders(LameInternalFlags gfc, int val, int j)
        {
            Debug.Assert(j < MAX_LENGTH - 2);

            while (j > 0)
            {
                int k;
                if (bufBitIdx == 0)
                {
                    bufBitIdx = 8;
                    bufByteIdx++;
                    Debug.Assert(bufByteIdx < Lame.LAME_MAXMP3BUFFER);
                    buf[bufByteIdx] = 0;
                }

                k  = Math.Min(j, bufBitIdx);
                j -= k;

                bufBitIdx -= k;

                Debug.Assert(j < MAX_LENGTH); // 32 too large on 32 bit machines
                Debug.Assert(bufBitIdx < MAX_LENGTH);

                buf[bufByteIdx] |= (byte)((val >> j) << bufBitIdx);
                totbit          += k;
            }
        }
예제 #5
0
        /// <summary>
        ///     write j bits into the bit stream
        /// </summary>
        private void putbits2(LameInternalFlags gfc, int val, int j)
        {
            Debug.Assert(j < MAX_LENGTH - 2);

            while (j > 0)
            {
                int k;
                if (bufBitIdx == 0)
                {
                    bufBitIdx = 8;
                    bufByteIdx++;
                    Debug.Assert(bufByteIdx < Lame.LAME_MAXMP3BUFFER);
                    Debug.Assert(gfc.header[gfc.w_ptr].write_timing >= totbit);
                    if (gfc.header[gfc.w_ptr].write_timing == totbit)
                    {
                        putheader_bits(gfc);
                    }

                    buf[bufByteIdx] = 0;
                }

                k  = Math.Min(j, bufBitIdx);
                j -= k;

                bufBitIdx -= k;

                Debug.Assert(j < MAX_LENGTH);
                /* 32 too large on 32 bit machines */
                Debug.Assert(bufBitIdx < MAX_LENGTH);

                buf[bufByteIdx] |= (byte)((val >> j) << bufBitIdx);
                totbit          += k;
            }
        }
예제 #6
0
 private void putheader_bits(LameInternalFlags gfc)
 {
     Array.Copy(gfc.header[gfc.w_ptr].buf, 0, buf, bufByteIdx, gfc.sideinfo_len);
     bufByteIdx += gfc.sideinfo_len;
     totbit     += gfc.sideinfo_len * 8;
     gfc.w_ptr   = (gfc.w_ptr + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1);
 }
예제 #7
0
        internal bool init_xrpow(LameInternalFlags gfc, GrInfo cod_info, float[] xrpow)
        {
            float sum = 0;

            var upper = cod_info.max_nonzero_coeff;

            Debug.Assert(xrpow != null);
            cod_info.xrpow_max = 0;
            Debug.Assert(0 <= upper && upper <= 575);
            Arrays.Fill(xrpow, upper, 576, 0);
            sum = init_xrpow_core(cod_info, xrpow, upper, sum);
            if (sum > 1E-20f)
            {
                var j = 0;
                if ((gfc.substep_shaping & 2) != 0)
                {
                    j = 1;
                }

                for (var i = 0; i < cod_info.psymax; i++)
                {
                    gfc.pseudohalf[i] = j;
                }

                return(true);
            }

            Arrays.Fill(cod_info.l3_enc, 0, 576, 0);
            return(false);
        }
예제 #8
0
        internal void init_bit_stream_w(LameInternalFlags gfc)
        {
            buf = new byte[Lame.LAME_MAXMP3BUFFER];

            gfc.h_ptr = gfc.w_ptr = 0;
            gfc.header[gfc.h_ptr].write_timing = 0;
            bufByteIdx = -1;
            bufBitIdx  = 0;
            totbit     = 0;
        }
예제 #9
0
        internal void iteration_finish_one(LameInternalFlags gfc, int gr, int ch)
        {
            var l3_side = gfc.l3_side;

            var cod_info = l3_side.tt[gr][ch];

            tk.best_scalefac_store(gfc, gr, ch, l3_side);
            if (gfc.use_best_huffman == 1)
            {
                tk.best_huffman_divide(gfc, cod_info);
            }

            rv.ResvAdjust(gfc, cod_info);
        }
예제 #10
0
        internal void fft_short(LameInternalFlags gfc, float[][] x_real, int chn, float[][] buffer, int bufPos)
        {
            for (var b = 0; b < 3; b++)
            {
                var x = Encoder.BLKSIZE_s / 2;

                var k = (short)(576 / 3 * (b + 1));
                var j = Encoder.BLKSIZE_s / 8 - 1;
                do
                {
                    float f0, f1, f2, f3, w;

                    var i = rv_tbl[j << 2] & 0xff;

                    f0 = window_s[i] * buffer[chn][bufPos + i + k];
                    w  = window_s[0x7f - i] * buffer[chn][bufPos + i + k + 0x80];
                    f1 = f0 - w;
                    f0 = f0 + w;
                    f2 = window_s[i + 0x40] * buffer[chn][bufPos + i + k + 0x40];
                    w  = window_s[0x3f - i] * buffer[chn][bufPos + i + k + 0xc0];
                    f3 = f2 - w;
                    f2 = f2 + w;

                    x -= 4;
                    x_real[b][x + 0] = f0 + f2;
                    x_real[b][x + 2] = f0 - f2;
                    x_real[b][x + 1] = f1 + f3;
                    x_real[b][x + 3] = f1 - f3;

                    f0 = window_s[i + 0x01] * buffer[chn][bufPos + i + k + 0x01];
                    w  = window_s[0x7e - i] * buffer[chn][bufPos + i + k + 0x81];
                    f1 = f0 - w;
                    f0 = f0 + w;
                    f2 = window_s[i + 0x41] * buffer[chn][bufPos + i + k + 0x41];
                    w  = window_s[0x3e - i] * buffer[chn][bufPos + i + k + 0xc1];
                    f3 = f2 - w;
                    f2 = f2 + w;

                    x_real[b][x + Encoder.BLKSIZE_s / 2 + 0] = f0 + f2;
                    x_real[b][x + Encoder.BLKSIZE_s / 2 + 2] = f0 - f2;
                    x_real[b][x + Encoder.BLKSIZE_s / 2 + 1] = f1 + f3;
                    x_real[b][x + Encoder.BLKSIZE_s / 2 + 3] = f1 - f3;
                }while (--j >= 0);

                fht(x_real[b], x, Encoder.BLKSIZE_s / 2);
                /* BLKSIZE_s/2 because of 3DNow! ASM routine */
                /* BLKSIZE/2 because of 3DNow! ASM routine */
            }
        }
예제 #11
0
        /// <summary>
        ///     Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, as
        ///     well as the definitions of the side information on pages 26 and 27.
        /// </summary>
        private int ShortHuffmancodebits(LameInternalFlags gfc, GrInfo gi)
        {
            var region1Start = 3 * gfc.scalefac_band.s[3];

            if (region1Start > gi.big_values)
            {
                region1Start = gi.big_values;
            }

            /* short blocks do not have a region2 */
            var bits = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi);

            bits += Huffmancode(gfc, gi.table_select[1], region1Start, gi.big_values, gi);
            return(bits);
        }
예제 #12
0
        private int reduce_bit_usage(LameInternalFlags gfc, int gr, int ch)
        {
            var cod_info = gfc.l3_side.tt[gr][ch];

            // try some better scalefac storage
            tak.best_scalefac_store(gfc, gr, ch, gfc.l3_side);

            // best huffman_divide may save some bits too
            if (gfc.use_best_huffman == 1)
            {
                tak.best_huffman_divide(gfc, cod_info);
            }

            return(cod_info.part2_3_length + cod_info.part2_length);
        }
예제 #13
0
        internal void CRC_writeheader(LameInternalFlags gfc, byte[] header)
        {
            var crc = 0xffff;

            /* (jo) init crc16 for error_protection */

            crc = CRC_update(header[2] & 0xff, crc);
            crc = CRC_update(header[3] & 0xff, crc);
            for (var i = 6; i < gfc.sideinfo_len; i++)
            {
                crc = CRC_update(header[i] & 0xff, crc);
            }

            header[4] = (byte)(crc >> 8);
            header[5] = unchecked ((byte)(crc & 255));
        }
예제 #14
0
        /// <summary>
        ///     write N bits into the header
        /// </summary>
        private void writeheader(LameInternalFlags gfc, int val, int j)
        {
            var ptr = gfc.header[gfc.h_ptr].ptr;

            while (j > 0)
            {
                var k = Math.Min(j, 8 - (ptr & 7));
                j -= k;
                Debug.Assert(j < MAX_LENGTH); // >> 32 too large for 32 bit machines

                gfc.header[gfc.h_ptr].buf[ptr >> 3] =
                    (byte)(gfc.header[gfc.h_ptr].buf[ptr >> 3] | (byte)((val >> j) << (8 - (ptr & 7) - k)));
                ptr += k;
            }

            gfc.header[gfc.h_ptr].ptr = ptr;
        }
예제 #15
0
        internal void fft_long(LameInternalFlags gfc, float[] y, int chn, float[][] buffer, int bufPos)
        {
            var jj = Encoder.BLKSIZE / 8 - 1;
            var x  = Encoder.BLKSIZE / 2;

            do
            {
                float f0, f1, f2, f3, w;

                var i = rv_tbl[jj] & 0xff;
                f0 = window[i] * buffer[chn][bufPos + i];
                w  = window[i + 0x200] * buffer[chn][bufPos + i + 0x200];
                f1 = f0 - w;
                f0 = f0 + w;
                f2 = window[i + 0x100] * buffer[chn][bufPos + i + 0x100];
                w  = window[i + 0x300] * buffer[chn][bufPos + i + 0x300];
                f3 = f2 - w;
                f2 = f2 + w;

                x       -= 4;
                y[x + 0] = f0 + f2;
                y[x + 2] = f0 - f2;
                y[x + 1] = f1 + f3;
                y[x + 3] = f1 - f3;

                f0 = window[i + 0x001] * buffer[chn][bufPos + i + 0x001];
                w  = window[i + 0x201] * buffer[chn][bufPos + i + 0x201];
                f1 = f0 - w;
                f0 = f0 + w;
                f2 = window[i + 0x101] * buffer[chn][bufPos + i + 0x101];
                w  = window[i + 0x301] * buffer[chn][bufPos + i + 0x301];
                f3 = f2 - w;
                f2 = f2 + w;

                y[x + Encoder.BLKSIZE / 2 + 0] = f0 + f2;
                y[x + Encoder.BLKSIZE / 2 + 2] = f0 - f2;
                y[x + Encoder.BLKSIZE / 2 + 1] = f1 + f3;
                y[x + Encoder.BLKSIZE / 2 + 3] = f1 - f3;
            }while (--jj >= 0);

            fht(y, x, Encoder.BLKSIZE / 2);
            /* BLKSIZE/2 because of 3DNow! ASM routine */
        }
예제 #16
0
        internal void init_fft(LameInternalFlags gfc)
        {
            /* The type of window used here will make no real difference, but */

            /*
             * in the interest of merging nspsytune stuff - switch to blackman
             * window
             */
            for (var i = 0; i < Encoder.BLKSIZE; i++)
            {
                /* blackman window */
                window[i] = (float)(0.42 - 0.5 * Math.Cos(2 * Math.PI * (i + .5) / Encoder.BLKSIZE) +
                                    0.08 * Math.Cos(4 * Math.PI * (i + .5) / Encoder.BLKSIZE));
            }

            for (var i = 0; i < Encoder.BLKSIZE_s / 2; i++)
            {
                window_s[i] = (float)(0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (i + 0.5) / Encoder.BLKSIZE_s)));
            }
        }
예제 #17
0
        internal void trancate_smallspectrums(LameInternalFlags gfc, GrInfo gi, float[] l3_xmin, float[] work)
        {
            var distort = new float[L3Side.SFBMAX];

            if (0 == (gfc.substep_shaping & 4) && gi.block_type == Encoder.SHORT_TYPE ||
                (gfc.substep_shaping & 0x80) != 0)
            {
                return;
            }

            qupvt.calc_noise(gi, l3_xmin, distort, new CalcNoiseResult(), null);
            for (var jj = 0; jj < 576; jj++)
            {
                var xr = 0.0f;
                if (gi.l3_enc[jj] != 0)
                {
                    xr = Math.Abs(gi.xr[jj]);
                }

                work[jj] = xr;
            }

            var j   = 0;
            var sfb = 8;

            if (gi.block_type == Encoder.SHORT_TYPE)
            {
                sfb = 6;
            }

            do
            {
                float allowedNoise, trancateThreshold;
                int   nsame, start;
                var   width = gi.width[sfb];
                j += width;
                if (distort[sfb] >= 1.0)
                {
                    continue;
                }

                Arrays.Sort(work, j - width, width);
                if (BitStream.EQ(work[j - 1], 0.0f))
                {
                    continue;
                }

                allowedNoise      = (1.0f - distort[sfb]) * l3_xmin[sfb];
                trancateThreshold = 0.0f;
                start             = 0;
                do
                {
                    float noise;
                    for (nsame = 1; start + nsame < width; nsame++)
                    {
                        if (BitStream.NEQ(work[start + j - width], work[start + j + nsame - width]))
                        {
                            break;
                        }
                    }

                    noise = work[start + j - width] * work[start + j - width] * nsame;
                    if (allowedNoise < noise)
                    {
                        if (start != 0)
                        {
                            trancateThreshold = work[start + j - width - 1];
                        }

                        break;
                    }

                    allowedNoise -= noise;
                    start        += nsame;
                }while (start < width);

                if (BitStream.EQ(trancateThreshold, 0.0f))
                {
                    continue;
                }

                do
                {
                    if (Math.Abs(gi.xr[j - width]) <= trancateThreshold)
                    {
                        gi.l3_enc[j - width] = 0;
                    }
                }while (--width > 0);
            }while (++sfb < gi.psymax);

            gi.part2_3_length = tk.noquant_count_bits(gfc, gi, null);
        }
예제 #18
0
        private int bin_search_StepSize(LameInternalFlags gfc, GrInfo cod_info, int desired_rate, int ch, float[] xrpow)
        {
            int nBits;
            var CurrentStep  = gfc.CurrentStep[ch];
            var flagGoneOver = false;

            var start     = gfc.OldValue[ch];
            var Direction = BinSearchDirection.BINSEARCH_NONE;

            cod_info.global_gain = start;
            desired_rate        -= cod_info.part2_length;
            Debug.Assert(CurrentStep != 0);
            for (;;)
            {
                int step;
                nBits = tk.count_bits(gfc, xrpow, cod_info, null);
                if (CurrentStep == 1 || nBits == desired_rate)
                {
                    break;
                }

                if (nBits > desired_rate)
                {
                    if (Direction == BinSearchDirection.BINSEARCH_DOWN)
                    {
                        flagGoneOver = true;
                    }

                    if (flagGoneOver)
                    {
                        CurrentStep /= 2;
                    }

                    Direction = BinSearchDirection.BINSEARCH_UP;
                    step      = CurrentStep;
                }
                else
                {
                    if (Direction == BinSearchDirection.BINSEARCH_UP)
                    {
                        flagGoneOver = true;
                    }

                    if (flagGoneOver)
                    {
                        CurrentStep /= 2;
                    }

                    Direction = BinSearchDirection.BINSEARCH_DOWN;
                    step      = -CurrentStep;
                }

                cod_info.global_gain += step;
                if (cod_info.global_gain < 0)
                {
                    cod_info.global_gain = 0;
                    flagGoneOver         = true;
                }

                if (cod_info.global_gain > 255)
                {
                    cod_info.global_gain = 255;
                    flagGoneOver         = true;
                }
            }

            Debug.Assert(cod_info.global_gain >= 0);
            Debug.Assert(cod_info.global_gain < 256);
            while (nBits > desired_rate && cod_info.global_gain < 255)
            {
                cod_info.global_gain++;
                nBits = tk.count_bits(gfc, xrpow, cod_info, null);
            }

            gfc.CurrentStep[ch]     = start - cod_info.global_gain >= 4 ? 4 : 2;
            gfc.OldValue[ch]        = cod_info.global_gain;
            cod_info.part2_3_length = nBits;
            return(nBits);
        }
예제 #19
0
        internal void init_outer_loop(LameInternalFlags gfc, GrInfo cod_info)
        {
            cod_info.part2_3_length     = 0;
            cod_info.big_values         = 0;
            cod_info.count1             = 0;
            cod_info.global_gain        = 210;
            cod_info.scalefac_compress  = 0;
            cod_info.table_select[0]    = 0;
            cod_info.table_select[1]    = 0;
            cod_info.table_select[2]    = 0;
            cod_info.subblock_gain[0]   = 0;
            cod_info.subblock_gain[1]   = 0;
            cod_info.subblock_gain[2]   = 0;
            cod_info.subblock_gain[3]   = 0;
            cod_info.region0_count      = 0;
            cod_info.region1_count      = 0;
            cod_info.preflag            = 0;
            cod_info.scalefac_scale     = 0;
            cod_info.count1table_select = 0;
            cod_info.part2_length       = 0;
            cod_info.sfb_lmax           = Encoder.SBPSY_l;
            cod_info.sfb_smin           = Encoder.SBPSY_s;
            cod_info.psy_lmax           = gfc.sfb21_extra ? Encoder.SBMAX_l : Encoder.SBPSY_l;
            cod_info.psymax             = cod_info.psy_lmax;
            cod_info.sfbmax             = cod_info.sfb_lmax;
            cod_info.sfbdivide          = 11;
            for (var sfb = 0; sfb < Encoder.SBMAX_l; sfb++)
            {
                cod_info.width[sfb]  = gfc.scalefac_band.l[sfb + 1] - gfc.scalefac_band.l[sfb];
                cod_info.window[sfb] = 3;
            }

            if (cod_info.block_type == Encoder.SHORT_TYPE)
            {
                var ixwork = new float[576];
                cod_info.sfb_smin = 0;
                cod_info.sfb_lmax = 0;
                if (cod_info.mixed_block_flag != 0)
                {
                    cod_info.sfb_smin = 3;
                    cod_info.sfb_lmax = gfc.mode_gr * 2 + 4;
                }

                cod_info.psymax = cod_info.sfb_lmax +
                                  3 * ((gfc.sfb21_extra ? Encoder.SBMAX_s : Encoder.SBPSY_s) - cod_info.sfb_smin);
                cod_info.sfbmax    = cod_info.sfb_lmax + 3 * (Encoder.SBPSY_s - cod_info.sfb_smin);
                cod_info.sfbdivide = cod_info.sfbmax - 18;
                cod_info.psy_lmax  = cod_info.sfb_lmax;
                var ix = gfc.scalefac_band.l[cod_info.sfb_lmax];
                Array.Copy(cod_info.xr, 0, ixwork, 0, 576);
                for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++)
                {
                    var start = gfc.scalefac_band.s[sfb];

                    var end = gfc.scalefac_band.s[sfb + 1];
                    for (var window = 0; window < 3; window++)
                    {
                        for (var l = start; l < end; l++)
                        {
                            cod_info.xr[ix++] = ixwork[3 * l + window];
                        }
                    }
                }

                var j = cod_info.sfb_lmax;
                for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++)
                {
                    cod_info.width[j]         = cod_info.width[j + 1] =
                        cod_info.width[j + 2] = gfc.scalefac_band.s[sfb + 1] - gfc.scalefac_band.s[sfb];
                    cod_info.window[j]        = 0;
                    cod_info.window[j + 1]    = 1;
                    cod_info.window[j + 2]    = 2;
                    j += 3;
                }
            }

            cod_info.count1bits          = 0;
            cod_info.sfb_partition_table = qupvt.nr_of_sfb_block[0][0];
            cod_info.slen[0]             = 0;
            cod_info.slen[1]             = 0;
            cod_info.slen[2]             = 0;
            cod_info.slen[3]             = 0;
            cod_info.max_nonzero_coeff   = 575;
            Arrays.Fill(cod_info.scalefac, 0);
            psfb21_analogsilence(gfc, cod_info);
        }
예제 #20
0
        private void psfb21_analogsilence(LameInternalFlags gfc, GrInfo cod_info)
        {
            var ath = gfc.ATH;

            var xr = cod_info.xr;

            if (cod_info.block_type != Encoder.SHORT_TYPE)
            {
                var stop = false;
                for (var gsfb = Encoder.PSFB21 - 1; gsfb >= 0 && !stop; gsfb--)
                {
                    var start = gfc.scalefac_band.psfb21[gsfb];

                    var end   = gfc.scalefac_band.psfb21[gsfb + 1];
                    var ath21 = qupvt.athAdjust(ath.adjust, ath.psfb21[gsfb], ath.floor);
                    if (gfc.nsPsy.longfact[21] > 1e-12f)
                    {
                        ath21 *= gfc.nsPsy.longfact[21];
                    }

                    for (var j = end - 1; j >= start; j--)
                    {
                        if (Math.Abs(xr[j]) < ath21)
                        {
                            xr[j] = 0;
                        }
                        else
                        {
                            stop = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                for (var block = 0; block < 3; block++)
                {
                    var stop = false;
                    for (var gsfb = Encoder.PSFB12 - 1; gsfb >= 0 && !stop; gsfb--)
                    {
                        var start = gfc.scalefac_band.s[12] * 3 +
                                    (gfc.scalefac_band.s[13] - gfc.scalefac_band.s[12]) * block +
                                    (gfc.scalefac_band.psfb12[gsfb] - gfc.scalefac_band.psfb12[0]);

                        var end   = start + (gfc.scalefac_band.psfb12[gsfb + 1] - gfc.scalefac_band.psfb12[gsfb]);
                        var ath12 = qupvt.athAdjust(ath.adjust, ath.psfb12[gsfb], ath.floor);
                        if (gfc.nsPsy.shortfact[12] > 1e-12f)
                        {
                            ath12 *= gfc.nsPsy.shortfact[12];
                        }

                        for (var j = end - 1; j >= start; j--)
                        {
                            if (Math.Abs(xr[j]) < ath12)
                            {
                                xr[j] = 0;
                            }
                            else
                            {
                                stop = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
예제 #21
0
        private int huffman_coder_count1(LameInternalFlags gfc, GrInfo gi)
        {
            /* Write count1 area */

            var h = Tables.ht[gi.count1table_select + 32];
            int i, bits = 0;

            var ix = gi.big_values;
            var xr = gi.big_values;

            Debug.Assert(gi.count1table_select < 2);

            for (i = (gi.count1 - gi.big_values) / 4; i > 0; --i)
            {
                var huffbits = 0;
                int p = 0, v;

                v = gi.l3_enc[ix + 0];
                if (v != 0)
                {
                    p += 8;
                    if (gi.xr[xr + 0] < 0)
                    {
                        huffbits++;
                    }

                    Debug.Assert(v <= 1);
                }

                v = gi.l3_enc[ix + 1];
                if (v != 0)
                {
                    p        += 4;
                    huffbits *= 2;
                    if (gi.xr[xr + 1] < 0)
                    {
                        huffbits++;
                    }

                    Debug.Assert(v <= 1);
                }

                v = gi.l3_enc[ix + 2];
                if (v != 0)
                {
                    p        += 2;
                    huffbits *= 2;
                    if (gi.xr[xr + 2] < 0)
                    {
                        huffbits++;
                    }

                    Debug.Assert(v <= 1);
                }

                v = gi.l3_enc[ix + 3];
                if (v != 0)
                {
                    p++;
                    huffbits *= 2;
                    if (gi.xr[xr + 3] < 0)
                    {
                        huffbits++;
                    }

                    Debug.Assert(v <= 1);
                }

                ix += 4;
                xr += 4;
                putbits2(gfc, huffbits + h.table[p], h.hlen[p]);
                bits += h.hlen[p];
            }

            return(bits);
        }
예제 #22
0
        /// <summary>
        ///     auto-adjust of ATH, useful for low volume Gabriel Bouvigne 3 feb 2001
        ///     modifies some values in gfp.internal_flags.ATH (gfc.ATH)
        /// </summary>
        private void adjust_ATH(LameInternalFlags gfc)
        {
            float gr2_max, max_pow;

            if (gfc.ATH.useAdjust == 0)
            {
                gfc.ATH.adjust = 1.0f;
                /* no adjustment */
                return;
            }

            /* jd - 2001 mar 12, 27, jun 30 */
            /* loudness based on equal loudness curve; */
            /* use granule with maximum combined loudness */
            max_pow = gfc.loudness_sq[0][0];
            gr2_max = gfc.loudness_sq[1][0];
            if (gfc.channels_out == 2)
            {
                max_pow += gfc.loudness_sq[0][1];
                gr2_max += gfc.loudness_sq[1][1];
            }
            else
            {
                max_pow += max_pow;
                gr2_max += gr2_max;
            }

            if (gfc.mode_gr == 2)
            {
                max_pow = Math.Max(max_pow, gr2_max);
            }

            max_pow *= (float)0.5; // max_pow approaches 1.0 for full band noise

            /* jd - 2001 mar 31, jun 30 */
            /* user tuning of ATH adjustment region */
            max_pow *= gfc.ATH.aaSensitivityP;

            /*
             * adjust ATH depending on range of maximum value
             */

            /* jd - 2001 feb27, mar12,20, jun30, jul22 */
            /* continuous curves based on approximation */
            /* to GB's original values. */
            /* For an increase in approximate loudness, */
            /* set ATH adjust to adjust_limit immediately */
            /* after a delay of one frame. */
            /* For a loudness decrease, reduce ATH adjust */
            /* towards adjust_limit gradually. */
            /* max_pow is a loudness squared or a power. */
            if (max_pow > 0.03125)
            {
                // ((1 - 0.000625)/ 31.98) from curve below
                if (gfc.ATH.adjust >= 1.0)
                {
                    gfc.ATH.adjust = 1.0f;
                }
                else
                {
                    /* preceding frame has lower ATH adjust; */
                    /* ascend only to the preceding adjust_limit */
                    /* in case there is leading low volume */
                    if (gfc.ATH.adjust < gfc.ATH.adjustLimit)
                    {
                        gfc.ATH.adjust = gfc.ATH.adjustLimit;
                    }
                }

                gfc.ATH.adjustLimit = 1.0f;
            }
            else
            {
                // adjustment curve
                /* about 32 dB maximum adjust (0.000625) */

                var adj_lim_new = 31.98f * max_pow + 0.000625f;
                if (gfc.ATH.adjust >= adj_lim_new)
                {
                    // descend gradually
                    gfc.ATH.adjust = (float)(gfc.ATH.adjust * adj_lim_new * 0.075 + 0.925);
                    if (gfc.ATH.adjust < adj_lim_new)
                    {
                        gfc.ATH.adjust = adj_lim_new;
                    }
                }
                else
                {
                    // ascend
                    if (gfc.ATH.adjustLimit >= adj_lim_new)
                    {
                        gfc.ATH.adjust = adj_lim_new;
                    }
                    else
                    {
                        /* preceding frame has lower ATH adjust; */
                        /* ascend only to the preceding adjust_limit */
                        if (gfc.ATH.adjust < gfc.ATH.adjustLimit)
                        {
                            gfc.ATH.adjust = gfc.ATH.adjustLimit;
                        }
                    }
                }

                gfc.ATH.adjustLimit = adj_lim_new;
            }
        }
예제 #23
0
        /// <summary>
        ///     Implements the pseudocode of page 98 of the IS
        /// </summary>
        private int Huffmancode(LameInternalFlags gfc, int tableindex, int start, int end, GrInfo gi)
        {
            var h    = Tables.ht[tableindex];
            var bits = 0;

            Debug.Assert(tableindex < 32);
            if (0 == tableindex)
            {
                return(bits);
            }

            for (var i = start; i < end; i += 2)
            {
                var cbits = 0;
                var xbits = 0;

                var linbits = h.xlen;
                var xlen    = h.xlen;
                var ext     = 0;
                var x1      = gi.l3_enc[i];
                var x2      = gi.l3_enc[i + 1];

                if (x1 != 0)
                {
                    if (gi.xr[i] < 0)
                    {
                        ext++;
                    }

                    cbits--;
                }

                if (tableindex > 15)
                {
                    /* use ESC-words */
                    if (x1 > 14)
                    {
                        var linbits_x1 = x1 - 15;
                        Debug.Assert(linbits_x1 <= h.linmax);
                        ext  |= linbits_x1 << 1;
                        xbits = linbits;
                        x1    = 15;
                    }

                    if (x2 > 14)
                    {
                        var linbits_x2 = x2 - 15;
                        Debug.Assert(linbits_x2 <= h.linmax);
                        ext  <<= linbits;
                        ext   |= linbits_x2;
                        xbits += linbits;
                        x2     = 15;
                    }

                    xlen = 16;
                }

                if (x2 != 0)
                {
                    ext <<= 1;
                    if (gi.xr[i + 1] < 0)
                    {
                        ext++;
                    }

                    cbits--;
                }

                Debug.Assert((x1 | x2) < 16);

                x1     = x1 * xlen + x2;
                xbits -= cbits;
                cbits += h.hlen[x1];

                Debug.Assert(cbits <= MAX_LENGTH);
                Debug.Assert(xbits <= MAX_LENGTH);

                putbits2(gfc, h.table[x1], cbits);
                putbits2(gfc, ext, xbits);
                bits += cbits + xbits;
            }

            return(bits);
        }
예제 #24
0
        internal void mdct_sub48(LameInternalFlags gfc, float[] w0, float[] w1)
        {
            var wk    = w0;
            var wkPos = 286;

            for (var ch = 0; ch < gfc.channels_out; ch++)
            {
                for (var gr = 0; gr < gfc.mode_gr; gr++)
                {
                    int band;

                    var gi          = gfc.l3_side.tt[gr][ch];
                    var mdct_enc    = gi.xr;
                    var mdct_encPos = 0;
                    var samp        = gfc.sb_sample[ch][1 - gr];
                    var sampPos     = 0;
                    for (var k = 0; k < 18 / 2; k++)
                    {
                        window_subband(wk, wkPos, samp[sampPos]);
                        window_subband(wk, wkPos + 32, samp[sampPos + 1]);
                        sampPos += 2;
                        wkPos   += 64;
                        for (band = 1; band < 32; band += 2)
                        {
                            samp[sampPos - 1][band] *= -1;
                        }
                    }

                    for (band = 0; band < 32; band++, mdct_encPos += 18)
                    {
                        var type  = gi.block_type;
                        var band0 = gfc.sb_sample[ch][gr];
                        var band1 = gfc.sb_sample[ch][1 - gr];
                        if (gi.mixed_block_flag != 0 && band < 2)
                        {
                            type = 0;
                        }

                        if (gfc.amp_filter[band] < 1e-12)
                        {
                            Arrays.Fill(mdct_enc, mdct_encPos + 0, mdct_encPos + 18, 0);
                        }
                        else
                        {
                            if (gfc.amp_filter[band] < 1.0)
                            {
                                for (var k = 0; k < 18; k++)
                                {
                                    band1[k][order[band]] *= gfc.amp_filter[band];
                                }
                            }

                            if (type == Encoder.SHORT_TYPE)
                            {
                                for (var k = -NS / 4; k < 0; k++)
                                {
                                    var w = win[Encoder.SHORT_TYPE][k + 3];
                                    mdct_enc[mdct_encPos + k * 3 + 9] =
                                        band0[9 + k][order[band]] * w - band0[8 - k][order[band]];
                                    mdct_enc[mdct_encPos + k * 3 + 18] =
                                        band0[14 - k][order[band]] * w + band0[15 + k][order[band]];
                                    mdct_enc[mdct_encPos + k * 3 + 10] =
                                        band0[15 + k][order[band]] * w - band0[14 - k][order[band]];
                                    mdct_enc[mdct_encPos + k * 3 + 19] =
                                        band1[2 - k][order[band]] * w + band1[3 + k][order[band]];
                                    mdct_enc[mdct_encPos + k * 3 + 11] =
                                        band1[3 + k][order[band]] * w - band1[2 - k][order[band]];
                                    mdct_enc[mdct_encPos + k * 3 + 20] =
                                        band1[8 - k][order[band]] * w + band1[9 + k][order[band]];
                                }

                                mdct_short(mdct_enc, mdct_encPos);
                            }
                            else
                            {
                                var work = new float[18];
                                for (var k = -NL / 4; k < 0; k++)
                                {
                                    float a, b;
                                    a = win[type][k + 27] * band1[k + 9][order[band]] +
                                        win[type][k + 36] * band1[8 - k][order[band]];
                                    b = win[type][k + 9] * band0[k + 9][order[band]] -
                                        win[type][k + 18] * band0[8 - k][order[band]];
                                    work[k + 9]  = a - b * tantab_l[3 + k + 9];
                                    work[k + 18] = a * tantab_l[3 + k + 9] + b;
                                }

                                mdct_long(mdct_enc, mdct_encPos, work);
                            }
                        }

                        if (type != Encoder.SHORT_TYPE && band != 0)
                        {
                            for (var k = 7; k >= 0; --k)
                            {
                                float bu, bd;
                                bu = mdct_enc[mdct_encPos + k] * ca[20 + k] +
                                     mdct_enc[mdct_encPos + -1 - k] * cs[28 + k];
                                bd = mdct_enc[mdct_encPos + k] * cs[28 + k] -
                                     mdct_enc[mdct_encPos + -1 - k] * ca[20 + k];
                                mdct_enc[mdct_encPos + -1 - k] = bu;
                                mdct_enc[mdct_encPos + k]      = bd;
                            }
                        }
                    }
                }

                wk    = w1;
                wkPos = 286;
                if (gfc.mode_gr == 1)
                {
                    for (var i = 0; i < 18; i++)
                    {
                        Array.Copy(gfc.sb_sample[ch][1][i], 0, gfc.sb_sample[ch][0][i], 0, 32);
                    }
                }
            }
        }
예제 #25
0
        private bool inc_subblock_gain(LameInternalFlags gfc, GrInfo cod_info, float[] xrpow)
        {
            int sfb;

            var scalefac = cod_info.scalefac;

            for (sfb = 0; sfb < cod_info.sfb_lmax; sfb++)
            {
                if (scalefac[sfb] >= 16)
                {
                    return(true);
                }
            }

            for (var window = 0; window < 3; window++)
            {
                var s1 = 0;
                var s2 = 0;
                for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbdivide; sfb += 3)
                {
                    if (s1 < scalefac[sfb])
                    {
                        s1 = scalefac[sfb];
                    }
                }

                for (; sfb < cod_info.sfbmax; sfb += 3)
                {
                    if (s2 < scalefac[sfb])
                    {
                        s2 = scalefac[sfb];
                    }
                }

                if (s1 < 16 && s2 < 8)
                {
                    continue;
                }

                if (cod_info.subblock_gain[window] >= 7)
                {
                    return(true);
                }

                cod_info.subblock_gain[window]++;
                var j = gfc.scalefac_band.l[cod_info.sfb_lmax];
                for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbmax; sfb += 3)
                {
                    float amp;

                    var width = cod_info.width[sfb];
                    var s     = scalefac[sfb];
                    Debug.Assert(s >= 0);
                    s = s - (4 >> cod_info.scalefac_scale);
                    if (s >= 0)
                    {
                        scalefac[sfb] = s;
                        j            += width * 3;
                        continue;
                    }

                    scalefac[sfb] = 0;
                    {
                        var gain = 210 + (s << (cod_info.scalefac_scale + 1));
                        amp = qupvt.IPOW20(gain);
                    }
                    j += width * (window + 1);
                    for (var l = -width; l < 0; l++)
                    {
                        xrpow[j + l] *= amp;
                        if (xrpow[j + l] > cod_info.xrpow_max)
                        {
                            cod_info.xrpow_max = xrpow[j + l];
                        }
                    }

                    j += width * (3 - window - 1);
                }

                {
                    var amp = qupvt.IPOW20(202);
                    j += cod_info.width[sfb] * (window + 1);
                    for (var l = -cod_info.width[sfb]; l < 0; l++)
                    {
                        xrpow[j + l] *= amp;
                        if (xrpow[j + l] > cod_info.xrpow_max)
                        {
                            cod_info.xrpow_max = xrpow[j + l];
                        }
                    }
                }
            }

            return(false);
        }
예제 #26
0
        internal virtual int VBR_encode_frame(
            LameInternalFlags gfc,
            float[][][] xr34orig,
            float[][][] l3_xmin,
            int[][] max_bits)
        {
            var sfwork_ = Arrays.ReturnRectangularArray <int>(2, 2, L3Side.SFBMAX);

            var vbrsfmin_ = Arrays.ReturnRectangularArray <int>(2, 2, L3Side.SFBMAX);

            var that_ = Arrays.ReturnRectangularArray <algo_t>(2, 2);

            var ngr = gfc.mode_gr;

            var nch = gfc.channels_out;

            var max_nbits_ch = Arrays.ReturnRectangularArray <int>(2, 2);
            var max_nbits_gr = new int[2];
            var max_nbits_fr = 0;

            var use_nbits_ch = Arrays.ReturnRectangularArray <int>(2, 2);
            var use_nbits_gr = new int[2];
            var use_nbits_fr = 0;

            /*
             * set up some encoding parameters
             */
            for (var gr = 0; gr < ngr; ++gr)
            {
                max_nbits_gr[gr] = 0;
                for (var ch = 0; ch < nch; ++ch)
                {
                    max_nbits_ch[gr][ch]   = max_bits[gr][ch];
                    use_nbits_ch[gr][ch]   = 0;
                    max_nbits_gr[gr]      += max_bits[gr][ch];
                    max_nbits_fr          += max_bits[gr][ch];
                    that_[gr][ch]          = new algo_t();
                    that_[gr][ch].gfc      = gfc;
                    that_[gr][ch].cod_info = gfc.l3_side.tt[gr][ch];
                    that_[gr][ch].xr34orig = xr34orig[gr][ch];
                    if (that_[gr][ch].cod_info.block_type == Encoder.SHORT_TYPE)
                    {
                        that_[gr][ch].alloc = new ShortBlockConstrain(this);
                    }
                    else
                    {
                        that_[gr][ch].alloc = new LongBlockConstrain(this);
                    }
                } // for ch
            }

            /*
             * searches scalefactors
             */
            for (var gr = 0; gr < ngr; ++gr)
            {
                for (var ch = 0; ch < nch; ++ch)
                {
                    if (max_bits[gr][ch] > 0)
                    {
                        var that     = that_[gr][ch];
                        var sfwork   = sfwork_[gr][ch];
                        var vbrsfmin = vbrsfmin_[gr][ch];
                        int vbrmax;
                        vbrmax = block_sf(that, l3_xmin[gr][ch], sfwork, vbrsfmin);
                        that.alloc.alloc(that, sfwork, vbrsfmin, vbrmax);
                        bitcount(that);
                    }
                }
            }

            /*
             * encode 'as is'
             */
            use_nbits_fr = 0;
            for (var gr = 0; gr < ngr; ++gr)
            {
                use_nbits_gr[gr] = 0;
                for (var ch = 0; ch < nch; ++ch)
                {
                    var that = that_[gr][ch];
                    if (max_bits[gr][ch] > 0)
                    {
                        var max_nonzero_coeff = that.cod_info.max_nonzero_coeff;
                        Debug.Assert(max_nonzero_coeff < 576);
                        Arrays.Fill(that.cod_info.l3_enc, max_nonzero_coeff, 576, 0);
                        quantizeAndCountBits(that);
                    }

                    use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch);
                    use_nbits_gr[gr]    += use_nbits_ch[gr][ch];
                } // for ch

                use_nbits_fr += use_nbits_gr[gr];
            }

            /*
             * check bit constrains
             */
            if (use_nbits_fr <= max_nbits_fr)
            {
                var ok = true;
                for (var gr = 0; gr < ngr; ++gr)
                {
                    if (use_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE)
                    {
                        ok = false;
                    }

                    for (var ch = 0; ch < nch; ++ch)
                    {
                        if (use_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                        {
                            ok = false;
                        }
                    }
                }

                if (ok)
                {
                    return(use_nbits_fr);
                }
            }

            /*
             * OK, we are in trouble and have to define how many bits are to be used
             * for each granule
             */
            {
                var ok     = true;
                var sum_fr = 0;
                for (var gr = 0; gr < ngr; ++gr)
                {
                    max_nbits_gr[gr] = 0;
                    for (var ch = 0; ch < nch; ++ch)
                    {
                        if (use_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                        {
                            max_nbits_ch[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL;
                        }
                        else
                        {
                            max_nbits_ch[gr][ch] = use_nbits_ch[gr][ch];
                        }

                        max_nbits_gr[gr] += max_nbits_ch[gr][ch];
                    }

                    if (max_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE)
                    {
                        var   f = new float[2];
                        float s = 0;
                        for (var ch = 0; ch < nch; ++ch)
                        {
                            if (max_nbits_ch[gr][ch] > 0)
                            {
                                f[ch] = (float)Math.Sqrt(Math.Sqrt(max_nbits_ch[gr][ch]));
                                s    += f[ch];
                            }
                            else
                            {
                                f[ch] = 0;
                            }
                        }

                        for (var ch = 0; ch < nch; ++ch)
                        {
                            if (s > 0)
                            {
                                max_nbits_ch[gr][ch] = (int)(LameInternalFlags.MAX_BITS_PER_GRANULE * f[ch] / s);
                            }
                            else
                            {
                                max_nbits_ch[gr][ch] = 0;
                            }
                        }

                        if (nch > 1)
                        {
                            if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32)
                            {
                                max_nbits_ch[gr][1] += max_nbits_ch[gr][0];
                                max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32;
                                max_nbits_ch[gr][0]  = use_nbits_ch[gr][0] + 32;
                            }

                            if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32)
                            {
                                max_nbits_ch[gr][0] += max_nbits_ch[gr][1];
                                max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32;
                                max_nbits_ch[gr][1]  = use_nbits_ch[gr][1] + 32;
                            }

                            if (max_nbits_ch[gr][0] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                            {
                                max_nbits_ch[gr][0] = LameInternalFlags.MAX_BITS_PER_CHANNEL;
                            }

                            if (max_nbits_ch[gr][1] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                            {
                                max_nbits_ch[gr][1] = LameInternalFlags.MAX_BITS_PER_CHANNEL;
                            }
                        }

                        max_nbits_gr[gr] = 0;
                        for (var ch = 0; ch < nch; ++ch)
                        {
                            max_nbits_gr[gr] += max_nbits_ch[gr][ch];
                        }
                    }

                    sum_fr += max_nbits_gr[gr];
                }

                if (sum_fr > max_nbits_fr)
                {
                    {
                        var   f = new float[2];
                        float s = 0;
                        for (var gr = 0; gr < ngr; ++gr)
                        {
                            if (max_nbits_gr[gr] > 0)
                            {
                                f[gr] = (float)Math.Sqrt(max_nbits_gr[gr]);
                                s    += f[gr];
                            }
                            else
                            {
                                f[gr] = 0;
                            }
                        }

                        for (var gr = 0; gr < ngr; ++gr)
                        {
                            if (s > 0)
                            {
                                max_nbits_gr[gr] = (int)(max_nbits_fr * f[gr] / s);
                            }
                            else
                            {
                                max_nbits_gr[gr] = 0;
                            }
                        }
                    }
                    if (ngr > 1)
                    {
                        if (max_nbits_gr[0] > use_nbits_gr[0] + 125)
                        {
                            max_nbits_gr[1] += max_nbits_gr[0];
                            max_nbits_gr[1] -= use_nbits_gr[0] + 125;
                            max_nbits_gr[0]  = use_nbits_gr[0] + 125;
                        }

                        if (max_nbits_gr[1] > use_nbits_gr[1] + 125)
                        {
                            max_nbits_gr[0] += max_nbits_gr[1];
                            max_nbits_gr[0] -= use_nbits_gr[1] + 125;
                            max_nbits_gr[1]  = use_nbits_gr[1] + 125;
                        }

                        for (var gr = 0; gr < ngr; ++gr)
                        {
                            if (max_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE)
                            {
                                max_nbits_gr[gr] = LameInternalFlags.MAX_BITS_PER_GRANULE;
                            }
                        }
                    }

                    for (var gr = 0; gr < ngr; ++gr)
                    {
                        var   f = new float[2];
                        float s = 0;
                        for (var ch = 0; ch < nch; ++ch)
                        {
                            if (max_nbits_ch[gr][ch] > 0)
                            {
                                f[ch] = (float)Math.Sqrt(max_nbits_ch[gr][ch]);
                                s    += f[ch];
                            }
                            else
                            {
                                f[ch] = 0;
                            }
                        }

                        for (var ch = 0; ch < nch; ++ch)
                        {
                            if (s > 0)
                            {
                                max_nbits_ch[gr][ch] = (int)(max_nbits_gr[gr] * f[ch] / s);
                            }
                            else
                            {
                                max_nbits_ch[gr][ch] = 0;
                            }
                        }

                        if (nch > 1)
                        {
                            if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32)
                            {
                                max_nbits_ch[gr][1] += max_nbits_ch[gr][0];
                                max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32;
                                max_nbits_ch[gr][0]  = use_nbits_ch[gr][0] + 32;
                            }

                            if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32)
                            {
                                max_nbits_ch[gr][0] += max_nbits_ch[gr][1];
                                max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32;
                                max_nbits_ch[gr][1]  = use_nbits_ch[gr][1] + 32;
                            }

                            for (var ch = 0; ch < nch; ++ch)
                            {
                                if (max_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                                {
                                    max_nbits_ch[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL;
                                }
                            }
                        }
                    }
                }

                /* sanity check */
                sum_fr = 0;
                for (var gr = 0; gr < ngr; ++gr)
                {
                    var sum_gr = 0;
                    for (var ch = 0; ch < nch; ++ch)
                    {
                        sum_gr += max_nbits_ch[gr][ch];
                        if (max_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL)
                        {
                            ok = false;
                        }
                    }

                    sum_fr += sum_gr;
                    if (sum_gr > LameInternalFlags.MAX_BITS_PER_GRANULE)
                    {
                        ok = false;
                    }
                }

                if (sum_fr > max_nbits_fr)
                {
                    ok = false;
                }

                if (!ok)
                {
                    for (var gr = 0; gr < ngr; ++gr)
                    {
                        for (var ch = 0; ch < nch; ++ch)
                        {
                            max_nbits_ch[gr][ch] = max_bits[gr][ch];
                        }
                    }
                }
            }
            /* we already called the 'best_scalefac_store' function, so we need to reset some variables before we can do it again.  */
            for (var ch = 0; ch < nch; ++ch)
            {
                gfc.l3_side.scfsi[ch][0] = 0;
                gfc.l3_side.scfsi[ch][1] = 0;
                gfc.l3_side.scfsi[ch][2] = 0;
                gfc.l3_side.scfsi[ch][3] = 0;
            }

            for (var gr = 0; gr < ngr; ++gr)
            {
                for (var ch = 0; ch < nch; ++ch)
                {
                    gfc.l3_side.tt[gr][ch].scalefac_compress = 0;
                }
            }

            /* alter our encoded data, until it fits into the target bitrate  */
            use_nbits_fr = 0;
            for (var gr = 0; gr < ngr; ++gr)
            {
                use_nbits_gr[gr] = 0;
                for (var ch = 0; ch < nch; ++ch)
                {
                    var that = that_[gr][ch];
                    use_nbits_ch[gr][ch] = 0;
                    if (max_bits[gr][ch] > 0)
                    {
                        var sfwork   = sfwork_[gr][ch];
                        var vbrsfmin = vbrsfmin_[gr][ch];
                        cutDistribution(sfwork, sfwork, that.cod_info.global_gain);
                        outOfBitsStrategy(that, sfwork, vbrsfmin, max_nbits_ch[gr][ch]);
                    }

                    use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch);
                    Debug.Assert(use_nbits_ch[gr][ch] <= max_nbits_ch[gr][ch]);
                    use_nbits_gr[gr] += use_nbits_ch[gr][ch];
                } // for ch

                use_nbits_fr += use_nbits_gr[gr];
            }

            /* check bit constrains, but it should always be ok, if there are no bugs ;-)  */
            if (use_nbits_fr <= max_nbits_fr)
            {
                return(use_nbits_fr);
            }

            throw new Exception(
                      string.Format(
                          "INTERNAL ERROR IN VBR NEW CODE (1313), please send bug report\n" +
                          "maxbits={0:D} usedbits={1:D}\n",
                          max_nbits_fr,
                          use_nbits_fr));
        }
예제 #27
0
        /// <summary>
        ///     <PRE>
        ///         copy data out of the internal MP3 bit buffer into a user supplied
        ///         unsigned char buffer.
        ///         mp3data=0      indicates data in buffer is an id3tags and VBR tags
        ///         mp3data=1      data is real mp3 frame data.
        ///     </PRE>
        /// </summary>
        internal int copy_buffer(LameInternalFlags gfc, byte[] buffer, int bufferPos, int size, int mp3data)
        {
            var minimum = bufByteIdx + 1;

            if (minimum <= 0)
            {
                return(0);
            }

            if (size != 0 && minimum > size)
            {
                return(-1);
            }

            Array.Copy(buf, 0, buffer, bufferPos, minimum);
            bufByteIdx = -1;
            bufBitIdx  = 0;

            if (mp3data != 0)
            {
                var crc = new int[1];
                crc[0] = gfc.nMusicCRC;
                vbr.updateMusicCRC(crc, buffer, bufferPos, minimum);
                gfc.nMusicCRC = crc[0];

                /// <summary>
                /// sum number of bytes belonging to the mp3 stream this info will be
                /// written into the Xing/LAME header for seeking
                /// </summary>
                if (minimum > 0)
                {
                    gfc.VBR_seek_table.nBytesWritten += minimum;
                }

                if (gfc.decode_on_the_fly)
                {
                    // decode the frame

                    var pcm_buf     = Arrays.ReturnRectangularArray <float>(2, 1152);
                    var mp3_in      = minimum;
                    var samples_out = -1;
                    int i;

                    /* re-synthesis to pcm. Repeat until we get a samples_out=0 */
                    while (samples_out != 0)
                    {
                        samples_out = mpg.hip_decode1_unclipped(
                            gfc.hip,
                            buffer,
                            bufferPos,
                            mp3_in,
                            pcm_buf[0],
                            pcm_buf[1]);

                        /*
                         * samples_out = 0: need more data to decode samples_out =
                         * -1: error. Lets assume 0 pcm output samples_out = number
                         * of samples output
                         */

                        /*
                         * set the lenght of the mp3 input buffer to zero, so that
                         * in the next iteration of the loop we will be querying
                         * mpglib about buffered data
                         */
                        mp3_in = 0;

                        if (samples_out == -1)
                        {
                            samples_out = 0;
                        }

                        if (samples_out > 0)
                        {
                            /* process the PCM data */

                            /*
                             * this should not be possible, and indicates we have
                             * overflown the pcm_buf buffer
                             */
                            Debug.Assert(samples_out <= 1152);

                            if (gfc.findPeakSample)
                            {
                                for (i = 0; i < samples_out; i++)
                                {
                                    if (pcm_buf[0][i] > gfc.PeakSample)
                                    {
                                        gfc.PeakSample = pcm_buf[0][i];
                                    }
                                    else if (-pcm_buf[0][i] > gfc.PeakSample)
                                    {
                                        gfc.PeakSample = -pcm_buf[0][i];
                                    }
                                }

                                if (gfc.channels_out > 1)
                                {
                                    for (i = 0; i < samples_out; i++)
                                    {
                                        if (pcm_buf[1][i] > gfc.PeakSample)
                                        {
                                            gfc.PeakSample = pcm_buf[1][i];
                                        }
                                        else if (-pcm_buf[1][i] > gfc.PeakSample)
                                        {
                                            gfc.PeakSample = -pcm_buf[1][i];
                                        }
                                    }
                                }
                            }

                            if (gfc.findReplayGain)
                            {
                                if (ga.AnalyzeSamples(
                                        gfc.rgdata,
                                        pcm_buf[0],
                                        0,
                                        pcm_buf[1],
                                        0,
                                        samples_out,
                                        gfc.channels_out) == GainAnalysis.GAIN_ANALYSIS_ERROR)
                                {
                                    return(-6);
                                }
                            }
                        } // if (samples_out>0)
                    }     // while (samples_out!=0)
                }         // if (gfc.decode_on_the_fly)
            }             // if (mp3data)

            return(minimum);
        }