Newer
Older
DH_Apicture / scripts / new_node_modules / lamejs / src / js / BitStream.js
@zhangqy zhangqy 28 days ago 35 KB first commit
var common = require('./common.js');
var System = common.System;
var VbrMode = common.VbrMode;
var Float = common.Float;
var ShortBlock = common.ShortBlock;
var Util = common.Util;
var Arrays = common.Arrays;
var new_array_n = common.new_array_n;
var new_byte = common.new_byte;
var new_double = common.new_double;
var new_float = common.new_float;
var new_float_n = common.new_float_n;
var new_int = common.new_int;
var new_int_n = common.new_int_n;
var assert = common.assert;

var Takehiro = require('./Takehiro.js');
var Tables = require('./Tables.js');
var Encoder = require('./Encoder.js');
var LameInternalFlags = require('./LameInternalFlags.js');

BitStream.EQ = function (a, b) {
    return (Math.abs(a) > Math.abs(b)) ? (Math.abs((a) - (b)) <= (Math
        .abs(a) * 1e-6))
        : (Math.abs((a) - (b)) <= (Math.abs(b) * 1e-6));
};

BitStream.NEQ = function (a, b) {
    return !BitStream.EQ(a, b);
};

function BitStream () {
    var Lame = require('./Lame.js');
    var self = this;
    var CRC16_POLYNOMIAL = 0x8005;

    /*
     * we work with ints, so when doing bit manipulation, we limit ourselves to
     * MAX_LENGTH-2 just to be on the safe side
     */
    var MAX_LENGTH = 32;

    //GainAnalysis ga;
    //MPGLib mpg;
    //Version ver;
    //VBRTag vbr;
    var ga = null;
    var mpg = null;
    var ver = null;
    var vbr = null;

    //public final void setModules(GainAnalysis ga, MPGLib mpg, Version ver,
    //	VBRTag vbr) {

    this.setModules = function (_ga, _mpg, _ver, _vbr) {
        ga = _ga;
        mpg = _mpg;
        ver = _ver;
        vbr = _vbr;
    };

    /**
     * Bit stream buffer.
     */
    //private byte[] buf;
    var buf = null;
    /**
     * Bit counter of bit stream.
     */
    var totbit = 0;
    /**
     * Pointer to top byte in buffer.
     */
    var bufByteIdx = 0;
    /**
     * Pointer to top bit of top byte in buffer.
     */
    var bufBitIdx = 0;

    /**
     * compute bitsperframe and mean_bits for a layer III frame
     */
    this.getframebits = function (gfp) {
        var gfc = gfp.internal_flags;
        var bit_rate;

        /* get bitrate in kbps [?] */
        if (gfc.bitrate_index != 0)
            bit_rate = Tables.bitrate_table[gfp.version][gfc.bitrate_index];
        else
            bit_rate = gfp.brate;
        assert(8 <= bit_rate && bit_rate <= 640);

        /* main encoding routine toggles padding on and off */
        /* one Layer3 Slot consists of 8 bits */
        var bytes = 0 | (gfp.version + 1) * 72000 * bit_rate / gfp.out_samplerate + gfc.padding;
        return 8 * bytes;
    };

    function putheader_bits (gfc) {
        System.arraycopy(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);
    }

    /**
     * write j bits into the bit stream
     */
    function putbits2 (gfc, val, j) {
        assert(j < MAX_LENGTH - 2);

        while (j > 0) {
            var k;
            if (bufBitIdx == 0) {
                bufBitIdx = 8;
                bufByteIdx++;
                assert(bufByteIdx < Lame.LAME_MAXMP3BUFFER);
                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;

            assert(j < MAX_LENGTH);
            /* 32 too large on 32 bit machines */
            assert(bufBitIdx < MAX_LENGTH);

            buf[bufByteIdx] |= ((val >> j) << bufBitIdx);
            totbit += k;
        }
    }

    /**
     * write j bits into the bit stream, ignoring frame headers
     */
    function putbits_noheaders (gfc, val, j) {
        assert(j < MAX_LENGTH - 2);

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

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

            bufBitIdx -= k;

            assert(j < MAX_LENGTH);
            /* 32 too large on 32 bit machines */
            assert(bufBitIdx < MAX_LENGTH);

            buf[bufByteIdx] |= ((val >> j) << bufBitIdx);
            totbit += k;
        }
    }

    /**
     * Some combinations of bitrate, Fs, and stereo make it impossible to stuff
     * out a frame using just main_data, due to the limited number of bits to
     * indicate main_data_length. In these situations, we put stuffing bits into
     * the ancillary data...
     */
    function drain_into_ancillary (gfp, remainingBits) {
        var gfc = gfp.internal_flags;
        var i;
        assert(remainingBits >= 0);

        if (remainingBits >= 8) {
            putbits2(gfc, 0x4c, 8);
            remainingBits -= 8;
        }
        if (remainingBits >= 8) {
            putbits2(gfc, 0x41, 8);
            remainingBits -= 8;
        }
        if (remainingBits >= 8) {
            putbits2(gfc, 0x4d, 8);
            remainingBits -= 8;
        }
        if (remainingBits >= 8) {
            putbits2(gfc, 0x45, 8);
            remainingBits -= 8;
        }

        if (remainingBits >= 32) {
            var version = ver.getLameShortVersion();
            if (remainingBits >= 32)
                for (i = 0; i < version.length && remainingBits >= 8; ++i) {
                    remainingBits -= 8;
                    putbits2(gfc, version.charAt(i), 8);
                }
        }

        for (; remainingBits >= 1; remainingBits -= 1) {
            putbits2(gfc, gfc.ancillary_flag, 1);
            gfc.ancillary_flag ^= (!gfp.disable_reservoir ? 1 : 0);
        }

        assert(remainingBits == 0);

    }

    /**
     * write N bits into the header
     */
    function writeheader (gfc, val, j) {
        var ptr = gfc.header[gfc.h_ptr].ptr;

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

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

    function CRC_update (value, crc) {
        value <<= 8;
        for (var i = 0; i < 8; i++) {
            value <<= 1;
            crc <<= 1;

            if ((((crc ^ value) & 0x10000) != 0))
                crc ^= CRC16_POLYNOMIAL;
        }
        return crc;
    }

    this.CRC_writeheader = function (gfc, 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] = (byte)(crc & 255);
    };

    function encodeSideInfo2 (gfp, bitsPerFrame) {
        var gfc = gfp.internal_flags;
        var l3_side;
        var gr, ch;

        l3_side = gfc.l3_side;
        gfc.header[gfc.h_ptr].ptr = 0;
        Arrays.fill(gfc.header[gfc.h_ptr].buf, 0, gfc.sideinfo_len, 0);
        if (gfp.out_samplerate < 16000)
            writeheader(gfc, 0xffe, 12);
        else
            writeheader(gfc, 0xfff, 12);
        writeheader(gfc, (gfp.version), 1);
        writeheader(gfc, 4 - 3, 2);
        writeheader(gfc, (!gfp.error_protection ? 1 : 0), 1);
        writeheader(gfc, (gfc.bitrate_index), 4);
        writeheader(gfc, (gfc.samplerate_index), 2);
        writeheader(gfc, (gfc.padding), 1);
        writeheader(gfc, (gfp.extension), 1);
        writeheader(gfc, (gfp.mode.ordinal()), 2);
        writeheader(gfc, (gfc.mode_ext), 2);
        writeheader(gfc, (gfp.copyright), 1);
        writeheader(gfc, (gfp.original), 1);
        writeheader(gfc, (gfp.emphasis), 2);
        if (gfp.error_protection) {
            writeheader(gfc, 0, 16);
            /* dummy */
        }

        if (gfp.version == 1) {
            /* MPEG1 */
            assert(l3_side.main_data_begin >= 0);
            writeheader(gfc, (l3_side.main_data_begin), 9);

            if (gfc.channels_out == 2)
                writeheader(gfc, l3_side.private_bits, 3);
            else
                writeheader(gfc, l3_side.private_bits, 5);

            for (ch = 0; ch < gfc.channels_out; ch++) {
                var band;
                for (band = 0; band < 4; band++) {
                    writeheader(gfc, l3_side.scfsi[ch][band], 1);
                }
            }

            for (gr = 0; gr < 2; gr++) {
                for (ch = 0; ch < gfc.channels_out; ch++) {
                    var gi = l3_side.tt[gr][ch];
                    writeheader(gfc, gi.part2_3_length + gi.part2_length, 12);
                    writeheader(gfc, gi.big_values / 2, 9);
                    writeheader(gfc, gi.global_gain, 8);
                    writeheader(gfc, gi.scalefac_compress, 4);

                    if (gi.block_type != Encoder.NORM_TYPE) {
                        writeheader(gfc, 1, 1);
                        /* window_switching_flag */
                        writeheader(gfc, gi.block_type, 2);
                        writeheader(gfc, gi.mixed_block_flag, 1);

                        if (gi.table_select[0] == 14)
                            gi.table_select[0] = 16;
                        writeheader(gfc, gi.table_select[0], 5);
                        if (gi.table_select[1] == 14)
                            gi.table_select[1] = 16;
                        writeheader(gfc, gi.table_select[1], 5);

                        writeheader(gfc, gi.subblock_gain[0], 3);
                        writeheader(gfc, gi.subblock_gain[1], 3);
                        writeheader(gfc, gi.subblock_gain[2], 3);
                    } else {
                        writeheader(gfc, 0, 1);
                        /* window_switching_flag */
                        if (gi.table_select[0] == 14)
                            gi.table_select[0] = 16;
                        writeheader(gfc, gi.table_select[0], 5);
                        if (gi.table_select[1] == 14)
                            gi.table_select[1] = 16;
                        writeheader(gfc, gi.table_select[1], 5);
                        if (gi.table_select[2] == 14)
                            gi.table_select[2] = 16;
                        writeheader(gfc, gi.table_select[2], 5);

                        assert(0 <= gi.region0_count && gi.region0_count < 16);
                        assert(0 <= gi.region1_count && gi.region1_count < 8);
                        writeheader(gfc, gi.region0_count, 4);
                        writeheader(gfc, gi.region1_count, 3);
                    }
                    writeheader(gfc, gi.preflag, 1);
                    writeheader(gfc, gi.scalefac_scale, 1);
                    writeheader(gfc, gi.count1table_select, 1);
                }
            }
        } else {
            /* MPEG2 */
            assert(l3_side.main_data_begin >= 0);
            writeheader(gfc, (l3_side.main_data_begin), 8);
            writeheader(gfc, l3_side.private_bits, gfc.channels_out);

            gr = 0;
            for (ch = 0; ch < gfc.channels_out; ch++) {
                var gi = l3_side.tt[gr][ch];
                writeheader(gfc, gi.part2_3_length + gi.part2_length, 12);
                writeheader(gfc, gi.big_values / 2, 9);
                writeheader(gfc, gi.global_gain, 8);
                writeheader(gfc, gi.scalefac_compress, 9);

                if (gi.block_type != Encoder.NORM_TYPE) {
                    writeheader(gfc, 1, 1);
                    /* window_switching_flag */
                    writeheader(gfc, gi.block_type, 2);
                    writeheader(gfc, gi.mixed_block_flag, 1);

                    if (gi.table_select[0] == 14)
                        gi.table_select[0] = 16;
                    writeheader(gfc, gi.table_select[0], 5);
                    if (gi.table_select[1] == 14)
                        gi.table_select[1] = 16;
                    writeheader(gfc, gi.table_select[1], 5);

                    writeheader(gfc, gi.subblock_gain[0], 3);
                    writeheader(gfc, gi.subblock_gain[1], 3);
                    writeheader(gfc, gi.subblock_gain[2], 3);
                } else {
                    writeheader(gfc, 0, 1);
                    /* window_switching_flag */
                    if (gi.table_select[0] == 14)
                        gi.table_select[0] = 16;
                    writeheader(gfc, gi.table_select[0], 5);
                    if (gi.table_select[1] == 14)
                        gi.table_select[1] = 16;
                    writeheader(gfc, gi.table_select[1], 5);
                    if (gi.table_select[2] == 14)
                        gi.table_select[2] = 16;
                    writeheader(gfc, gi.table_select[2], 5);

                    assert(0 <= gi.region0_count && gi.region0_count < 16);
                    assert(0 <= gi.region1_count && gi.region1_count < 8);
                    writeheader(gfc, gi.region0_count, 4);
                    writeheader(gfc, gi.region1_count, 3);
                }

                writeheader(gfc, gi.scalefac_scale, 1);
                writeheader(gfc, gi.count1table_select, 1);
            }
        }

        if (gfp.error_protection) {
            /* (jo) error_protection: add crc16 information to header */
            CRC_writeheader(gfc, gfc.header[gfc.h_ptr].buf);
        }

        {
            var old = gfc.h_ptr;
            assert(gfc.header[old].ptr == gfc.sideinfo_len * 8);

            gfc.h_ptr = (old + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1);
            gfc.header[gfc.h_ptr].write_timing = gfc.header[old].write_timing
                + bitsPerFrame;

            if (gfc.h_ptr == gfc.w_ptr) {
                /* yikes! we are out of header buffer space */
                System.err
                    .println("Error: MAX_HEADER_BUF too small in bitstream.c \n");
            }

        }
    }

    function huffman_coder_count1 (gfc, gi) {
        /* Write count1 area */
        var h = Tables.ht[gi.count1table_select + 32];
        var i, bits = 0;

        var ix = gi.big_values;
        var xr = gi.big_values;
        assert(gi.count1table_select < 2);

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

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

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

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

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

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

    /**
     * Implements the pseudocode of page 98 of the IS
     */
    function Huffmancode (gfc, tableindex, start, end, gi) {
        var h = Tables.ht[tableindex];
        var bits = 0;

        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;
                    assert(linbits_x1 <= h.linmax);
                    ext |= linbits_x1 << 1;
                    xbits = linbits;
                    x1 = 15;
                }

                if (x2 > 14) {
                    var linbits_x2 = x2 - 15;
                    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--;
            }

            assert((x1 | x2) < 16);

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

            assert(cbits <= MAX_LENGTH);
            assert(xbits <= MAX_LENGTH);

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

    /**
     * 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.
     */
    function ShortHuffmancodebits (gfc, 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;
    }

    function LongHuffmancodebits (gfc, gi) {
        var bigvalues, bits;
        var region1Start, region2Start;

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

        var i = gi.region0_count + 1;
        assert(0 <= i);
        assert(i < gfc.scalefac_band.l.length);
        region1Start = gfc.scalefac_band.l[i];
        i += gi.region1_count + 1;
        assert(0 <= i);
        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;
    }

    function writeMainData (gfp) {
        var gr, ch, sfb, data_bits, tot_bits = 0;
        var gfc = gfp.internal_flags;
        var l3_side = gfc.l3_side;

        if (gfp.version == 1) {
            /* MPEG 1 */
            for (gr = 0; gr < 2; gr++) {
                for (ch = 0; ch < gfc.channels_out; ch++) {
                    var gi = l3_side.tt[gr][ch];
                    var slen1 = Takehiro.slen1_tab[gi.scalefac_compress];
                    var slen2 = Takehiro.slen2_tab[gi.scalefac_compress];
                    data_bits = 0;
                    for (sfb = 0; sfb < gi.sfbdivide; sfb++) {
                        if (gi.scalefac[sfb] == -1)
                            continue;
                        /* scfsi is used */
                        putbits2(gfc, gi.scalefac[sfb], slen1);
                        data_bits += slen1;
                    }
                    for (; sfb < gi.sfbmax; sfb++) {
                        if (gi.scalefac[sfb] == -1)
                            continue;
                        /* scfsi is used */
                        putbits2(gfc, gi.scalefac[sfb], slen2);
                        data_bits += slen2;
                    }
                    assert(data_bits == gi.part2_length);

                    if (gi.block_type == Encoder.SHORT_TYPE) {
                        data_bits += ShortHuffmancodebits(gfc, gi);
                    } else {
                        data_bits += LongHuffmancodebits(gfc, gi);
                    }
                    data_bits += huffman_coder_count1(gfc, gi);
                    /* does bitcount in quantize.c agree with actual bit count? */
                    assert(data_bits == gi.part2_3_length + gi.part2_length);
                    tot_bits += data_bits;
                }
                /* for ch */
            }
            /* for gr */
        } else {
            /* MPEG 2 */
            gr = 0;
            for (ch = 0; ch < gfc.channels_out; ch++) {
                var gi = l3_side.tt[gr][ch];
                var i, sfb_partition, scale_bits = 0;
                assert(gi.sfb_partition_table != null);
                data_bits = 0;
                sfb = 0;
                sfb_partition = 0;

                if (gi.block_type == Encoder.SHORT_TYPE) {
                    for (; sfb_partition < 4; sfb_partition++) {
                        var sfbs = gi.sfb_partition_table[sfb_partition] / 3;
                        var slen = gi.slen[sfb_partition];
                        for (i = 0; i < sfbs; i++, sfb++) {
                            putbits2(gfc,
                                Math.max(gi.scalefac[sfb * 3 + 0], 0), slen);
                            putbits2(gfc,
                                Math.max(gi.scalefac[sfb * 3 + 1], 0), slen);
                            putbits2(gfc,
                                Math.max(gi.scalefac[sfb * 3 + 2], 0), slen);
                            scale_bits += 3 * slen;
                        }
                    }
                    data_bits += ShortHuffmancodebits(gfc, gi);
                } else {
                    for (; sfb_partition < 4; sfb_partition++) {
                        var sfbs = gi.sfb_partition_table[sfb_partition];
                        var slen = gi.slen[sfb_partition];
                        for (i = 0; i < sfbs; i++, sfb++) {
                            putbits2(gfc, Math.max(gi.scalefac[sfb], 0), slen);
                            scale_bits += slen;
                        }
                    }
                    data_bits += LongHuffmancodebits(gfc, gi);
                }
                data_bits += huffman_coder_count1(gfc, gi);
                /* does bitcount in quantize.c agree with actual bit count? */
                assert(data_bits == gi.part2_3_length);
                assert(scale_bits == gi.part2_length);
                tot_bits += scale_bits + data_bits;
            }
            /* for ch */
        }
        /* for gf */
        return tot_bits;
    }

    /* main_data */

    function TotalBytes () {
        this.total = 0;
    }

    /*
     * compute the number of bits required to flush all mp3 frames currently in
     * the buffer. This should be the same as the reservoir size. Only call this
     * routine between frames - i.e. only after all headers and data have been
     * added to the buffer by format_bitstream().
     *
     * Also compute total_bits_output = size of mp3 buffer (including frame
     * headers which may not have yet been send to the mp3 buffer) + number of
     * bits needed to flush all mp3 frames.
     *
     * total_bytes_output is the size of the mp3 output buffer if
     * lame_encode_flush_nogap() was called right now.
     */
    function compute_flushbits (gfp, total_bytes_output) {
        var gfc = gfp.internal_flags;
        var flushbits, remaining_headers;
        var bitsPerFrame;
        var last_ptr, first_ptr;
        first_ptr = gfc.w_ptr;
        /* first header to add to bitstream */
        last_ptr = gfc.h_ptr - 1;
        /* last header to add to bitstream */
        if (last_ptr == -1)
            last_ptr = LameInternalFlags.MAX_HEADER_BUF - 1;

        /* add this many bits to bitstream so we can flush all headers */
        flushbits = gfc.header[last_ptr].write_timing - totbit;
        total_bytes_output.total = flushbits;

        if (flushbits >= 0) {
            /* if flushbits >= 0, some headers have not yet been written */
            /* reduce flushbits by the size of the headers */
            remaining_headers = 1 + last_ptr - first_ptr;
            if (last_ptr < first_ptr)
                remaining_headers = 1 + last_ptr - first_ptr
                    + LameInternalFlags.MAX_HEADER_BUF;
            flushbits -= remaining_headers * 8 * gfc.sideinfo_len;
        }

        /*
         * finally, add some bits so that the last frame is complete these bits
         * are not necessary to decode the last frame, but some decoders will
         * ignore last frame if these bits are missing
         */
        bitsPerFrame = self.getframebits(gfp);
        flushbits += bitsPerFrame;
        total_bytes_output.total += bitsPerFrame;
        /* round up: */
        if ((total_bytes_output.total % 8) != 0)
            total_bytes_output.total = 1 + (total_bytes_output.total / 8);
        else
            total_bytes_output.total = (total_bytes_output.total / 8);
        total_bytes_output.total += bufByteIdx + 1;

        if (flushbits < 0) {
            System.err.println("strange error flushing buffer ... \n");
        }
        return flushbits;
    }

    this.flush_bitstream = function (gfp) {
        var gfc = gfp.internal_flags;
        var l3_side;
        var flushbits;
        var last_ptr = gfc.h_ptr - 1;
        /* last header to add to bitstream */
        if (last_ptr == -1)
            last_ptr = LameInternalFlags.MAX_HEADER_BUF - 1;
        l3_side = gfc.l3_side;

        if ((flushbits = compute_flushbits(gfp, new TotalBytes())) < 0)
            return;
        drain_into_ancillary(gfp, flushbits);

        /* check that the 100% of the last frame has been written to bitstream */
        assert(gfc.header[last_ptr].write_timing + this.getframebits(gfp) == totbit);

        /*
         * we have padded out all frames with ancillary data, which is the same
         * as filling the bitreservoir with ancillary data, so :
         */
        gfc.ResvSize = 0;
        l3_side.main_data_begin = 0;

        /* save the ReplayGain value */
        if (gfc.findReplayGain) {
            var RadioGain = ga.GetTitleGain(gfc.rgdata);
            assert(NEQ(RadioGain, GainAnalysis.GAIN_NOT_ENOUGH_SAMPLES));
            gfc.RadioGain = Math.floor(RadioGain * 10.0 + 0.5) | 0;
            /* round to nearest */
        }

        /* find the gain and scale change required for no clipping */
        if (gfc.findPeakSample) {
            gfc.noclipGainChange = Math.ceil(Math
                .log10(gfc.PeakSample / 32767.0) * 20.0 * 10.0) | 0;
            /* round up */

            if (gfc.noclipGainChange > 0) {
                /* clipping occurs */
                if (EQ(gfp.scale, 1.0) || EQ(gfp.scale, 0.0))
                    gfc.noclipScale = (Math
                        .floor((32767.0 / gfc.PeakSample) * 100.0) / 100.0);
                /* round down */
                else {
                    /*
                     * the user specified his own scaling factor. We could
                     * suggest the scaling factor of
                     * (32767.0/gfp.PeakSample)*(gfp.scale) but it's usually
                     * very inaccurate. So we'd rather not advice him on the
                     * scaling factor.
                     */
                    gfc.noclipScale = -1;
                }
            } else
                /* no clipping */
                gfc.noclipScale = -1;
        }
    };

    this.add_dummy_byte = function (gfp, val, n) {
        var gfc = gfp.internal_flags;
        var i;

        while (n-- > 0) {
            putbits_noheaders(gfc, val, 8);

            for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i)
                gfc.header[i].write_timing += 8;
        }
    };

    /**
     * This is called after a frame of audio has been quantized and coded. It
     * will write the encoded audio to the bitstream. Note that from a layer3
     * encoder's perspective the bit stream is primarily a series of main_data()
     * blocks, with header and side information inserted at the proper locations
     * to maintain framing. (See Figure A.7 in the IS).
     */
    this.format_bitstream = function (gfp) {
        var gfc = gfp.internal_flags;
        var l3_side;
        l3_side = gfc.l3_side;

        var bitsPerFrame = this.getframebits(gfp);
        drain_into_ancillary(gfp, l3_side.resvDrain_pre);

        encodeSideInfo2(gfp, bitsPerFrame);
        var bits = 8 * gfc.sideinfo_len;
        bits += writeMainData(gfp);
        drain_into_ancillary(gfp, l3_side.resvDrain_post);
        bits += l3_side.resvDrain_post;

        l3_side.main_data_begin += (bitsPerFrame - bits) / 8;

        /*
         * compare number of bits needed to clear all buffered mp3 frames with
         * what we think the resvsize is:
         */
        if (compute_flushbits(gfp, new TotalBytes()) != gfc.ResvSize) {
            System.err.println("Internal buffer inconsistency. flushbits <> ResvSize");
        }

        /*
         * compare main_data_begin for the next frame with what we think the
         * resvsize is:
         */
        if ((l3_side.main_data_begin * 8) != gfc.ResvSize) {
            System.err.printf("bit reservoir error: \n"
                + "l3_side.main_data_begin: %d \n"
                + "Resvoir size:             %d \n"
                + "resv drain (post)         %d \n"
                + "resv drain (pre)          %d \n"
                + "header and sideinfo:      %d \n"
                + "data bits:                %d \n"
                + "total bits:               %d (remainder: %d) \n"
                + "bitsperframe:             %d \n",
                8 * l3_side.main_data_begin, gfc.ResvSize,
                l3_side.resvDrain_post, l3_side.resvDrain_pre,
                8 * gfc.sideinfo_len, bits - l3_side.resvDrain_post - 8
                * gfc.sideinfo_len, bits, bits % 8, bitsPerFrame);

            System.err.println("This is a fatal error.  It has several possible causes:");
            System.err.println("90%%  LAME compiled with buggy version of gcc using advanced optimizations");
            System.err.println(" 9%%  Your system is overclocked");
            System.err.println(" 1%%  bug in LAME encoding library");

            gfc.ResvSize = l3_side.main_data_begin * 8;
        }
        //;
        assert(totbit % 8 == 0);

        if (totbit > 1000000000) {
            /*
             * to avoid totbit overflow, (at 8h encoding at 128kbs) lets reset
             * bit counter
             */
            var i;
            for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i)
                gfc.header[i].write_timing -= totbit;
            totbit = 0;
        }

        return 0;
    };

    /**
     * <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>
     */
    this.copy_buffer = function (gfc, buffer, bufferPos, size, mp3data) {
        var minimum = bufByteIdx + 1;
        if (minimum <= 0)
            return 0;
        if (size != 0 && minimum > size) {
            /* buffer is too small */
            return -1;
        }
        System.arraycopy(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];

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

            if (gfc.decode_on_the_fly) { /* decode the frame */
                var pcm_buf = new_float_n([2, 1152]);
                var mp3_in = minimum;
                var samples_out = -1;
                var 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) {
                        /*
                         * error decoding. Not fatal, but might screw up the
                         * ReplayGain tag. What should we do? Ignore for now
                         */
                        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
                         */
                        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;
    };

    this.init_bit_stream_w = function (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;
    };

    // From machine.h


}

module.exports = BitStream;