diff --git a/lame.all.js b/lame.all.js index bdd5a7e..0102a78 100644 --- a/lame.all.js +++ b/lame.all.js @@ -264,4357 +264,4357 @@ function Version() { } +/* + * MP3 huffman table selecting and bit counting + * + * Copyright (c) 1999-2005 Takehiro TOMINAGA + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ -function Presets() { - function VBRPresets(qual, comp, compS, - y, shThreshold, shThresholdS, - adj, adjShort, lower, - curve, sens, inter, - joint, mod, fix) { - this.vbr_q = qual; - this.quant_comp = comp; - this.quant_comp_s = compS; - this.expY = y; - this.st_lrm = shThreshold; - this.st_s = shThresholdS; - this.masking_adj = adj; - this.masking_adj_short = adjShort; - this.ath_lower = lower; - this.ath_curve = curve; - this.ath_sensitivity = sens; - this.interch = inter; - this.safejoint = joint; - this.sfb21mod = mod; - this.msfix = fix; - } +/* $Id: Takehiro.java,v 1.26 2011/05/24 20:48:06 kenchis Exp $ */ - function ABRPresets(kbps, comp, compS, - joint, fix, shThreshold, - shThresholdS, bass, sc, - mask, lower, curve, - interCh, sfScale) { - this.quant_comp = comp; - this.quant_comp_s = compS; - this.safejoint = joint; - this.nsmsfix = fix; - this.st_lrm = shThreshold; - this.st_s = shThresholdS; - this.nsbass = bass; - this.scale = sc; - this.masking_adj = mask; - this.ath_lower = lower; - this.ath_curve = curve; - this.interch = interCh; - this.sfscale = sfScale; - } +//package mp3; - var lame; +//import java.util.Arrays; - this.setModules = function (_lame) { - lame = _lame; - }; - /** - *
- * Switch mappings for VBR mode VBR_RH - * vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix - *- */ - var vbr_old_switch_map = [ - new VBRPresets(0, 9, 9, 0, 5.20, 125.0, -4.2, -6.3, 4.8, 1, 0, 0, 2, 21, 0.97), - new VBRPresets(1, 9, 9, 0, 5.30, 125.0, -3.6, -5.6, 4.5, 1.5, 0, 0, 2, 21, 1.35), - new VBRPresets(2, 9, 9, 0, 5.60, 125.0, -2.2, -3.5, 2.8, 2, 0, 0, 2, 21, 1.49), - new VBRPresets(3, 9, 9, 1, 5.80, 130.0, -1.8, -2.8, 2.6, 3, -4, 0, 2, 20, 1.64), - new VBRPresets(4, 9, 9, 1, 6.00, 135.0, -0.7, -1.1, 1.1, 3.5, -8, 0, 2, 0, 1.79), - new VBRPresets(5, 9, 9, 1, 6.40, 140.0, 0.5, 0.4, -7.5, 4, -12, 0.0002, 0, 0, 1.95), - new VBRPresets(6, 9, 9, 1, 6.60, 145.0, 0.67, 0.65, -14.7, 6.5, -19, 0.0004, 0, 0, 2.30), - new VBRPresets(7, 9, 9, 1, 6.60, 145.0, 0.8, 0.75, -19.7, 8, -22, 0.0006, 0, 0, 2.70), - new VBRPresets(8, 9, 9, 1, 6.60, 145.0, 1.2, 1.15, -27.5, 10, -23, 0.0007, 0, 0, 0), - new VBRPresets(9, 9, 9, 1, 6.60, 145.0, 1.6, 1.6, -36, 11, -25, 0.0008, 0, 0, 0), - new VBRPresets(10, 9, 9, 1, 6.60, 145.0, 2.0, 2.0, -36, 12, -25, 0.0008, 0, 0, 0) + +function Takehiro() { + + var qupvt = null; + this.qupvt = null; + + this.setModules = function (_qupvt) { + this.qupvt = _qupvt; + qupvt = _qupvt; + } + + function Bits(b) { + this.bits = 0 | b; + } + + var subdv_table = [[0, 0], /* 0 bands */ + [0, 0], /* 1 bands */ + [0, 0], /* 2 bands */ + [0, 0], /* 3 bands */ + [0, 0], /* 4 bands */ + [0, 1], /* 5 bands */ + [1, 1], /* 6 bands */ + [1, 1], /* 7 bands */ + [1, 2], /* 8 bands */ + [2, 2], /* 9 bands */ + [2, 3], /* 10 bands */ + [2, 3], /* 11 bands */ + [3, 4], /* 12 bands */ + [3, 4], /* 13 bands */ + [3, 4], /* 14 bands */ + [4, 5], /* 15 bands */ + [4, 5], /* 16 bands */ + [4, 6], /* 17 bands */ + [5, 6], /* 18 bands */ + [5, 6], /* 19 bands */ + [5, 7], /* 20 bands */ + [6, 7], /* 21 bands */ + [6, 7], /* 22 bands */ ]; /** - *
- * vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix - *+ * nonlinear quantization of xr More accurate formula than the ISO formula. + * Takes into account the fact that we are quantizing xr . ix, but we want + * ix^4/3 to be as close as possible to x^4/3. (taking the nearest int would + * mean ix is as close as possible to xr, which is different.) + * + * From Segher Boessenkool
- * Switch mappings for ABR mode - * - * kbps quant q_s safejoint nsmsfix st_lrm st_s ns-bass scale msk ath_lwr ath_curve interch , sfscale - *+ * Quantization function This function will select which lines to quantize + * and call the proper quantization function */ - var abr_switch_map = [ - new ABRPresets(8, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -30.0, 11, 0.0012, 1), /* 8, impossible to use in stereo */ - new ABRPresets(16, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -25.0, 11, 0.0010, 1), /* 16 */ - new ABRPresets(24, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -20.0, 11, 0.0010, 1), /* 24 */ - new ABRPresets(32, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -15.0, 11, 0.0010, 1), /* 32 */ - new ABRPresets(40, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 40 */ - new ABRPresets(48, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 48 */ - new ABRPresets(56, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -6.0, 11, 0.0008, 1), /* 56 */ - new ABRPresets(64, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -2.0, 11, 0.0008, 1), /* 64 */ - new ABRPresets(80, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, .0, 8, 0.0007, 1), /* 80 */ - new ABRPresets(96, 9, 9, 0, 2.50, 6.60, 145, 0, 0.95, 0, 1.0, 5.5, 0.0006, 1), /* 96 */ - new ABRPresets(112, 9, 9, 0, 2.25, 6.60, 145, 0, 0.95, 0, 2.0, 4.5, 0.0005, 1), /* 112 */ - new ABRPresets(128, 9, 9, 0, 1.95, 6.40, 140, 0, 0.95, 0, 3.0, 4, 0.0002, 1), /* 128 */ - new ABRPresets(160, 9, 9, 1, 1.79, 6.00, 135, 0, 0.95, -2, 5.0, 3.5, 0, 1), /* 160 */ - new ABRPresets(192, 9, 9, 1, 1.49, 5.60, 125, 0, 0.97, -4, 7.0, 3, 0, 0), /* 192 */ - new ABRPresets(224, 9, 9, 1, 1.25, 5.20, 125, 0, 0.98, -6, 9.0, 2, 0, 0), /* 224 */ - new ABRPresets(256, 9, 9, 1, 0.97, 5.20, 125, 0, 1.00, -8, 10.0, 1, 0, 0), /* 256 */ - new ABRPresets(320, 9, 9, 1, 0.90, 5.20, 125, 0, 1.00, -10, 12.0, 0, 0, 0) /* 320 */ - ]; + function quantize_xrpow(xp, pi, istep, codInfo, prevNoise) { + /* quantize on xr^(3/4) instead of xr */ + var sfb; + var sfbmax; + var j = 0; + var prev_data_use; + var accumulate = 0; + var accumulate01 = 0; + var xpPos = 0; + var iData = pi; + var iDataPos = 0; + var acc_iData = iData; + var acc_iDataPos = 0; + var acc_xp = xp; + var acc_xpPos = 0; - function apply_abr_preset(gfp, preset, enforce) { - /* Variables for the ABR stuff */ - var actual_bitrate = preset; + /* + * Reusing previously computed data does not seems to work if global + * gain is changed. Finding why it behaves this way would allow to use a + * cache of previously computed values (let's 10 cached values per sfb) + * that would probably provide a noticeable speedup + */ + prev_data_use = (prevNoise != null && (codInfo.global_gain == prevNoise.global_gain)); - var r = lame.nearestBitrateFullIndex(preset); + if (codInfo.block_type == Encoder.SHORT_TYPE) + sfbmax = 38; + else + sfbmax = 21; - gfp.VBR = VbrMode.vbr_abr; - gfp.VBR_mean_bitrate_kbps = actual_bitrate; - gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, 320); - gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, 8); - gfp.brate = gfp.VBR_mean_bitrate_kbps; - if (gfp.VBR_mean_bitrate_kbps > 320) { - gfp.disable_reservoir = true; - } + for (sfb = 0; sfb <= sfbmax; sfb++) { + var step = -1; - /* parameters for which there is no proper set/get interface */ - if (abr_switch_map[r].safejoint > 0) - gfp.exp_nspsytune = gfp.exp_nspsytune | 2; - /* safejoint */ + if (prev_data_use || codInfo.block_type == Encoder.NORM_TYPE) { + step = codInfo.global_gain + - ((codInfo.scalefac[sfb] + (codInfo.preflag != 0 ? qupvt.pretab[sfb] + : 0)) << (codInfo.scalefac_scale + 1)) + - codInfo.subblock_gain[codInfo.window[sfb]] * 8; + } + if (prev_data_use && (prevNoise.step[sfb] == step)) { + /* + * do not recompute this part, but compute accumulated lines + */ + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_xpPos, + acc_iData, acc_iDataPos); + accumulate = 0; + } + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + } + } else { /* should compute this part */ + var l = codInfo.width[sfb]; - if (abr_switch_map[r].sfscale > 0) { - gfp.internal_flags.noise_shaping = 2; - } - /* ns-bass tweaks */ - if (Math.abs(abr_switch_map[r].nsbass) > 0) { - var k = (int)(abr_switch_map[r].nsbass * 4); - if (k < 0) - k += 64; - gfp.exp_nspsytune = gfp.exp_nspsytune | (k << 2); - } + if ((j + codInfo.width[sfb]) > codInfo.max_nonzero_coeff) { + /* do not compute upper zero part */ + var usefullsize; + usefullsize = codInfo.max_nonzero_coeff - j + 1; + Arrays.fill(pi, codInfo.max_nonzero_coeff, 576, 0); + l = usefullsize; - if (enforce != 0) - gfp.quant_comp = abr_switch_map[r].quant_comp; - else if (!(Math.abs(gfp.quant_comp - -1) > 0)) - gfp.quant_comp = abr_switch_map[r].quant_comp; - // SET_OPTION(quant_comp, abr_switch_map[r].quant_comp, -1); - if (enforce != 0) - gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; - else if (!(Math.abs(gfp.quant_comp_short - -1) > 0)) - gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; - // SET_OPTION(quant_comp_short, abr_switch_map[r].quant_comp_s, -1); + if (l < 0) { + l = 0; + } - if (enforce != 0) - gfp.msfix = abr_switch_map[r].nsmsfix; - else if (!(Math.abs(gfp.msfix - -1) > 0)) - gfp.msfix = abr_switch_map[r].nsmsfix; - // SET_OPTION(msfix, abr_switch_map[r].nsmsfix, -1); + /* no need to compute higher sfb values */ + sfb = sfbmax + 1; + } - if (enforce != 0) - gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; - else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre - -1) > 0)) - gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; - // SET_OPTION(short_threshold_lrm, abr_switch_map[r].st_lrm, -1); - if (enforce != 0) - gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; - else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre_s - -1) > 0)) - gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; - // SET_OPTION(short_threshold_s, abr_switch_map[r].st_s, -1); + /* accumulate lines to quantize */ + if (0 == accumulate && 0 == accumulate01) { + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + if (prevNoise != null && prevNoise.sfb_count1 > 0 + && sfb >= prevNoise.sfb_count1 + && prevNoise.step[sfb] > 0 + && step >= prevNoise.step[sfb]) { - /* - * ABR seems to have big problems with clipping, especially at low - * bitrates - */ - /* - * so we compensate for that here by using a scale value depending on - * bitrate - */ - if (enforce != 0) - gfp.scale = abr_switch_map[r].scale; - else if (!(Math.abs(gfp.scale - -1) > 0)) - gfp.scale = abr_switch_map[r].scale; - // SET_OPTION(scale, abr_switch_map[r].scale, -1); + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate = 0; + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + accumulate01 += l; + } else { + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + accumulate += l; + } - if (enforce != 0) - gfp.maskingadjust = abr_switch_map[r].masking_adj; - else if (!(Math.abs(gfp.maskingadjust - 0) > 0)) - gfp.maskingadjust = abr_switch_map[r].masking_adj; - // SET_OPTION(maskingadjust, abr_switch_map[r].masking_adj, 0); - if (abr_switch_map[r].masking_adj > 0) { - if (enforce != 0) - gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); - else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) - gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); - // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * - // .9, 0); - } else { - if (enforce != 0) - gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); - else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) - gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); - // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * - // 1.1, 0); - } - - if (enforce != 0) - gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; - else if (!(Math.abs((-gfp.ATHlower * 10.) - 0) > 0)) - gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; - // SET_OPTION(ATHlower, abr_switch_map[r].ath_lower, 0); - if (enforce != 0) - gfp.ATHcurve = abr_switch_map[r].ath_curve; - else if (!(Math.abs(gfp.ATHcurve - -1) > 0)) - gfp.ATHcurve = abr_switch_map[r].ath_curve; - // SET_OPTION(ATHcurve, abr_switch_map[r].ath_curve, -1); - - if (enforce != 0) - gfp.interChRatio = abr_switch_map[r].interch; - else if (!(Math.abs(gfp.interChRatio - -1) > 0)) - gfp.interChRatio = abr_switch_map[r].interch; - // SET_OPTION(interChRatio, abr_switch_map[r].interch, -1); - - return preset; - } - - this.apply_preset = function(gfp, preset, enforce) { - /* translate legacy presets */ - switch (preset) { - case Lame.R3MIX: - { - preset = Lame.V3; - gfp.VBR = VbrMode.vbr_mtrh; - break; - } - case Lame.MEDIUM: - { - preset = Lame.V4; - gfp.VBR = VbrMode.vbr_rh; - break; - } - case Lame.MEDIUM_FAST: - { - preset = Lame.V4; - gfp.VBR = VbrMode.vbr_mtrh; - break; - } - case Lame.STANDARD: - { - preset = Lame.V2; - gfp.VBR = VbrMode.vbr_rh; - break; - } - case Lame.STANDARD_FAST: - { - preset = Lame.V2; - gfp.VBR = VbrMode.vbr_mtrh; - break; - } - case Lame.EXTREME: - { - preset = Lame.V0; - gfp.VBR = VbrMode.vbr_rh; - break; - } - case Lame.EXTREME_FAST: - { - preset = Lame.V0; - gfp.VBR = VbrMode.vbr_mtrh; - break; - } - case Lame.INSANE: - { - preset = 320; - gfp.preset = preset; - apply_abr_preset(gfp, preset, enforce); - gfp.VBR = VbrMode.vbr_off; - return preset; - } - } + if (l <= 0) { + /* + * rh: 20040215 may happen due to "prev_data_use" + * optimization + */ + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + } + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate = 0; + } - gfp.preset = preset; - { - switch (preset) { - case Lame.V9: - apply_vbr_preset(gfp, 9, enforce); - return preset; - case Lame.V8: - apply_vbr_preset(gfp, 8, enforce); - return preset; - case Lame.V7: - apply_vbr_preset(gfp, 7, enforce); - return preset; - case Lame.V6: - apply_vbr_preset(gfp, 6, enforce); - return preset; - case Lame.V5: - apply_vbr_preset(gfp, 5, enforce); - return preset; - case Lame.V4: - apply_vbr_preset(gfp, 4, enforce); - return preset; - case Lame.V3: - apply_vbr_preset(gfp, 3, enforce); - return preset; - case Lame.V2: - apply_vbr_preset(gfp, 2, enforce); - return preset; - case Lame.V1: - apply_vbr_preset(gfp, 1, enforce); - return preset; - case Lame.V0: - apply_vbr_preset(gfp, 0, enforce); - return preset; - default: break; - } - } - if (8 <= preset && preset <= 320) { - return apply_abr_preset(gfp, preset, enforce); - } - - /* no corresponding preset found */ - gfp.preset = 0; - return preset; - } - - // Rest from getset.c: - - /** - * VBR quality level.
- * 1. The following rule can be used to calculate the maximum - * number of bits used for one granule [^W frame]:- */ + /* have to allow for the case when bigvalues < region0 < region1 */ + /* (and region0, region1 are ignored) */ + a1 = Math.min(a1, i); + a2 = Math.min(a2, i); -function Reservoir() { - var bs; + /* Count the number of bits necessary to code the bigvalues region. */ + if (0 < a1) { + var bi = new Bits(bits); + gi.table_select[0] = choose_table(ix, 0, a1, bi); + bits = bi.bits; + } + if (a1 < a2) { + var bi = new Bits(bits); + gi.table_select[1] = choose_table(ix, a1, a2, bi); + bits = bi.bits; + } + if (gfc.use_best_huffman == 2) { + gi.part2_3_length = bits; + best_huffman_divide(gfc, gi); + bits = gi.part2_3_length; + } - this.setModules = function(_bs) { - bs = _bs; - } + if (prev_noise != null) { + if (gi.block_type == Encoder.NORM_TYPE) { + var sfb = 0; + while (gfc.scalefac_band.l[sfb] < gi.big_values) { + sfb++; + } + prev_noise.sfb_count1 = sfb; + } + } - this.ResvFrameBegin = function(gfp, mean_bits) { - var gfc = gfp.internal_flags; - var maxmp3buf; - var l3_side = gfc.l3_side; + return bits; + } - var frameLength = bs.getframebits(gfp); - mean_bits.bits = (frameLength - gfc.sideinfo_len * 8) / gfc.mode_gr; + this.count_bits = function (gfc, xr, gi, prev_noise) { + var ix = gi.l3_enc; - /** - *
- * At the highest possible bitrate of Layer III (320 kbps - * per stereo signal [^W^W^W], 48 kHz) the frames must be of - * [^W^W^W are designed to have] constant length, i.e. - * one buffer [^W^W the frame] length is:
- * - * 320 kbps * 1152/48 kHz = 7680 bit = 960 byte - * - * This value is used as the maximum buffer per channel [^W^W] at - * lower bitrates [than 320 kbps]. At 64 kbps mono or 128 kbps - * stereo the main granule length is 64 kbps * 576/48 kHz = 768 bit - * [per granule and channel] at 48 kHz sampling frequency. - * This means that there is a maximum deviation (short time buffer - * [= reservoir]) of 7680 - 2*2*768 = 4608 bits is allowed at 64 kbps. - * The actual deviation is equal to the number of bytes [with the - * meaning of octets] denoted by the main_data_end offset pointer. - * The actual maximum deviation is (2^9-1)*8 bit = 4088 bits - * [for MPEG-1 and (2^8-1)*8 bit for MPEG-2, both are hard limits]. - * ... The xchange of buffer bits between the left and right channel - * is allowed without restrictions [exception: dual channel]. - * Because of the [constructed] constraint on the buffer size - * main_data_end is always set to 0 in the case of bit_rate_index==14, - * i.e. data rate 320 kbps per stereo signal [^W^W^W]. In this case - * all data are allocated between adjacent header [^W sync] words - * [, i.e. there is no buffering at all]. - *
- * Meaning of the variables: - * resvLimit: (0, 8, ..., 8*255 (MPEG-2), 8*511 (MPEG-1)) - * Number of bits can be stored in previous frame(s) due to - * counter size constaints - * maxmp3buf: ( ??? ... 8*1951 (MPEG-1 and 2), 8*2047 (MPEG-2.5)) - * Number of bits allowed to encode one frame (you can take 8*511 bit - * from the bit reservoir and at most 8*1440 bit from the current - * frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible - * value for MPEG-1 and -2) - * - * maximum allowed granule/channel size times 4 = 8*2047 bits., - * so this is the absolute maximum supported by the format. - * - * - * fullFrameBits: maximum number of bits available for encoding - * the current frame. - * - * mean_bits: target number of bits per granule. - * - * frameLength: - * - * gfc.ResvMax: maximum allowed reservoir - * - * gfc.ResvSize: current reservoir size - * - * l3_side.resvDrain_pre: - * ancillary data to be added to previous frame: - * (only usefull in VBR modes if it is possible to have - * maxmp3buf < fullFrameBits)). Currently disabled, - * see #define NEW_DRAIN - * 2010-02-13: RH now enabled, it seems to be needed for CBR too, - * as there exists one example, where the FhG decoder - * can't decode a -b320 CBR file anymore. - * - * l3_side.resvDrain_post: - * ancillary data to be added to this frame: - * - *- */ + /* since quantize_xrpow uses table lookup, we need to check this first: */ + var w = (QuantizePVT.IXMAX_VAL) / qupvt.IPOW20(gi.global_gain); - /* main_data_begin has 9 bits in MPEG-1, 8 bits MPEG-2 */ - var resvLimit = (8 * 256) * gfc.mode_gr - 8; + if (gi.xrpow_max > w) + return QuantizePVT.LARGE_BITS; - /* - * maximum allowed frame size. dont use more than this number of bits, - * even if the frame has the space for them: - */ - if (gfp.brate > 320) { - /* in freeformat the buffer is constant */ - maxmp3buf = 8 * ((int) ((gfp.brate * 1000) - / (gfp.out_samplerate / 1152) / 8 + .5)); - } else { - /* - * all mp3 decoders should have enough buffer to handle this value: - * size of a 320kbps 32kHz frame - */ - maxmp3buf = 8 * 1440; + quantize_xrpow(xr, ix, qupvt.IPOW20(gi.global_gain), gi, prev_noise); - /* - * Bouvigne suggests this more lax interpretation of the ISO doc - * instead of using 8*960. - */ + if ((gfc.substep_shaping & 2) != 0) { + var j = 0; + /* 0.634521682242439 = 0.5946*2**(.5*0.1875) */ + var gain = gi.global_gain + gi.scalefac_scale; + var roundfac = 0.634521682242439 / qupvt.IPOW20(gain); + for (var sfb = 0; sfb < gi.sfbmax; sfb++) { + var width = gi.width[sfb]; + if (0 == gfc.pseudohalf[sfb]) { + j += width; + } else { + var k; + for (k = j, j += width; k < j; ++k) { + ix[k] = (xr[k] >= roundfac) ? ix[k] : 0; + } + } + } + } + return this.noquant_count_bits(gfc, gi, prev_noise); + } - if (gfp.strict_ISO) { - maxmp3buf = 8 * ((int) (320000 / (gfp.out_samplerate / 1152) / 8 + .5)); - } - } + /** + * re-calculate the best scalefac_compress using scfsi the saved bits are + * kept in the bit reservoir. + */ + function recalc_divide_init(gfc, cod_info, ix, r01_bits, r01_div, r0_tbl, r1_tbl) { + var bigv = cod_info.big_values; - gfc.ResvMax = maxmp3buf - frameLength; - if (gfc.ResvMax > resvLimit) - gfc.ResvMax = resvLimit; - if (gfc.ResvMax < 0 || gfp.disable_reservoir) - gfc.ResvMax = 0; + for (var r0 = 0; r0 <= 7 + 15; r0++) { + r01_bits[r0] = QuantizePVT.LARGE_BITS; + } - var fullFrameBits = mean_bits.bits * gfc.mode_gr - + Math.min(gfc.ResvSize, gfc.ResvMax); + for (var r0 = 0; r0 < 16; r0++) { + var a1 = gfc.scalefac_band.l[r0 + 1]; + if (a1 >= bigv) + break; + var r0bits = 0; + var bi = new Bits(r0bits); + var r0t = choose_table(ix, 0, a1, bi); + r0bits = bi.bits; - if (fullFrameBits > maxmp3buf) - fullFrameBits = maxmp3buf; + for (var r1 = 0; r1 < 8; r1++) { + var a2 = gfc.scalefac_band.l[r0 + r1 + 2]; + if (a2 >= bigv) + break; + var bits = r0bits; + bi = new Bits(bits); + var r1t = choose_table(ix, a1, a2, bi); + bits = bi.bits; + if (r01_bits[r0 + r1] > bits) { + r01_bits[r0 + r1] = bits; + r01_div[r0 + r1] = r0; + r0_tbl[r0 + r1] = r0t; + r1_tbl[r0 + r1] = r1t; + } + } + } + } + function recalc_divide_sub(gfc, cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl) { + var bigv = cod_info2.big_values; - l3_side.resvDrain_pre = 0; + for (var r2 = 2; r2 < Encoder.SBMAX_l + 1; r2++) { + var a2 = gfc.scalefac_band.l[r2]; + if (a2 >= bigv) + break; + var bits = r01_bits[r2 - 2] + cod_info2.count1bits; + if (gi.part2_3_length <= bits) + break; + + var bi = new Bits(bits); + var r2t = choose_table(ix, a2, bigv, bi); + bits = bi.bits; + if (gi.part2_3_length <= bits) + continue; - // frame analyzer code - if (gfc.pinfo != null) { - /* - * expected bits per channel per granule [is this also right for - * mono/stereo, MPEG-1/2 ?] - */ - gfc.pinfo.mean_bits = mean_bits.bits / 2; - gfc.pinfo.resvsize = gfc.ResvSize; - } + gi.assign(cod_info2); + gi.part2_3_length = bits; + gi.region0_count = r01_div[r2 - 2]; + gi.region1_count = r2 - 2 - r01_div[r2 - 2]; + gi.table_select[0] = r0_tbl[r2 - 2]; + gi.table_select[1] = r1_tbl[r2 - 2]; + gi.table_select[2] = r2t; + } + } - return fullFrameBits; - } + this.best_huffman_divide = function (gfc, gi) { + var cod_info2 = new GrInfo(); + var ix = gi.l3_enc; + var r01_bits = new_int(7 + 15 + 1); + var r01_div = new_int(7 + 15 + 1); + var r0_tbl = new_int(7 + 15 + 1); + var r1_tbl = new_int(7 + 15 + 1); - /** - * returns targ_bits: target number of bits to use for 1 granule
+ * Switch mappings for VBR mode VBR_RH + * vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix + **/ - var scale_long = [0, 10, 20, 30, 33, 21, 31, 41, 32, 42, - 52, 43, 53, 63, 64, 74]; + var vbr_old_switch_map = [ + new VBRPresets(0, 9, 9, 0, 5.20, 125.0, -4.2, -6.3, 4.8, 1, 0, 0, 2, 21, 0.97), + new VBRPresets(1, 9, 9, 0, 5.30, 125.0, -3.6, -5.6, 4.5, 1.5, 0, 0, 2, 21, 1.35), + new VBRPresets(2, 9, 9, 0, 5.60, 125.0, -2.2, -3.5, 2.8, 2, 0, 0, 2, 21, 1.49), + new VBRPresets(3, 9, 9, 1, 5.80, 130.0, -1.8, -2.8, 2.6, 3, -4, 0, 2, 20, 1.64), + new VBRPresets(4, 9, 9, 1, 6.00, 135.0, -0.7, -1.1, 1.1, 3.5, -8, 0, 2, 0, 1.79), + new VBRPresets(5, 9, 9, 1, 6.40, 140.0, 0.5, 0.4, -7.5, 4, -12, 0.0002, 0, 0, 1.95), + new VBRPresets(6, 9, 9, 1, 6.60, 145.0, 0.67, 0.65, -14.7, 6.5, -19, 0.0004, 0, 0, 2.30), + new VBRPresets(7, 9, 9, 1, 6.60, 145.0, 0.8, 0.75, -19.7, 8, -22, 0.0006, 0, 0, 2.70), + new VBRPresets(8, 9, 9, 1, 6.60, 145.0, 1.2, 1.15, -27.5, 10, -23, 0.0007, 0, 0, 0), + new VBRPresets(9, 9, 9, 1, 6.60, 145.0, 1.6, 1.6, -36, 11, -25, 0.0008, 0, 0, 0), + new VBRPresets(10, 9, 9, 1, 6.60, 145.0, 2.0, 2.0, -36, 12, -25, 0.0008, 0, 0, 0) + ]; /** - * Also calculates the number of bits necessary to code the scalefactors. + *
+ * vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix + **/ - this.scale_bitcount = function (cod_info) { - var k, sfb, max_slen1 = 0, max_slen2 = 0; + var vbr_psy_switch_map = [ + new VBRPresets(0, 9, 9, 0, 4.20, 25.0, -7.0, -4.0, 7.5, 1, 0, 0, 2, 26, 0.97), + new VBRPresets(1, 9, 9, 0, 4.20, 25.0, -5.6, -3.6, 4.5, 1.5, 0, 0, 2, 21, 1.35), + new VBRPresets(2, 9, 9, 0, 4.20, 25.0, -4.4, -1.8, 2, 2, 0, 0, 2, 18, 1.49), + new VBRPresets(3, 9, 9, 1, 4.20, 25.0, -3.4, -1.25, 1.1, 3, -4, 0, 2, 15, 1.64), + new VBRPresets(4, 9, 9, 1, 4.20, 25.0, -2.2, 0.1, 0, 3.5, -8, 0, 2, 0, 1.79), + new VBRPresets(5, 9, 9, 1, 4.20, 25.0, -1.0, 1.65, -7.7, 4, -12, 0.0002, 0, 0, 1.95), + new VBRPresets(6, 9, 9, 1, 4.20, 25.0, -0.0, 2.47, -7.7, 6.5, -19, 0.0004, 0, 0, 2), + new VBRPresets(7, 9, 9, 1, 4.20, 25.0, 0.5, 2.0, -14.5, 8, -22, 0.0006, 0, 0, 2), + new VBRPresets(8, 9, 9, 1, 4.20, 25.0, 1.0, 2.4, -22.0, 10, -23, 0.0007, 0, 0, 2), + new VBRPresets(9, 9, 9, 1, 4.20, 25.0, 1.5, 2.95, -30.0, 11, -25, 0.0008, 0, 0, 2), + new VBRPresets(10, 9, 9, 1, 4.20, 25.0, 2.0, 2.95, -36.0, 12, -30, 0.0008, 0, 0, 2) + ]; - /* maximum values */ - var tab; - var scalefac = cod_info.scalefac; + function apply_vbr_preset(gfp, a, enforce) { + var vbr_preset = gfp.VBR == VbrMode.vbr_rh ? vbr_old_switch_map + : vbr_psy_switch_map; + var x = gfp.VBR_q_frac; + var p = vbr_preset[a]; + var q = vbr_preset[a + 1]; + var set = p; - if (cod_info.block_type == Encoder.SHORT_TYPE) { - tab = scale_short; - if (cod_info.mixed_block_flag != 0) - tab = scale_mixed; - } else { /* block_type == 1,2,or 3 */ - tab = scale_long; - if (0 == cod_info.preflag) { - for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) - if (scalefac[sfb] < qupvt.pretab[sfb]) - break; + // NOOP(vbr_q); + // NOOP(quant_comp); + // NOOP(quant_comp_s); + // NOOP(expY); + p.st_lrm = p.st_lrm + x * (q.st_lrm - p.st_lrm); + // LERP(st_lrm); + p.st_s = p.st_s + x * (q.st_s - p.st_s); + // LERP(st_s); + p.masking_adj = p.masking_adj + x * (q.masking_adj - p.masking_adj); + // LERP(masking_adj); + p.masking_adj_short = p.masking_adj_short + x + * (q.masking_adj_short - p.masking_adj_short); + // LERP(masking_adj_short); + p.ath_lower = p.ath_lower + x * (q.ath_lower - p.ath_lower); + // LERP(ath_lower); + p.ath_curve = p.ath_curve + x * (q.ath_curve - p.ath_curve); + // LERP(ath_curve); + p.ath_sensitivity = p.ath_sensitivity + x + * (q.ath_sensitivity - p.ath_sensitivity); + // LERP(ath_sensitivity); + p.interch = p.interch + x * (q.interch - p.interch); + // LERP(interch); + // NOOP(safejoint); + // NOOP(sfb21mod); + p.msfix = p.msfix + x * (q.msfix - p.msfix); + // LERP(msfix); - if (sfb == Encoder.SBPSY_l) { - cod_info.preflag = 1; - for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) - scalefac[sfb] -= qupvt.pretab[sfb]; - } - } - } + lame_set_VBR_q(gfp, set.vbr_q); - for (sfb = 0; sfb < cod_info.sfbdivide; sfb++) - if (max_slen1 < scalefac[sfb]) - max_slen1 = scalefac[sfb]; + if (enforce != 0) + gfp.quant_comp = set.quant_comp; + else if (!(Math.abs(gfp.quant_comp - -1) > 0)) + gfp.quant_comp = set.quant_comp; + // SET_OPTION(quant_comp, set.quant_comp, -1); + if (enforce != 0) + gfp.quant_comp_short = set.quant_comp_s; + else if (!(Math.abs(gfp.quant_comp_short - -1) > 0)) + gfp.quant_comp_short = set.quant_comp_s; + // SET_OPTION(quant_comp_short, set.quant_comp_s, -1); + if (set.expY != 0) { + gfp.experimentalY = set.expY != 0; + } + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre = set.st_lrm; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre = set.st_lrm; + // SET_OPTION(short_threshold_lrm, set.st_lrm, -1); + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre_s = set.st_s; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre_s - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre_s = set.st_s; + // SET_OPTION(short_threshold_s, set.st_s, -1); + if (enforce != 0) + gfp.maskingadjust = set.masking_adj; + else if (!(Math.abs(gfp.maskingadjust - 0) > 0)) + gfp.maskingadjust = set.masking_adj; + // SET_OPTION(maskingadjust, set.masking_adj, 0); + if (enforce != 0) + gfp.maskingadjust_short = set.masking_adj_short; + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = set.masking_adj_short; + // SET_OPTION(maskingadjust_short, set.masking_adj_short, 0); + if (enforce != 0) + gfp.ATHlower = -set.ath_lower / 10.0; + else if (!(Math.abs((-gfp.ATHlower * 10.0) - 0) > 0)) + gfp.ATHlower = -set.ath_lower / 10.0; + // SET_OPTION(ATHlower, set.ath_lower, 0); + if (enforce != 0) + gfp.ATHcurve = set.ath_curve; + else if (!(Math.abs(gfp.ATHcurve - -1) > 0)) + gfp.ATHcurve = set.ath_curve; + // SET_OPTION(ATHcurve, set.ath_curve, -1); + if (enforce != 0) + gfp.athaa_sensitivity = set.ath_sensitivity; + else if (!(Math.abs(gfp.athaa_sensitivity - -1) > 0)) + gfp.athaa_sensitivity = set.ath_sensitivity; + // SET_OPTION(athaa_sensitivity, set.ath_sensitivity, 0); + if (set.interch > 0) { + if (enforce != 0) + gfp.interChRatio = set.interch; + else if (!(Math.abs(gfp.interChRatio - -1) > 0)) + gfp.interChRatio = set.interch; + // SET_OPTION(interChRatio, set.interch, -1); + } - for (; sfb < cod_info.sfbmax; sfb++) - if (max_slen2 < scalefac[sfb]) - max_slen2 = scalefac[sfb]; + /* parameters for which there is no proper set/get interface */ + if (set.safejoint > 0) { + gfp.exp_nspsytune = gfp.exp_nspsytune | set.safejoint; + } + if (set.sfb21mod > 0) { + gfp.exp_nspsytune = gfp.exp_nspsytune | (set.sfb21mod << 20); + } + if (enforce != 0) + gfp.msfix = set.msfix; + else if (!(Math.abs(gfp.msfix - -1) > 0)) + gfp.msfix = set.msfix; + // SET_OPTION(msfix, set.msfix, -1); - /* - * from Takehiro TOMINAGA
+ * Switch mappings for ABR mode * - * This is reverse-engineered from section 2.4.3.2 of the MPEG2 IS, - * "Audio Decoding Layer III" + * kbps quant q_s safejoint nsmsfix st_lrm st_s ns-bass scale msk ath_lwr ath_curve interch , sfscale + **/ - this.scale_bitcount_lsf = function (gfc, cod_info) { - var table_number, row_in_table, partition, nr_sfb, window; - var over; - var i, sfb; - var max_sfac = new_int(4); -//var partition_table; - var scalefac = cod_info.scalefac; + var abr_switch_map = [ + new ABRPresets(8, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -30.0, 11, 0.0012, 1), /* 8, impossible to use in stereo */ + new ABRPresets(16, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -25.0, 11, 0.0010, 1), /* 16 */ + new ABRPresets(24, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -20.0, 11, 0.0010, 1), /* 24 */ + new ABRPresets(32, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -15.0, 11, 0.0010, 1), /* 32 */ + new ABRPresets(40, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 40 */ + new ABRPresets(48, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 48 */ + new ABRPresets(56, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -6.0, 11, 0.0008, 1), /* 56 */ + new ABRPresets(64, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -2.0, 11, 0.0008, 1), /* 64 */ + new ABRPresets(80, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, .0, 8, 0.0007, 1), /* 80 */ + new ABRPresets(96, 9, 9, 0, 2.50, 6.60, 145, 0, 0.95, 0, 1.0, 5.5, 0.0006, 1), /* 96 */ + new ABRPresets(112, 9, 9, 0, 2.25, 6.60, 145, 0, 0.95, 0, 2.0, 4.5, 0.0005, 1), /* 112 */ + new ABRPresets(128, 9, 9, 0, 1.95, 6.40, 140, 0, 0.95, 0, 3.0, 4, 0.0002, 1), /* 128 */ + new ABRPresets(160, 9, 9, 1, 1.79, 6.00, 135, 0, 0.95, -2, 5.0, 3.5, 0, 1), /* 160 */ + new ABRPresets(192, 9, 9, 1, 1.49, 5.60, 125, 0, 0.97, -4, 7.0, 3, 0, 0), /* 192 */ + new ABRPresets(224, 9, 9, 1, 1.25, 5.20, 125, 0, 0.98, -6, 9.0, 2, 0, 0), /* 224 */ + new ABRPresets(256, 9, 9, 1, 0.97, 5.20, 125, 0, 1.00, -8, 10.0, 1, 0, 0), /* 256 */ + new ABRPresets(320, 9, 9, 1, 0.90, 5.20, 125, 0, 1.00, -10, 12.0, 0, 0, 0) /* 320 */ + ]; - /* - * Set partition table. Note that should try to use table one, but do - * not yet... - */ - if (cod_info.preflag != 0) - table_number = 2; - else - table_number = 0; + function apply_abr_preset(gfp, preset, enforce) { + /* Variables for the ABR stuff */ + var actual_bitrate = preset; + + var r = lame.nearestBitrateFullIndex(preset); + + gfp.VBR = VbrMode.vbr_abr; + gfp.VBR_mean_bitrate_kbps = actual_bitrate; + gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, 320); + gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, 8); + gfp.brate = gfp.VBR_mean_bitrate_kbps; + if (gfp.VBR_mean_bitrate_kbps > 320) { + gfp.disable_reservoir = true; + } - for (i = 0; i < 4; i++) - max_sfac[i] = 0; + /* parameters for which there is no proper set/get interface */ + if (abr_switch_map[r].safejoint > 0) + gfp.exp_nspsytune = gfp.exp_nspsytune | 2; + /* safejoint */ - if (cod_info.block_type == Encoder.SHORT_TYPE) { - row_in_table = 1; - var partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; - for (sfb = 0, partition = 0; partition < 4; partition++) { - nr_sfb = partition_table[partition] / 3; - for (i = 0; i < nr_sfb; i++, sfb++) - for (window = 0; window < 3; window++) - if (scalefac[sfb * 3 + window] > max_sfac[partition]) - max_sfac[partition] = scalefac[sfb * 3 + window]; - } - } else { - row_in_table = 0; - var partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; - for (sfb = 0, partition = 0; partition < 4; partition++) { - nr_sfb = partition_table[partition]; - for (i = 0; i < nr_sfb; i++, sfb++) - if (scalefac[sfb] > max_sfac[partition]) - max_sfac[partition] = scalefac[sfb]; - } + if (abr_switch_map[r].sfscale > 0) { + gfp.internal_flags.noise_shaping = 2; } - - for (over = false, partition = 0; partition < 4; partition++) { - if (max_sfac[partition] > max_range_sfac_tab[table_number][partition]) - over = true; + /* ns-bass tweaks */ + if (Math.abs(abr_switch_map[r].nsbass) > 0) { + var k = (int)(abr_switch_map[r].nsbass * 4); + if (k < 0) + k += 64; + gfp.exp_nspsytune = gfp.exp_nspsytune | (k << 2); } - if (!over) { - var slen1, slen2, slen3, slen4; - - cod_info.sfb_partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; - for (partition = 0; partition < 4; partition++) - cod_info.slen[partition] = log2tab[max_sfac[partition]]; - /* set scalefac_compress */ - slen1 = cod_info.slen[0]; - slen2 = cod_info.slen[1]; - slen3 = cod_info.slen[2]; - slen4 = cod_info.slen[3]; + if (enforce != 0) + gfp.quant_comp = abr_switch_map[r].quant_comp; + else if (!(Math.abs(gfp.quant_comp - -1) > 0)) + gfp.quant_comp = abr_switch_map[r].quant_comp; + // SET_OPTION(quant_comp, abr_switch_map[r].quant_comp, -1); + if (enforce != 0) + gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; + else if (!(Math.abs(gfp.quant_comp_short - -1) > 0)) + gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; + // SET_OPTION(quant_comp_short, abr_switch_map[r].quant_comp_s, -1); - switch (table_number) { - case 0: - cod_info.scalefac_compress = (((slen1 * 5) + slen2) << 4) - + (slen3 << 2) + slen4; - break; + if (enforce != 0) + gfp.msfix = abr_switch_map[r].nsmsfix; + else if (!(Math.abs(gfp.msfix - -1) > 0)) + gfp.msfix = abr_switch_map[r].nsmsfix; + // SET_OPTION(msfix, abr_switch_map[r].nsmsfix, -1); - case 1: - cod_info.scalefac_compress = 400 + (((slen1 * 5) + slen2) << 2) - + slen3; - break; + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; + // SET_OPTION(short_threshold_lrm, abr_switch_map[r].st_lrm, -1); + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre_s - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; + // SET_OPTION(short_threshold_s, abr_switch_map[r].st_s, -1); - case 2: - cod_info.scalefac_compress = 500 + (slen1 * 3) + slen2; - break; + /* + * ABR seems to have big problems with clipping, especially at low + * bitrates + */ + /* + * so we compensate for that here by using a scale value depending on + * bitrate + */ + if (enforce != 0) + gfp.scale = abr_switch_map[r].scale; + else if (!(Math.abs(gfp.scale - -1) > 0)) + gfp.scale = abr_switch_map[r].scale; + // SET_OPTION(scale, abr_switch_map[r].scale, -1); - default: - System.err.printf("intensity stereo not implemented yet\n"); - break; - } - } - if (!over) { - cod_info.part2_length = 0; - for (partition = 0; partition < 4; partition++) - cod_info.part2_length += cod_info.slen[partition] - * cod_info.sfb_partition_table[partition]; + if (enforce != 0) + gfp.maskingadjust = abr_switch_map[r].masking_adj; + else if (!(Math.abs(gfp.maskingadjust - 0) > 0)) + gfp.maskingadjust = abr_switch_map[r].masking_adj; + // SET_OPTION(maskingadjust, abr_switch_map[r].masking_adj, 0); + if (abr_switch_map[r].masking_adj > 0) { + if (enforce != 0) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); + // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * + // .9, 0); + } else { + if (enforce != 0) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); + // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * + // 1.1, 0); } - return over; - } - /* - * Since no bands have been over-amplified, we can set scalefac_compress and - * slen[] for the formatter - */ - var log2tab = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, - 4, 4, 4, 4]; + if (enforce != 0) + gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; + else if (!(Math.abs((-gfp.ATHlower * 10.) - 0) > 0)) + gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; + // SET_OPTION(ATHlower, abr_switch_map[r].ath_lower, 0); + if (enforce != 0) + gfp.ATHcurve = abr_switch_map[r].ath_curve; + else if (!(Math.abs(gfp.ATHcurve - -1) > 0)) + gfp.ATHcurve = abr_switch_map[r].ath_curve; + // SET_OPTION(ATHcurve, abr_switch_map[r].ath_curve, -1); - this.huffman_init = function (gfc) { - for (var i = 2; i <= 576; i += 2) { - var scfb_anz = 0, bv_index; - while (gfc.scalefac_band.l[++scfb_anz] < i) - ; + if (enforce != 0) + gfp.interChRatio = abr_switch_map[r].interch; + else if (!(Math.abs(gfp.interChRatio - -1) > 0)) + gfp.interChRatio = abr_switch_map[r].interch; + // SET_OPTION(interChRatio, abr_switch_map[r].interch, -1); - bv_index = subdv_table[scfb_anz][0]; // .region0_count - while (gfc.scalefac_band.l[bv_index + 1] > i) - bv_index--; + return preset; + } - if (bv_index < 0) { - /* - * this is an indication that everything is going to be encoded - * as region0: bigvalues < region0 < region1 so lets set - * region0, region1 to some value larger than bigvalues - */ - bv_index = subdv_table[scfb_anz][0]; // .region0_count + this.apply_preset = function(gfp, preset, enforce) { + /* translate legacy presets */ + switch (preset) { + case Lame.R3MIX: + { + preset = Lame.V3; + gfp.VBR = VbrMode.vbr_mtrh; + break; } + case Lame.MEDIUM: + { + preset = Lame.V4; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.MEDIUM_FAST: + { + preset = Lame.V4; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.STANDARD: + { + preset = Lame.V2; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.STANDARD_FAST: + { + preset = Lame.V2; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.EXTREME: + { + preset = Lame.V0; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.EXTREME_FAST: + { + preset = Lame.V0; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.INSANE: + { + preset = 320; + gfp.preset = preset; + apply_abr_preset(gfp, preset, enforce); + gfp.VBR = VbrMode.vbr_off; + return preset; + } + } - gfc.bv_scf[i - 2] = bv_index; - - bv_index = subdv_table[scfb_anz][1]; // .region1_count - while (gfc.scalefac_band.l[bv_index + gfc.bv_scf[i - 2] + 2] > i) - bv_index--; - - if (bv_index < 0) { - bv_index = subdv_table[scfb_anz][1]; // .region1_count + gfp.preset = preset; + { + switch (preset) { + case Lame.V9: + apply_vbr_preset(gfp, 9, enforce); + return preset; + case Lame.V8: + apply_vbr_preset(gfp, 8, enforce); + return preset; + case Lame.V7: + apply_vbr_preset(gfp, 7, enforce); + return preset; + case Lame.V6: + apply_vbr_preset(gfp, 6, enforce); + return preset; + case Lame.V5: + apply_vbr_preset(gfp, 5, enforce); + return preset; + case Lame.V4: + apply_vbr_preset(gfp, 4, enforce); + return preset; + case Lame.V3: + apply_vbr_preset(gfp, 3, enforce); + return preset; + case Lame.V2: + apply_vbr_preset(gfp, 2, enforce); + return preset; + case Lame.V1: + apply_vbr_preset(gfp, 1, enforce); + return preset; + case Lame.V0: + apply_vbr_preset(gfp, 0, enforce); + return preset; + default: + break; } - - gfc.bv_scf[i - 1] = bv_index; } - } -} + if (8 <= preset && preset <= 320) { + return apply_abr_preset(gfp, preset, enforce); + } + /* no corresponding preset found */ + gfp.preset = 0; + return preset; + } + // Rest from getset.c: -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)); -}; + /** + * VBR quality level.
+ * 1. The following rule can be used to calculate the maximum + * number of bits used for one granule [^W frame]:+ */ - /** - * 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; +function Reservoir() { + var bs; - /* 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; - }; + this.setModules = function(_bs) { + bs = _bs; + } - 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); - } + this.ResvFrameBegin = function(gfp, mean_bits) { + var gfc = gfp.internal_flags; + var maxmp3buf; + var l3_side = gfc.l3_side; - /** - * write j bits into the bit stream - */ - function putbits2(gfc, val, j) { + var frameLength = bs.getframebits(gfp); + mean_bits.bits = (frameLength - gfc.sideinfo_len * 8) / gfc.mode_gr; - while (j > 0) { - var k; - if (bufBitIdx == 0) { - bufBitIdx = 8; - bufByteIdx++; - if (gfc.header[gfc.w_ptr].write_timing == totbit) { - putheader_bits(gfc); - } - buf[bufByteIdx] = 0; - } + /** + *
+ * At the highest possible bitrate of Layer III (320 kbps + * per stereo signal [^W^W^W], 48 kHz) the frames must be of + * [^W^W^W are designed to have] constant length, i.e. + * one buffer [^W^W the frame] length is:
+ * + * 320 kbps * 1152/48 kHz = 7680 bit = 960 byte + * + * This value is used as the maximum buffer per channel [^W^W] at + * lower bitrates [than 320 kbps]. At 64 kbps mono or 128 kbps + * stereo the main granule length is 64 kbps * 576/48 kHz = 768 bit + * [per granule and channel] at 48 kHz sampling frequency. + * This means that there is a maximum deviation (short time buffer + * [= reservoir]) of 7680 - 2*2*768 = 4608 bits is allowed at 64 kbps. + * The actual deviation is equal to the number of bytes [with the + * meaning of octets] denoted by the main_data_end offset pointer. + * The actual maximum deviation is (2^9-1)*8 bit = 4088 bits + * [for MPEG-1 and (2^8-1)*8 bit for MPEG-2, both are hard limits]. + * ... The xchange of buffer bits between the left and right channel + * is allowed without restrictions [exception: dual channel]. + * Because of the [constructed] constraint on the buffer size + * main_data_end is always set to 0 in the case of bit_rate_index==14, + * i.e. data rate 320 kbps per stereo signal [^W^W^W]. In this case + * all data are allocated between adjacent header [^W sync] words + * [, i.e. there is no buffering at all]. + *
+ * Meaning of the variables: + * resvLimit: (0, 8, ..., 8*255 (MPEG-2), 8*511 (MPEG-1)) + * Number of bits can be stored in previous frame(s) due to + * counter size constaints + * maxmp3buf: ( ??? ... 8*1951 (MPEG-1 and 2), 8*2047 (MPEG-2.5)) + * Number of bits allowed to encode one frame (you can take 8*511 bit + * from the bit reservoir and at most 8*1440 bit from the current + * frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible + * value for MPEG-1 and -2) + * + * maximum allowed granule/channel size times 4 = 8*2047 bits., + * so this is the absolute maximum supported by the format. + * + * + * fullFrameBits: maximum number of bits available for encoding + * the current frame. + * + * mean_bits: target number of bits per granule. + * + * frameLength: + * + * gfc.ResvMax: maximum allowed reservoir + * + * gfc.ResvSize: current reservoir size + * + * l3_side.resvDrain_pre: + * ancillary data to be added to previous frame: + * (only usefull in VBR modes if it is possible to have + * maxmp3buf < fullFrameBits)). Currently disabled, + * see #define NEW_DRAIN + * 2010-02-13: RH now enabled, it seems to be needed for CBR too, + * as there exists one example, where the FhG decoder + * can't decode a -b320 CBR file anymore. + * + * l3_side.resvDrain_post: + * ancillary data to be added to this frame: + * + *+ */ - k = Math.min(j, bufBitIdx); - j -= k; + /* main_data_begin has 9 bits in MPEG-1, 8 bits MPEG-2 */ + var resvLimit = (8 * 256) * gfc.mode_gr - 8; - bufBitIdx -= k; + /* + * maximum allowed frame size. dont use more than this number of bits, + * even if the frame has the space for them: + */ + if (gfp.brate > 320) { + /* in freeformat the buffer is constant */ + maxmp3buf = 8 * ((int) ((gfp.brate * 1000) + / (gfp.out_samplerate / 1152) / 8 + .5)); + } else { + /* + * all mp3 decoders should have enough buffer to handle this value: + * size of a 320kbps 32kHz frame + */ + maxmp3buf = 8 * 1440; - /* 32 too large on 32 bit machines */ + /* + * Bouvigne suggests this more lax interpretation of the ISO doc + * instead of using 8*960. + */ - buf[bufByteIdx] |= ((val >> j) << bufBitIdx); - totbit += k; - } - } + if (gfp.strict_ISO) { + maxmp3buf = 8 * ((int) (320000 / (gfp.out_samplerate / 1152) / 8 + .5)); + } + } - /** - * write j bits into the bit stream, ignoring frame headers - */ - function putbits_noheaders(gfc, val, j) { + gfc.ResvMax = maxmp3buf - frameLength; + if (gfc.ResvMax > resvLimit) + gfc.ResvMax = resvLimit; + if (gfc.ResvMax < 0 || gfp.disable_reservoir) + gfc.ResvMax = 0; - while (j > 0) { - var k; - if (bufBitIdx == 0) { - bufBitIdx = 8; - bufByteIdx++; - buf[bufByteIdx] = 0; - } + var fullFrameBits = mean_bits.bits * gfc.mode_gr + + Math.min(gfc.ResvSize, gfc.ResvMax); - k = Math.min(j, bufBitIdx); - j -= k; + if (fullFrameBits > maxmp3buf) + fullFrameBits = maxmp3buf; - bufBitIdx -= k; - /* 32 too large on 32 bit machines */ + l3_side.resvDrain_pre = 0; - buf[bufByteIdx] |= ((val >> j) << bufBitIdx); - totbit += k; - } - } + // frame analyzer code + if (gfc.pinfo != null) { + /* + * expected bits per channel per granule [is this also right for + * mono/stereo, MPEG-1/2 ?] + */ + gfc.pinfo.mean_bits = mean_bits.bits / 2; + gfc.pinfo.resvsize = gfc.ResvSize; + } - /** - * 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; + return fullFrameBits; + } - 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; - } + /** + * returns targ_bits: target number of bits to use for 1 granule
+ * 4 bytes for Header Tag + * 4 bytes for Header Flags + * 100 bytes for entry (toc) + * 4 bytes for frame size + * 4 bytes for stream size + * 4 bytes for VBR scale. a VBR quality indicator: 0=best 100=worst + * 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)" + * ___________ + * 140 bytes + *+ */ + var VBRHEADERSIZE = (NUMTOCENTRIES + 4 + 4 + 4 + 4 + 4); - 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 */ - writeheader(gfc, (l3_side.main_data_begin), 8); - writeheader(gfc, l3_side.private_bits, gfc.channels_out); + var LAMEHEADERSIZE = (VBRHEADERSIZE + 9 + 1 + 1 + 8 + + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2); - 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); + /** + * The size of the Xing header MPEG-1, bit rate in kbps. + */ + var XING_BITRATE1 = 128; + /** + * The size of the Xing header MPEG-2, bit rate in kbps. + */ + var XING_BITRATE2 = 64; + /** + * The size of the Xing header MPEG-2.5, bit rate in kbps. + */ + var XING_BITRATE25 = 32; - 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); + /** + * ISO-8859-1 charset for byte to string operations. + */ + var ISO_8859_1 = null; //Charset.forName("ISO-8859-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); + /** + * VBR header magic string. + */ + var VBRTag0 = "Xing"; + /** + * VBR header magic string (VBR == VBRMode.vbr_off). + */ + var VBRTag1 = "Info"; - 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); + /** + * Lookup table for fast CRC-16 computation. Uses the polynomial + * x^16+x^15+x^2+1 + */ + var crc16Lookup = [0x0000, 0xC0C1, 0xC181, 0x0140, + 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, + 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, + 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, + 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, + 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, + 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, + 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, + 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, + 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, + 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, + 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, + 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, + 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, + 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, + 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, + 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, + 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, + 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, + 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, + 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, + 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, + 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, + 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, + 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, + 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, + 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, + 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, + 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, + 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, + 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, + 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, + 0x4100, 0x81C1, 0x8081, 0x4040]; - writeheader(gfc, gi.region0_count, 4); - writeheader(gfc, gi.region1_count, 3); - } + /*********************************************************************** + * Robert Hegemann 2001-01-17 + ***********************************************************************/ - writeheader(gfc, gi.scalefac_scale, 1); - writeheader(gfc, gi.count1table_select, 1); + function addVbr(v, bitrate) { + v.nVbrNumFrames++; + v.sum += bitrate; + v.seen++; + + if (v.seen < v.want) { + return; + } + + if (v.pos < v.size) { + v.bag[v.pos] = v.sum; + v.pos++; + v.seen = 0; + } + if (v.pos == v.size) { + for (var i = 1; i < v.size; i += 2) { + v.bag[i / 2] = v.bag[i]; } + v.want *= 2; + v.pos /= 2; + } + } + + function xingSeekTable(v, t) { + if (v.pos <= 0) + return; + + for (var i = 1; i < NUMTOCENTRIES; ++i) { + var j = i / NUMTOCENTRIES, act, sum; + var indx = 0 | (Math.floor(j * v.pos)); + if (indx > v.pos - 1) + indx = v.pos - 1; + act = v.bag[indx]; + sum = v.sum; + var seek_point = 0 | (256. * act / sum); + if (seek_point > 255) + seek_point = 255; + t[i] = 0xff & seek_point; } + } + + /** + * Add VBR entry, used to fill the VBR TOC entries. + * + * @param gfp + * global flags + */ + this.addVbrFrame = function (gfp) { + var gfc = gfp.internal_flags; + var kbps = Tables.bitrate_table[gfp.version][gfc.bitrate_index]; + addVbr(gfc.VBR_seek_table, kbps); + } - if (gfp.error_protection) { - /* (jo) error_protection: add crc16 information to header */ - CRC_writeheader(gfc, gfc.header[gfc.h_ptr].buf); - } + /** + * Read big endian integer (4-bytes) from header. + * + * @param buf + * header containing the integer + * @param bufPos + * offset into the header + * @return extracted integer + */ + function extractInteger(buf, bufPos) { + var x = buf[bufPos + 0] & 0xff; + x <<= 8; + x |= buf[bufPos + 1] & 0xff; + x <<= 8; + x |= buf[bufPos + 2] & 0xff; + x <<= 8; + x |= buf[bufPos + 3] & 0xff; + return x; + } - { - var old = gfc.h_ptr; + /** + * Write big endian integer (4-bytes) in the header. + * + * @param buf + * header to write the integer into + * @param bufPos + * offset into the header + * @param value + * integer value to write + */ + function createInteger(buf, bufPos, value) { + buf[bufPos + 0] = 0xff & ((value >> 24) & 0xff); + buf[bufPos + 1] = 0xff & ((value >> 16) & 0xff); + buf[bufPos + 2] = 0xff & ((value >> 8) & 0xff); + buf[bufPos + 3] = 0xff & (value & 0xff); + } - gfc.h_ptr = (old + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1); - gfc.header[gfc.h_ptr].write_timing = gfc.header[old].write_timing - + bitsPerFrame; + /** + * Write big endian short (2-bytes) in the header. + * + * @param buf + * header to write the integer into + * @param bufPos + * offset into the header + * @param value + * integer value to write + */ + function createShort(buf, bufPos, value) { + buf[bufPos + 0] = 0xff & ((value >> 8) & 0xff); + buf[bufPos + 1] = 0xff & (value & 0xff); + } - 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"); - } + /** + * Check for magic strings (Xing/Info). + * + * @param buf + * header to check + * @param bufPos + * header offset to check + * @return magic string found + */ + function isVbrTag(buf, bufPos) { + return new String(buf, bufPos, VBRTag0.length(), ISO_8859_1) + .equals(VBRTag0) + || new String(buf, bufPos, VBRTag1.length(), ISO_8859_1) + .equals(VBRTag1); + } - } + function shiftInBitsValue(x, n, v) { + return 0xff & ((x << n) | (v & ~(-1 << n))); } - function huffman_coder_count1(gfc, gi) { - /* Write count1 area */ - var h = Tables.ht[gi.count1table_select + 32]; - var i, bits = 0; + /** + * Construct the MP3 header using the settings of the global flags. + * + *
+ * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz). + * (at 48kHz they use 56kbs since 48kbs frame not big enough for + * table of contents) + * let's always embed Xing header inside a 64kbs layer III frame. + * this gives us enough room for a LAME version string too. + * size determined by sampling frequency (MPEG1) + * 32kHz: 216 bytes@48kbs 288bytes@ 64kbs + * 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1) + * 48kHz: 144 bytes 192 + * + * MPEG 2 values are the same since the framesize and samplerate + * are each reduced by a factor of 2. + *+ */ + var kbps_header; + if (1 == gfp.version) { + kbps_header = XING_BITRATE1; + } else { + if (gfp.out_samplerate < 16000) + kbps_header = XING_BITRATE25; + else + kbps_header = XING_BITRATE2; + } - if (region2Start > bigvalues) - region2Start = bigvalues; + if (gfp.VBR == VbrMode.vbr_off) + kbps_header = gfp.brate; - 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; - } + // make sure LAME Header fits into Frame + var totalFrameSize = ((gfp.version + 1) * 72000 * kbps_header) + / gfp.out_samplerate; + var headerSize = (gfc.sideinfo_len + LAMEHEADERSIZE); + gfc.VBR_seek_table.TotalFrameSize = totalFrameSize; + if (totalFrameSize < headerSize || totalFrameSize > MAXFRAMESIZE) { + /* disable tag, it wont fit */ + gfp.bWriteVbrTag = false; + return; + } - function writeMainData(gfp) { - var gr, ch, sfb, data_bits, tot_bits = 0; - var gfc = gfp.internal_flags; - var l3_side = gfc.l3_side; + gfc.VBR_seek_table.nVbrNumFrames = 0; + gfc.VBR_seek_table.nBytesWritten = 0; + gfc.VBR_seek_table.sum = 0; - 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; - } + gfc.VBR_seek_table.seen = 0; + gfc.VBR_seek_table.want = 1; + gfc.VBR_seek_table.pos = 0; - 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? */ - 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; - data_bits = 0; - sfb = 0; - sfb_partition = 0; + if (gfc.VBR_seek_table.bag == null) { + gfc.VBR_seek_table.bag = new int[400]; + gfc.VBR_seek_table.size = 400; + } - 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? */ - tot_bits += scale_bits + data_bits; - } - /* for ch */ + // write dummy VBR tag of all 0's into bitstream + var buffer = new_byte(MAXFRAMESIZE); + + setLameTagFrameHeader(gfp, buffer); + var n = gfc.VBR_seek_table.TotalFrameSize; + for (var i = 0; i < n; ++i) { + bs.add_dummy_byte(gfp, buffer[i] & 0xff, 1); } - /* for gf */ - return tot_bits; } - /* main_data */ + /** + * Fast CRC-16 computation (uses table crc16Lookup). + * + * @param value + * @param crc + * @return + */ + function crcUpdateLookup(value, crc) { + var tmp = crc ^ value; + crc = (crc >> 8) ^ crc16Lookup[tmp & 0xff]; + return crc; + } - function TotalBytes() { - this.total = 0; + this.updateMusicCRC = function (crc, buffer, bufferPos, size) { + for (var i = 0; i < size; ++i) + crc[0] = crcUpdateLookup(buffer[bufferPos + i], crc[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. + /** + * Write LAME info: mini version + info on various switches used (Jonathan + * Dee 2001/08/31). * - * total_bytes_output is the size of the mp3 output buffer if - * lame_encode_flush_nogap() was called right now. + * @param gfp + * global flags + * @param musicLength + * music length + * @param streamBuffer + * pointer to output buffer + * @param streamBufferPos + * offset into the output buffer + * @param crc + * computation of CRC-16 of Lame Tag so far (starting at frame + * sync) + * @return number of bytes written to the stream */ - function compute_flushbits(gfp, total_bytes_output) { + function putLameVBR(gfp, musicLength, streamBuffer, streamBufferPos, crc) { 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; + var bytesWritten = 0; - /* 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; + /* encoder delay */ + var encDelay = gfp.encoder_delay; + /* encoder padding */ + var encPadding = gfp.encoder_padding; - 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; + /* recall: gfp.VBR_q is for example set by the switch -V */ + /* gfp.quality by -q, -h, -f, etc */ + var quality = (100 - 10 * gfp.VBR_q - gfp.quality); + + var version = v.getLameVeryShortVersion(); + var vbr; + var revision = 0x00; + var revMethod; + // numbering different in vbr_mode vs. Lame tag + var vbrTypeTranslator = [1, 5, 3, 2, 4, 0, 3]; + var lowpass = 0 | (((gfp.lowpassfreq / 100.0) + .5) > 255 ? 255 + : (gfp.lowpassfreq / 100.0) + .5); + var peakSignalAmplitude = 0; + var radioReplayGain = 0; + var audiophileReplayGain = 0; + var noiseShaping = gfp.internal_flags.noise_shaping; + var stereoMode = 0; + var nonOptimal = 0; + var sourceFreq = 0; + var misc = 0; + var musicCRC = 0; + + // psy model type: Gpsycho or NsPsytune + var expNPsyTune = (gfp.exp_nspsytune & 1) != 0; + var safeJoint = (gfp.exp_nspsytune & 2) != 0; + var noGapMore = false; + var noGapPrevious = false; + var noGapCount = gfp.internal_flags.nogap_total; + var noGapCurr = gfp.internal_flags.nogap_current; + + // 4 bits + var athType = gfp.ATHtype; + var flags = 0; + + // vbr modes + var abrBitrate; + switch (gfp.VBR) { + case vbr_abr: + abrBitrate = gfp.VBR_mean_bitrate_kbps; + break; + case vbr_off: + abrBitrate = gfp.brate; + break; + default: + abrBitrate = gfp.VBR_min_bitrate_kbps; } - /* - * 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); + // revision and vbr method + if (gfp.VBR.ordinal() < vbrTypeTranslator.length) + vbr = vbrTypeTranslator[gfp.VBR.ordinal()]; else - total_bytes_output.total = (total_bytes_output.total / 8); - total_bytes_output.total += bufByteIdx + 1; + vbr = 0x00; // unknown - if (flushbits < 0) { - System.err.println("strange error flushing buffer ... \n"); - } - return flushbits; - } + revMethod = 0x10 * revision + vbr; - 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; + // ReplayGain + if (gfc.findReplayGain) { + if (gfc.RadioGain > 0x1FE) + gfc.RadioGain = 0x1FE; + if (gfc.RadioGain < -0x1FE) + gfc.RadioGain = -0x1FE; - if ((flushbits = compute_flushbits(gfp, new TotalBytes())) < 0) - return; - drain_into_ancillary(gfp, flushbits); + // set name code + radioReplayGain = 0x2000; + // set originator code to `determined automatically' + radioReplayGain |= 0xC00; - /* check that the 100% of the last frame has been written to bitstream */ + if (gfc.RadioGain >= 0) { + // set gain adjustment + radioReplayGain |= gfc.RadioGain; + } else { + // set the sign bit + radioReplayGain |= 0x200; + // set gain adjustment + radioReplayGain |= -gfc.RadioGain; + } + } - /* - * 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; + // peak sample + if (gfc.findPeakSample) + peakSignalAmplitude = Math + .abs(0 | ((( gfc.PeakSample) / 32767.0) * Math.pow(2, 23) + .5)); - /* save the ReplayGain value */ - if (gfc.findReplayGain) { - var RadioGain = ga.GetTitleGain(gfc.rgdata); - gfc.RadioGain = Math.floor(RadioGain * 10.0 + 0.5) | 0; - /* round to nearest */ + // nogap + if (noGapCount != -1) { + if (noGapCurr > 0) + noGapPrevious = true; + + if (noGapCurr < noGapCount - 1) + noGapMore = true; } - /* 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 */ + // flags + flags = athType + ((expNPsyTune ? 1 : 0) << 4) + + ((safeJoint ? 1 : 0) << 5) + ((noGapMore ? 1 : 0) << 6) + + ((noGapPrevious ? 1 : 0) << 7); - 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; + if (quality < 0) + quality = 0; + + // stereo mode field (Intensity stereo is not implemented) + switch (gfp.mode) { + case MONO: + stereoMode = 0; + break; + case STEREO: + stereoMode = 1; + break; + case DUAL_CHANNEL: + stereoMode = 2; + break; + case JOINT_STEREO: + if (gfp.force_ms) + stereoMode = 4; + else + stereoMode = 3; + break; + case NOT_SET: + //$FALL-THROUGH$ + default: + stereoMode = 7; + break; + } + + if (gfp.in_samplerate <= 32000) + sourceFreq = 0x00; + else if (gfp.in_samplerate == 48000) + sourceFreq = 0x02; + else if (gfp.in_samplerate > 48000) + sourceFreq = 0x03; + else { + // default is 44100Hz + sourceFreq = 0x01; } - }; - this.add_dummy_byte = function (gfp, val, n) { - var gfc = gfp.internal_flags; - var i; + // Check if the user overrided the default LAME behavior with some + // nasty options + if (gfp.short_blocks == ShortBlock.short_block_forced + || gfp.short_blocks == ShortBlock.short_block_dispensed + || ((gfp.lowpassfreq == -1) && (gfp.highpassfreq == -1)) || /* "-k" */ + (gfp.scale_left < gfp.scale_right) + || (gfp.scale_left > gfp.scale_right) + || (gfp.disable_reservoir && gfp.brate < 320) || gfp.noATH + || gfp.ATHonly || (athType == 0) || gfp.in_samplerate <= 32000) + nonOptimal = 1; - while (n-- > 0) { - putbits_noheaders(gfc, val, 8); + misc = noiseShaping + (stereoMode << 2) + (nonOptimal << 5) + + (sourceFreq << 6); - for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i) - gfc.header[i].write_timing += 8; - } - }; + musicCRC = gfc.nMusicCRC; - /** - * 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; + // Write all this information into the stream - var bitsPerFrame = this.getframebits(gfp); - drain_into_ancillary(gfp, l3_side.resvDrain_pre); + createInteger(streamBuffer, streamBufferPos + bytesWritten, quality); + bytesWritten += 4; - 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; + for (var j = 0; j < 9; j++) { + streamBuffer[streamBufferPos + bytesWritten + j] = 0xff & version .charAt(j); + } + bytesWritten += 9; - l3_side.main_data_begin += (bitsPerFrame - bits) / 8; + streamBuffer[streamBufferPos + bytesWritten] = 0xff & revMethod; + bytesWritten++; - /* - * 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"); - } + streamBuffer[streamBufferPos + bytesWritten] = 0xff & lowpass; + bytesWritten++; - /* - * 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); + createInteger(streamBuffer, streamBufferPos + bytesWritten, + peakSignalAmplitude); + bytesWritten += 4; - 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"); + createShort(streamBuffer, streamBufferPos + bytesWritten, + radioReplayGain); + bytesWritten += 2; - gfc.ResvSize = l3_side.main_data_begin * 8; - } - //; + createShort(streamBuffer, streamBufferPos + bytesWritten, + audiophileReplayGain); + bytesWritten += 2; - 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; - } + streamBuffer[streamBufferPos + bytesWritten] = 0xff & flags; + bytesWritten++; - return 0; - }; + if (abrBitrate >= 255) + streamBuffer[streamBufferPos + bytesWritten] = 0xFF; + else + streamBuffer[streamBufferPos + bytesWritten] = 0xff & abrBitrate; + bytesWritten++; - /** - *
- * 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. - *- */ - 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; + streamBuffer[streamBufferPos + bytesWritten] = 0xff & (encDelay >> 4); + streamBuffer[streamBufferPos + bytesWritten + 1] = 0xff & ((encDelay << 4) + (encPadding >> 8)); + streamBuffer[streamBufferPos + bytesWritten + 2] = 0xff & encPadding; - if (mp3data != 0) { - var crc = new_int(1); - crc[0] = gfc.nMusicCRC; - vbr.updateMusicCRC(crc, buffer, bufferPos, minimum); - gfc.nMusicCRC = crc[0]; + bytesWritten += 3; - /** - * 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; - } + streamBuffer[streamBufferPos + bytesWritten] = 0xff & misc; + bytesWritten++; - 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; + // unused in rev0 + streamBuffer[streamBufferPos + bytesWritten++] = 0; - /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ - while (samples_out != 0) { + createShort(streamBuffer, streamBufferPos + bytesWritten, gfp.preset); + bytesWritten += 2; - 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 - */ + createInteger(streamBuffer, streamBufferPos + bytesWritten, musicLength); + bytesWritten += 4; - /* - * 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; + createShort(streamBuffer, streamBufferPos + bytesWritten, musicCRC); + bytesWritten += 2; - 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 */ + // Calculate tag CRC.... must be done here, since it includes previous + // information - /* - * this should not be possible, and indicates we have - * overflown the pcm_buf buffer - */ + for (var i = 0; i < bytesWritten; i++) + crc = crcUpdateLookup(streamBuffer[streamBufferPos + i], crc); - 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]; - } - } + createShort(streamBuffer, streamBufferPos + bytesWritten, crc); + bytesWritten += 2; - 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; + return bytesWritten; + } - } - /* if (samples_out>0) */ - } - /* while (samples_out!=0) */ - } - /* if (gfc.decode_on_the_fly) */ + function skipId3v2(fpStream) { + // seek to the beginning of the stream + fpStream.seek(0); + // read 10 bytes in case there's an ID3 version 2 header here + var id3v2Header = new_byte(10); + fpStream.readFully(id3v2Header); + /* does the stream begin with the ID3 version 2 file identifier? */ + var id3v2TagSize; + if (!new String(id3v2Header, "ISO-8859-1").startsWith("ID3")) { + /* + * the tag size (minus the 10-byte header) is encoded into four + * bytes where the most significant bit is clear in each byte + */ + id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21) + | ((id3v2Header[7] & 0x7f) << 14) + | ((id3v2Header[8] & 0x7f) << 7) | (id3v2Header[9] & 0x7f)) + + id3v2Header.length; + } else { + /* no ID3 version 2 tag in this stream */ + id3v2TagSize = 0; + } + return id3v2TagSize; + } + + this.getLameTagFrame = function (gfp, buffer) { + var gfc = gfp.internal_flags; + if (!gfp.bWriteVbrTag) { + return 0; + } + if (gfc.Class_ID != Lame.LAME_ID) { + return 0; + } + if (gfc.VBR_seek_table.pos <= 0) { + return 0; + } + if (buffer.length < gfc.VBR_seek_table.TotalFrameSize) { + return gfc.VBR_seek_table.TotalFrameSize; } - /* if (mp3data) */ - return minimum; - }; - this.init_bit_stream_w = function (gfc) { - buf = new_byte(Lame.LAME_MAXMP3BUFFER); + Arrays.fill(buffer, 0, gfc.VBR_seek_table.TotalFrameSize, 0); - gfc.h_ptr = gfc.w_ptr = 0; - gfc.header[gfc.h_ptr].write_timing = 0; - bufByteIdx = -1; - bufBitIdx = 0; - totbit = 0; - }; + // 4 bytes frame header + setLameTagFrameHeader(gfp, buffer); - // From machine.h + // Create TOC entries + var toc = new_byte(NUMTOCENTRIES); + if (gfp.free_format) { + for (var i = 1; i < NUMTOCENTRIES; ++i) + toc[i] = 0xff & (255 * i / 100); + } else { + xingSeekTable(gfc.VBR_seek_table, toc); + } -} + // Start writing the tag after the zero frame + var streamIndex = gfc.sideinfo_len; + /** + * Note: Xing header specifies that Xing data goes in the ancillary data + * with NO ERROR PROTECTION. If error protecton in enabled, the Xing + * data still starts at the same offset, and now it is in sideinfo data + * block, and thus will not decode correctly by non-Xing tag aware + * players + */ + if (gfp.error_protection) + streamIndex -= 2; + // Put Vbr tag + if (gfp.VBR == VbrMode.vbr_off) { + buffer[streamIndex++] = 0xff & VBRTag1.charAt(0); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(1); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(2); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(3); -/** - * A Vbr header may be present in the ancillary data field of the first frame of - * an mp3 bitstream
- * 4 bytes for Header Tag - * 4 bytes for Header Flags - * 100 bytes for entry (toc) - * 4 bytes for frame size - * 4 bytes for stream size - * 4 bytes for VBR scale. a VBR quality indicator: 0=best 100=worst - * 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)" - * ___________ - * 140 bytes - *+ * Write final VBR tag to the file. + * + * @param gfp + * global flags + * @param stream + * stream to add the VBR tag to + * @return 0 (OK), -1 else + * @throws IOException + * I/O error */ - var VBRHEADERSIZE = (NUMTOCENTRIES + 4 + 4 + 4 + 4 + 4); + this.putVbrTag = function (gfp, stream) { + var gfc = gfp.internal_flags; - var LAMEHEADERSIZE = (VBRHEADERSIZE + 9 + 1 + 1 + 8 - + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2); + if (gfc.VBR_seek_table.pos <= 0) + return -1; - /** - * The size of the Xing header MPEG-1, bit rate in kbps. - */ - var XING_BITRATE1 = 128; - /** - * The size of the Xing header MPEG-2, bit rate in kbps. - */ - var XING_BITRATE2 = 64; - /** - * The size of the Xing header MPEG-2.5, bit rate in kbps. - */ - var XING_BITRATE25 = 32; + // Seek to end of file + stream.seek(stream.length()); - /** - * ISO-8859-1 charset for byte to string operations. - */ - var ISO_8859_1 = null; //Charset.forName("ISO-8859-1"); + // Get file size, abort if file has zero length. + if (stream.length() == 0) + return -1; - /** - * VBR header magic string. - */ - var VBRTag0 = "Xing"; - /** - * VBR header magic string (VBR == VBRMode.vbr_off). - */ - var VBRTag1 = "Info"; + // The VBR tag may NOT be located at the beginning of the stream. If an + // ID3 version 2 tag was added, then it must be skipped to write the VBR + // tag data. + var id3v2TagSize = skipId3v2(stream); - /** - * Lookup table for fast CRC-16 computation. Uses the polynomial - * x^16+x^15+x^2+1 - */ - var crc16Lookup = [0x0000, 0xC0C1, 0xC181, 0x0140, - 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, - 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, - 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, - 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, - 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, - 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, - 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, - 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, - 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, - 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, - 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, - 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, - 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, - 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, - 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, - 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, - 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, - 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, - 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, - 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, - 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, - 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, - 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, - 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, - 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, - 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, - 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, - 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, - 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, - 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, - 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, - 0x4100, 0x81C1, 0x8081, 0x4040]; + // Seek to the beginning of the stream + stream.seek(id3v2TagSize); - /*********************************************************************** - * Robert Hegemann 2001-01-17 - ***********************************************************************/ + var buffer = new_byte(MAXFRAMESIZE); + var bytes = getLameTagFrame(gfp, buffer); + if (bytes > buffer.length) { + return -1; + } + + if (bytes < 1) { + return 0; + } + + // Put it all to disk again + stream.write(buffer, 0, bytes); + // success + return 0; + } + +} + + + +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 addVbr(v, bitrate) { - v.nVbrNumFrames++; - v.sum += bitrate; - v.seen++; +function BitStream() { + var self = this; + var CRC16_POLYNOMIAL = 0x8005; - if (v.seen < v.want) { - return; - } + /* + * 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; - if (v.pos < v.size) { - v.bag[v.pos] = v.sum; - v.pos++; - v.seen = 0; - } - if (v.pos == v.size) { - for (var i = 1; i < v.size; i += 2) { - v.bag[i / 2] = v.bag[i]; - } - v.want *= 2; - v.pos /= 2; - } - } + //GainAnalysis ga; + //MPGLib mpg; + //Version ver; + //VBRTag vbr; + var ga = null; + var mpg = null; + var ver = null; + var vbr = null; - function xingSeekTable(v, t) { - if (v.pos <= 0) - return; + //public final void setModules(GainAnalysis ga, MPGLib mpg, Version ver, + // VBRTag vbr) { - for (var i = 1; i < NUMTOCENTRIES; ++i) { - var j = i / NUMTOCENTRIES, act, sum; - var indx = 0 | (Math.floor(j * v.pos)); - if (indx > v.pos - 1) - indx = v.pos - 1; - act = v.bag[indx]; - sum = v.sum; - var seek_point = 0 | (256. * act / sum); - if (seek_point > 255) - seek_point = 255; - t[i] = 0xff & seek_point; - } - } + this.setModules = function (_ga, _mpg, _ver, _vbr) { + ga = _ga; + mpg = _mpg; + ver = _ver; + vbr = _vbr; + }; /** - * Add VBR entry, used to fill the VBR TOC entries. - * - * @param gfp - * global flags + * Bit stream buffer. */ - this.addVbrFrame = function (gfp) { - var gfc = gfp.internal_flags; - var kbps = Tables.bitrate_table[gfp.version][gfc.bitrate_index]; - addVbr(gfc.VBR_seek_table, kbps); - } + //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; /** - * Read big endian integer (4-bytes) from header. - * - * @param buf - * header containing the integer - * @param bufPos - * offset into the header - * @return extracted integer + * compute bitsperframe and mean_bits for a layer III frame */ - function extractInteger(buf, bufPos) { - var x = buf[bufPos + 0] & 0xff; - x <<= 8; - x |= buf[bufPos + 1] & 0xff; - x <<= 8; - x |= buf[bufPos + 2] & 0xff; - x <<= 8; - x |= buf[bufPos + 3] & 0xff; - return x; + 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; + + /* 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 big endian integer (4-bytes) in the header. - * - * @param buf - * header to write the integer into - * @param bufPos - * offset into the header - * @param value - * integer value to write + * write j bits into the bit stream */ - function createInteger(buf, bufPos, value) { - buf[bufPos + 0] = 0xff & ((value >> 24) & 0xff); - buf[bufPos + 1] = 0xff & ((value >> 16) & 0xff); - buf[bufPos + 2] = 0xff & ((value >> 8) & 0xff); - buf[bufPos + 3] = 0xff & (value & 0xff); + function putbits2(gfc, val, j) { + + while (j > 0) { + var k; + if (bufBitIdx == 0) { + bufBitIdx = 8; + bufByteIdx++; + if (gfc.header[gfc.w_ptr].write_timing == totbit) { + putheader_bits(gfc); + } + buf[bufByteIdx] = 0; + } + + k = Math.min(j, bufBitIdx); + j -= k; + + bufBitIdx -= k; + + /* 32 too large on 32 bit machines */ + + buf[bufByteIdx] |= ((val >> j) << bufBitIdx); + totbit += k; + } } /** - * Write big endian short (2-bytes) in the header. - * - * @param buf - * header to write the integer into - * @param bufPos - * offset into the header - * @param value - * integer value to write + * write j bits into the bit stream, ignoring frame headers */ - function createShort(buf, bufPos, value) { - buf[bufPos + 0] = 0xff & ((value >> 8) & 0xff); - buf[bufPos + 1] = 0xff & (value & 0xff); + function putbits_noheaders(gfc, val, j) { + + while (j > 0) { + var k; + if (bufBitIdx == 0) { + bufBitIdx = 8; + bufByteIdx++; + buf[bufByteIdx] = 0; + } + + k = Math.min(j, bufBitIdx); + j -= k; + + bufBitIdx -= k; + + /* 32 too large on 32 bit machines */ + + buf[bufByteIdx] |= ((val >> j) << bufBitIdx); + totbit += k; + } } /** - * Check for magic strings (Xing/Info). - * - * @param buf - * header to check - * @param bufPos - * header offset to check - * @return magic string found + * 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 isVbrTag(buf, bufPos) { - return new String(buf, bufPos, VBRTag0.length(), ISO_8859_1) - .equals(VBRTag0) - || new String(buf, bufPos, VBRTag1.length(), ISO_8859_1) - .equals(VBRTag1); - } + function drain_into_ancillary(gfp, remainingBits) { + var gfc = gfp.internal_flags; + var i; + + 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); + } + - function shiftInBitsValue(x, n, v) { - return 0xff & ((x << n) | (v & ~(-1 << n))); } /** - * Construct the MP3 header using the settings of the global flags. - * - *
- * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz). - * (at 48kHz they use 56kbs since 48kbs frame not big enough for - * table of contents) - * let's always embed Xing header inside a 64kbs layer III frame. - * this gives us enough room for a LAME version string too. - * size determined by sampling frequency (MPEG1) - * 32kHz: 216 bytes@48kbs 288bytes@ 64kbs - * 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1) - * 48kHz: 144 bytes 192 - * - * MPEG 2 values are the same since the framesize and samplerate - * are each reduced by a factor of 2. - *- */ - var kbps_header; - if (1 == gfp.version) { - kbps_header = XING_BITRATE1; - } else { - if (gfp.out_samplerate < 16000) - kbps_header = XING_BITRATE25; - else - kbps_header = XING_BITRATE2; - } + function huffman_coder_count1(gfc, gi) { + /* Write count1 area */ + var h = Tables.ht[gi.count1table_select + 32]; + var i, bits = 0; - if (gfp.VBR == VbrMode.vbr_off) - kbps_header = gfp.brate; + var ix = gi.big_values; + var xr = gi.big_values; - // make sure LAME Header fits into Frame - var totalFrameSize = ((gfp.version + 1) * 72000 * kbps_header) - / gfp.out_samplerate; - var headerSize = (gfc.sideinfo_len + LAMEHEADERSIZE); - gfc.VBR_seek_table.TotalFrameSize = totalFrameSize; - if (totalFrameSize < headerSize || totalFrameSize > MAXFRAMESIZE) { - /* disable tag, it wont fit */ - gfp.bWriteVbrTag = false; - return; - } + for (i = (gi.count1 - gi.big_values) / 4; i > 0; --i) { + var huffbits = 0; + var p = 0, v; - gfc.VBR_seek_table.nVbrNumFrames = 0; - gfc.VBR_seek_table.nBytesWritten = 0; - gfc.VBR_seek_table.sum = 0; + v = gi.l3_enc[ix + 0]; + if (v != 0) { + p += 8; + if (gi.xr[xr + 0] < 0) + huffbits++; + } - gfc.VBR_seek_table.seen = 0; - gfc.VBR_seek_table.want = 1; - gfc.VBR_seek_table.pos = 0; + v = gi.l3_enc[ix + 1]; + if (v != 0) { + p += 4; + huffbits *= 2; + if (gi.xr[xr + 1] < 0) + huffbits++; + } - if (gfc.VBR_seek_table.bag == null) { - gfc.VBR_seek_table.bag = new int[400]; - gfc.VBR_seek_table.size = 400; - } + v = gi.l3_enc[ix + 2]; + if (v != 0) { + p += 2; + huffbits *= 2; + if (gi.xr[xr + 2] < 0) + huffbits++; + } - // write dummy VBR tag of all 0's into bitstream - var buffer = new_byte(MAXFRAMESIZE); + v = gi.l3_enc[ix + 3]; + if (v != 0) { + p++; + huffbits *= 2; + if (gi.xr[xr + 3] < 0) + huffbits++; + } - setLameTagFrameHeader(gfp, buffer); - var n = gfc.VBR_seek_table.TotalFrameSize; - for (var i = 0; i < n; ++i) { - bs.add_dummy_byte(gfp, buffer[i] & 0xff, 1); + ix += 4; + xr += 4; + putbits2(gfc, huffbits + h.table[p], h.hlen[p]); + bits += h.hlen[p]; } + return bits; } /** - * Fast CRC-16 computation (uses table crc16Lookup). - * - * @param value - * @param crc - * @return - */ - function crcUpdateLookup(value, crc) { - var tmp = crc ^ value; - crc = (crc >> 8) ^ crc16Lookup[tmp & 0xff]; - return crc; - } - - this.updateMusicCRC = function (crc, buffer, bufferPos, size) { - for (var i = 0; i < size; ++i) - crc[0] = crcUpdateLookup(buffer[bufferPos + i], crc[0]); - } - - /** - * Write LAME info: mini version + info on various switches used (Jonathan - * Dee 2001/08/31). - * - * @param gfp - * global flags - * @param musicLength - * music length - * @param streamBuffer - * pointer to output buffer - * @param streamBufferPos - * offset into the output buffer - * @param crc - * computation of CRC-16 of Lame Tag so far (starting at frame - * sync) - * @return number of bytes written to the stream + * Implements the pseudocode of page 98 of the IS */ - function putLameVBR(gfp, musicLength, streamBuffer, streamBufferPos, crc) { - var gfc = gfp.internal_flags; - var bytesWritten = 0; - - /* encoder delay */ - var encDelay = gfp.encoder_delay; - /* encoder padding */ - var encPadding = gfp.encoder_padding; - - /* recall: gfp.VBR_q is for example set by the switch -V */ - /* gfp.quality by -q, -h, -f, etc */ - var quality = (100 - 10 * gfp.VBR_q - gfp.quality); - - var version = v.getLameVeryShortVersion(); - var vbr; - var revision = 0x00; - var revMethod; - // numbering different in vbr_mode vs. Lame tag - var vbrTypeTranslator = [1, 5, 3, 2, 4, 0, 3]; - var lowpass = 0 | (((gfp.lowpassfreq / 100.0) + .5) > 255 ? 255 - : (gfp.lowpassfreq / 100.0) + .5); - var peakSignalAmplitude = 0; - var radioReplayGain = 0; - var audiophileReplayGain = 0; - var noiseShaping = gfp.internal_flags.noise_shaping; - var stereoMode = 0; - var nonOptimal = 0; - var sourceFreq = 0; - var misc = 0; - var musicCRC = 0; - - // psy model type: Gpsycho or NsPsytune - var expNPsyTune = (gfp.exp_nspsytune & 1) != 0; - var safeJoint = (gfp.exp_nspsytune & 2) != 0; - var noGapMore = false; - var noGapPrevious = false; - var noGapCount = gfp.internal_flags.nogap_total; - var noGapCurr = gfp.internal_flags.nogap_current; - - // 4 bits - var athType = gfp.ATHtype; - var flags = 0; - - // vbr modes - var abrBitrate; - switch (gfp.VBR) { - case vbr_abr: - abrBitrate = gfp.VBR_mean_bitrate_kbps; - break; - case vbr_off: - abrBitrate = gfp.brate; - break; - default: - abrBitrate = gfp.VBR_min_bitrate_kbps; - } + function Huffmancode(gfc, tableindex, start, end, gi) { + var h = Tables.ht[tableindex]; + var bits = 0; - // revision and vbr method - if (gfp.VBR.ordinal() < vbrTypeTranslator.length) - vbr = vbrTypeTranslator[gfp.VBR.ordinal()]; - else - vbr = 0x00; // unknown + if (0 == tableindex) + return bits; - revMethod = 0x10 * revision + vbr; + 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]; - // ReplayGain - if (gfc.findReplayGain) { - if (gfc.RadioGain > 0x1FE) - gfc.RadioGain = 0x1FE; - if (gfc.RadioGain < -0x1FE) - gfc.RadioGain = -0x1FE; + if (x1 != 0) { + if (gi.xr[i] < 0) + ext++; + cbits--; + } - // set name code - radioReplayGain = 0x2000; - // set originator code to `determined automatically' - radioReplayGain |= 0xC00; + if (tableindex > 15) { + /* use ESC-words */ + if (x1 > 14) { + var linbits_x1 = x1 - 15; + ext |= linbits_x1 << 1; + xbits = linbits; + x1 = 15; + } - if (gfc.RadioGain >= 0) { - // set gain adjustment - radioReplayGain |= gfc.RadioGain; - } else { - // set the sign bit - radioReplayGain |= 0x200; - // set gain adjustment - radioReplayGain |= -gfc.RadioGain; + if (x2 > 14) { + var linbits_x2 = x2 - 15; + ext <<= linbits; + ext |= linbits_x2; + xbits += linbits; + x2 = 15; + } + xlen = 16; } - } - // peak sample - if (gfc.findPeakSample) - peakSignalAmplitude = Math - .abs(0 | ((( gfc.PeakSample) / 32767.0) * Math.pow(2, 23) + .5)); + if (x2 != 0) { + ext <<= 1; + if (gi.xr[i + 1] < 0) + ext++; + cbits--; + } - // nogap - if (noGapCount != -1) { - if (noGapCurr > 0) - noGapPrevious = true; - if (noGapCurr < noGapCount - 1) - noGapMore = true; + x1 = x1 * xlen + x2; + xbits -= cbits; + cbits += h.hlen[x1]; + + + putbits2(gfc, h.table[x1], cbits); + putbits2(gfc, ext, xbits); + bits += cbits + xbits; } + return bits; + } - // flags - flags = athType + ((expNPsyTune ? 1 : 0) << 4) - + ((safeJoint ? 1 : 0) << 5) + ((noGapMore ? 1 : 0) << 6) - + ((noGapPrevious ? 1 : 0) << 7); + /** + * 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; - if (quality < 0) - quality = 0; + /* 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; + } - // stereo mode field (Intensity stereo is not implemented) - switch (gfp.mode) { - case MONO: - stereoMode = 0; - break; - case STEREO: - stereoMode = 1; - break; - case DUAL_CHANNEL: - stereoMode = 2; - break; - case JOINT_STEREO: - if (gfp.force_ms) - stereoMode = 4; - else - stereoMode = 3; - break; - case NOT_SET: - //$FALL-THROUGH$ - default: - stereoMode = 7; - break; - } + function LongHuffmancodebits(gfc, gi) { + var bigvalues, bits; + var region1Start, region2Start; - if (gfp.in_samplerate <= 32000) - sourceFreq = 0x00; - else if (gfp.in_samplerate == 48000) - sourceFreq = 0x02; - else if (gfp.in_samplerate > 48000) - sourceFreq = 0x03; - else { - // default is 44100Hz - sourceFreq = 0x01; - } + bigvalues = gi.big_values; - // Check if the user overrided the default LAME behavior with some - // nasty options - if (gfp.short_blocks == ShortBlock.short_block_forced - || gfp.short_blocks == ShortBlock.short_block_dispensed - || ((gfp.lowpassfreq == -1) && (gfp.highpassfreq == -1)) || /* "-k" */ - (gfp.scale_left < gfp.scale_right) - || (gfp.scale_left > gfp.scale_right) - || (gfp.disable_reservoir && gfp.brate < 320) || gfp.noATH - || gfp.ATHonly || (athType == 0) || gfp.in_samplerate <= 32000) - nonOptimal = 1; + var i = gi.region0_count + 1; + region1Start = gfc.scalefac_band.l[i]; + i += gi.region1_count + 1; + region2Start = gfc.scalefac_band.l[i]; - misc = noiseShaping + (stereoMode << 2) + (nonOptimal << 5) - + (sourceFreq << 6); + if (region1Start > bigvalues) + region1Start = bigvalues; - musicCRC = gfc.nMusicCRC; + if (region2Start > bigvalues) + region2Start = bigvalues; - // Write all this information into the stream + 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; + } - createInteger(streamBuffer, streamBufferPos + bytesWritten, quality); - bytesWritten += 4; + function writeMainData(gfp) { + var gr, ch, sfb, data_bits, tot_bits = 0; + var gfc = gfp.internal_flags; + var l3_side = gfc.l3_side; - for (var j = 0; j < 9; j++) { - streamBuffer[streamBufferPos + bytesWritten + j] = 0xff & version .charAt(j); - } - bytesWritten += 9; + 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; + } - streamBuffer[streamBufferPos + bytesWritten] = 0xff & revMethod; - bytesWritten++; + 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? */ + 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; + 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? */ + tot_bits += scale_bits + data_bits; + } + /* for ch */ + } + /* for gf */ + return tot_bits; + } - streamBuffer[streamBufferPos + bytesWritten] = 0xff & lowpass; - bytesWritten++; + /* main_data */ - createInteger(streamBuffer, streamBufferPos + bytesWritten, - peakSignalAmplitude); - bytesWritten += 4; + function TotalBytes() { + this.total = 0; + } - createShort(streamBuffer, streamBufferPos + bytesWritten, - radioReplayGain); - bytesWritten += 2; + /* + * 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; - createShort(streamBuffer, streamBufferPos + bytesWritten, - audiophileReplayGain); - bytesWritten += 2; + /* 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; - streamBuffer[streamBufferPos + bytesWritten] = 0xff & flags; - bytesWritten++; + 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; + } - if (abrBitrate >= 255) - streamBuffer[streamBufferPos + bytesWritten] = 0xFF; + /* + * 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 - streamBuffer[streamBufferPos + bytesWritten] = 0xff & abrBitrate; - bytesWritten++; - - streamBuffer[streamBufferPos + bytesWritten] = 0xff & (encDelay >> 4); - streamBuffer[streamBufferPos + bytesWritten + 1] = 0xff & ((encDelay << 4) + (encPadding >> 8)); - streamBuffer[streamBufferPos + bytesWritten + 2] = 0xff & encPadding; + total_bytes_output.total = (total_bytes_output.total / 8); + total_bytes_output.total += bufByteIdx + 1; - bytesWritten += 3; + if (flushbits < 0) { + System.err.println("strange error flushing buffer ... \n"); + } + return flushbits; + } - streamBuffer[streamBufferPos + bytesWritten] = 0xff & misc; - bytesWritten++; + 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; - // unused in rev0 - streamBuffer[streamBufferPos + bytesWritten++] = 0; + if ((flushbits = compute_flushbits(gfp, new TotalBytes())) < 0) + return; + drain_into_ancillary(gfp, flushbits); - createShort(streamBuffer, streamBufferPos + bytesWritten, gfp.preset); - bytesWritten += 2; + /* check that the 100% of the last frame has been written to bitstream */ - createInteger(streamBuffer, streamBufferPos + bytesWritten, musicLength); - bytesWritten += 4; + /* + * 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; - createShort(streamBuffer, streamBufferPos + bytesWritten, musicCRC); - bytesWritten += 2; + /* save the ReplayGain value */ + if (gfc.findReplayGain) { + var RadioGain = ga.GetTitleGain(gfc.rgdata); + gfc.RadioGain = Math.floor(RadioGain * 10.0 + 0.5) | 0; + /* round to nearest */ + } - // Calculate tag CRC.... must be done here, since it includes previous - // information + /* 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 */ - for (var i = 0; i < bytesWritten; i++) - crc = crcUpdateLookup(streamBuffer[streamBufferPos + i], crc); + 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; + } + }; - createShort(streamBuffer, streamBufferPos + bytesWritten, crc); - bytesWritten += 2; + this.add_dummy_byte = function (gfp, val, n) { + var gfc = gfp.internal_flags; + var i; - return bytesWritten; - } + while (n-- > 0) { + putbits_noheaders(gfc, val, 8); - function skipId3v2(fpStream) { - // seek to the beginning of the stream - fpStream.seek(0); - // read 10 bytes in case there's an ID3 version 2 header here - var id3v2Header = new_byte(10); - fpStream.readFully(id3v2Header); - /* does the stream begin with the ID3 version 2 file identifier? */ - var id3v2TagSize; - if (!new String(id3v2Header, "ISO-8859-1").startsWith("ID3")) { - /* - * the tag size (minus the 10-byte header) is encoded into four - * bytes where the most significant bit is clear in each byte - */ - id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21) - | ((id3v2Header[7] & 0x7f) << 14) - | ((id3v2Header[8] & 0x7f) << 7) | (id3v2Header[9] & 0x7f)) - + id3v2Header.length; - } else { - /* no ID3 version 2 tag in this stream */ - id3v2TagSize = 0; + for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i) + gfc.header[i].write_timing += 8; } - return id3v2TagSize; - } + }; - this.getLameTagFrame = function (gfp, buffer) { + /** + * 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; - if (!gfp.bWriteVbrTag) { - return 0; - } - if (gfc.Class_ID != Lame.LAME_ID) { - return 0; - } - if (gfc.VBR_seek_table.pos <= 0) { - return 0; - } - if (buffer.length < gfc.VBR_seek_table.TotalFrameSize) { - return gfc.VBR_seek_table.TotalFrameSize; - } + var bitsPerFrame = this.getframebits(gfp); + drain_into_ancillary(gfp, l3_side.resvDrain_pre); - Arrays.fill(buffer, 0, gfc.VBR_seek_table.TotalFrameSize, 0); + 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; - // 4 bytes frame header - setLameTagFrameHeader(gfp, buffer); + l3_side.main_data_begin += (bitsPerFrame - bits) / 8; - // Create TOC entries - var toc = new_byte(NUMTOCENTRIES); + /* + * 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"); + } - if (gfp.free_format) { - for (var i = 1; i < NUMTOCENTRIES; ++i) - toc[i] = 0xff & (255 * i / 100); - } else { - xingSeekTable(gfc.VBR_seek_table, toc); + /* + * 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; } + //; - // Start writing the tag after the zero frame - var streamIndex = gfc.sideinfo_len; - /** - * Note: Xing header specifies that Xing data goes in the ancillary data - * with NO ERROR PROTECTION. If error protecton in enabled, the Xing - * data still starts at the same offset, and now it is in sideinfo data - * block, and thus will not decode correctly by non-Xing tag aware - * players - */ - if (gfp.error_protection) - streamIndex -= 2; + 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; + } - // Put Vbr tag - if (gfp.VBR == VbrMode.vbr_off) { - buffer[streamIndex++] = 0xff & VBRTag1.charAt(0); - buffer[streamIndex++] = 0xff & VBRTag1.charAt(1); - buffer[streamIndex++] = 0xff & VBRTag1.charAt(2); - buffer[streamIndex++] = 0xff & VBRTag1.charAt(3); + return 0; + }; - } else { - buffer[streamIndex++] = 0xff & VBRTag0.charAt(0); - buffer[streamIndex++] = 0xff & VBRTag0.charAt(1); - buffer[streamIndex++] = 0xff & VBRTag0.charAt(2); - buffer[streamIndex++] = 0xff & VBRTag0.charAt(3); + /** + *
+ * 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. + *+ */ + 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; - // Put header flags - createInteger(buffer, streamIndex, FRAMES_FLAG + BYTES_FLAG + TOC_FLAG - + VBR_SCALE_FLAG); - streamIndex += 4; + if (mp3data != 0) { + var crc = new_int(1); + crc[0] = gfc.nMusicCRC; + vbr.updateMusicCRC(crc, buffer, bufferPos, minimum); + gfc.nMusicCRC = crc[0]; - // Put Total Number of frames - createInteger(buffer, streamIndex, gfc.VBR_seek_table.nVbrNumFrames); - streamIndex += 4; + /** + * 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; + } - // Put total audio stream size, including Xing/LAME Header - var streamSize = (gfc.VBR_seek_table.nBytesWritten + gfc.VBR_seek_table.TotalFrameSize); - createInteger(buffer, streamIndex, 0 | streamSize); - streamIndex += 4; + 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; - /* Put TOC */ - System.arraycopy(toc, 0, buffer, streamIndex, toc.length); - streamIndex += toc.length; + /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ + while (samples_out != 0) { - if (gfp.error_protection) { - // (jo) error_protection: add crc16 information to header - bs.CRC_writeheader(gfc, buffer); - } + 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 + */ - // work out CRC so far: initially crc = 0 - var crc = 0x00; - for (var i = 0; i < streamIndex; i++) - crc = crcUpdateLookup(buffer[i], crc); - // Put LAME VBR info - streamIndex += putLameVBR(gfp, streamSize, buffer, streamIndex, crc); + /* + * 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; - return gfc.VBR_seek_table.TotalFrameSize; - } + 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 */ - /** - * Write final VBR tag to the file. - * - * @param gfp - * global flags - * @param stream - * stream to add the VBR tag to - * @return 0 (OK), -1 else - * @throws IOException - * I/O error - */ - this.putVbrTag = function (gfp, stream) { - var gfc = gfp.internal_flags; + /* + * this should not be possible, and indicates we have + * overflown the pcm_buf buffer + */ - if (gfc.VBR_seek_table.pos <= 0) - return -1; + 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]; + } + } - // Seek to end of file - stream.seek(stream.length()); + 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; - // Get file size, abort if file has zero length. - if (stream.length() == 0) - return -1; + } + /* if (samples_out>0) */ + } + /* while (samples_out!=0) */ + } + /* if (gfc.decode_on_the_fly) */ - // The VBR tag may NOT be located at the beginning of the stream. If an - // ID3 version 2 tag was added, then it must be skipped to write the VBR - // tag data. - var id3v2TagSize = skipId3v2(stream); + } + /* if (mp3data) */ + return minimum; + }; - // Seek to the beginning of the stream - stream.seek(id3v2TagSize); + this.init_bit_stream_w = function (gfc) { + buf = new_byte(Lame.LAME_MAXMP3BUFFER); - var buffer = new_byte(MAXFRAMESIZE); - var bytes = getLameTagFrame(gfp, buffer); - if (bytes > buffer.length) { - return -1; - } + gfc.h_ptr = gfc.w_ptr = 0; + gfc.header[gfc.h_ptr].write_timing = 0; + bufByteIdx = -1; + bufBitIdx = 0; + totbit = 0; + }; - if (bytes < 1) { - return 0; - } + // From machine.h - // Put it all to disk again - stream.write(buffer, 0, bytes); - // success - return 0; - } } @@ -5135,6 +5135,32 @@ function MeanBits(meanBits) { this.bits = meanBits; } +//package mp3; + +function CalcNoiseResult() { + /** + * sum of quantization noise > masking + */ + this.over_noise = 0.; + /** + * sum of all quantization noise + */ + this.tot_noise = 0.; + /** + * max quantization noise + */ + this.max_noise = 0.; + /** + * number of quantization noise > masking + */ + this.over_count = 0; + /** + * SSD-like cost of distorted bands + */ + this.over_SSD = 0; + this.bits = 0; +} + function VBRQuantize() { var qupvt; var tak; @@ -5147,30 +5173,66 @@ function VBRQuantize() { } -//package mp3; -function CalcNoiseResult() { + +/** + * ATH related stuff, if something new ATH related has to be added, please plug + * it here into the ATH. + */ +function ATH() { + /** + * Method for the auto adjustment. + */ + this.useAdjust = 0; + /** + * factor for tuning the (sample power) point below which adaptive threshold + * of hearing adjustment occurs + */ + this.aaSensitivityP = 0.; + /** + * Lowering based on peak volume, 1 = no lowering. + */ + this.adjust = 0.; + /** + * Limit for dynamic ATH adjust. + */ + this.adjustLimit = 0.; + /** + * Determined to lower x dB each second. + */ + this.decay = 0.; /** - * sum of quantization noise > masking + * Lowest ATH value. */ - this.over_noise = 0.; + this.floor = 0.; /** - * sum of all quantization noise + * ATH for sfbs in long blocks. */ - this.tot_noise = 0.; + this.l = new_float(Encoder.SBMAX_l); /** - * max quantization noise + * ATH for sfbs in short blocks. */ - this.max_noise = 0.; + this.s = new_float(Encoder.SBMAX_s); /** - * number of quantization noise > masking + * ATH for partitioned sfb21 in long blocks. */ - this.over_count = 0; + this.psfb21 = new_float(Encoder.PSFB21); /** - * SSD-like cost of distorted bands + * ATH for partitioned sfb12 in short blocks. */ - this.over_SSD = 0; - this.bits = 0; + this.psfb12 = new_float(Encoder.PSFB12); + /** + * ATH for long block convolution bands. + */ + this.cb_l = new_float(Encoder.CBANDS); + /** + * ATH for short block convolution bands. + */ + this.cb_s = new_float(Encoder.CBANDS); + /** + * Equal loudness weights (based on ATH). + */ + this.eql_w = new_float(Encoder.BLKSIZE / 2); } @@ -5442,110 +5504,6 @@ function LameGlobalFlags() { -/** - * ATH related stuff, if something new ATH related has to be added, please plug - * it here into the ATH. - */ -function ATH() { - /** - * Method for the auto adjustment. - */ - this.useAdjust = 0; - /** - * factor for tuning the (sample power) point below which adaptive threshold - * of hearing adjustment occurs - */ - this.aaSensitivityP = 0.; - /** - * Lowering based on peak volume, 1 = no lowering. - */ - this.adjust = 0.; - /** - * Limit for dynamic ATH adjust. - */ - this.adjustLimit = 0.; - /** - * Determined to lower x dB each second. - */ - this.decay = 0.; - /** - * Lowest ATH value. - */ - this.floor = 0.; - /** - * ATH for sfbs in long blocks. - */ - this.l = new_float(Encoder.SBMAX_l); - /** - * ATH for sfbs in short blocks. - */ - this.s = new_float(Encoder.SBMAX_s); - /** - * ATH for partitioned sfb21 in long blocks. - */ - this.psfb21 = new_float(Encoder.PSFB21); - /** - * ATH for partitioned sfb12 in short blocks. - */ - this.psfb12 = new_float(Encoder.PSFB12); - /** - * ATH for long block convolution bands. - */ - this.cb_l = new_float(Encoder.CBANDS); - /** - * ATH for short block convolution bands. - */ - this.cb_s = new_float(Encoder.CBANDS); - /** - * Equal loudness weights (based on ATH). - */ - this.eql_w = new_float(Encoder.BLKSIZE / 2); -} - - - -function ReplayGain() { - this.linprebuf = new_float(GainAnalysis.MAX_ORDER * 2); - /** - * left input samples, with pre-buffer - */ - this.linpre = 0; - this.lstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); - /** - * left "first step" (i.e. post first filter) samples - */ - this.lstep = 0; - this.loutbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); - /** - * left "out" (i.e. post second filter) samples - */ - this.lout = 0; - this.rinprebuf = new_float(GainAnalysis.MAX_ORDER * 2); - /** - * right input samples ... - */ - this.rinpre = 0; - this.rstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); - this.rstep = 0; - this.routbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); - this.rout = 0; - /** - * number of samples required to reach number of milliseconds required - * for RMS window - */ - this.sampleWindow = 0; - this.totsamp = 0; - this.lsum = 0.; - this.rsum = 0.; - this.freqindex = 0; - this.first = 0; - this.A = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); - this.B = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); - -} - - - function CBRNewIterationLoop(_quantize) { var quantize = _quantize; this.quantize = quantize; @@ -5614,6 +5572,48 @@ function CBRNewIterationLoop(_quantize) { this.quantize.rv.ResvFrameEnd(gfc, mean_bits); } } + + +function ReplayGain() { + this.linprebuf = new_float(GainAnalysis.MAX_ORDER * 2); + /** + * left input samples, with pre-buffer + */ + this.linpre = 0; + this.lstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + /** + * left "first step" (i.e. post first filter) samples + */ + this.lstep = 0; + this.loutbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + /** + * left "out" (i.e. post second filter) samples + */ + this.lout = 0; + this.rinprebuf = new_float(GainAnalysis.MAX_ORDER * 2); + /** + * right input samples ... + */ + this.rinpre = 0; + this.rstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + this.rstep = 0; + this.routbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + this.rout = 0; + /** + * number of samples required to reach number of milliseconds required + * for RMS window + */ + this.sampleWindow = 0; + this.totsamp = 0; + this.lsum = 0.; + this.rsum = 0.; + this.freqindex = 0; + this.first = 0; + this.A = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); + this.B = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); + +} + //package mp3; /** @@ -6657,6 +6657,15 @@ function QuantizePVT() { } + +function CalcNoiseData() { + this.global_gain = 0; + this.sfb_count1 = 0; + this.step = new_int(39); + this.noise = new_float(39); + this.noise_log = new_float(39); +} + //package mp3; @@ -6748,15 +6757,6 @@ function GrInfo() { } -function CalcNoiseData() { - this.global_gain = 0; - this.sfb_count1 = 0; - this.step = new_int(39); - this.noise = new_float(39); - this.noise_log = new_float(39); -} - - var L3Side = {}; @@ -10074,6 +10074,22 @@ function IIISideInfo() { } +function III_psy_xmin() { + this.l = new_float(Encoder.SBMAX_l); + this.s = new_float_n([Encoder.SBMAX_s, 3]); + + var self = this; + this.assign = function (iii_psy_xmin) { + System.arraycopy(iii_psy_xmin.l, 0, self.l, 0, Encoder.SBMAX_l); + for (var i = 0; i < Encoder.SBMAX_s; i++) { + for (var j = 0; j < 3; j++) { + self.s[i][j] = iii_psy_xmin.s[i][j]; + } + } + } +} + + //package mp3; @@ -10098,22 +10114,6 @@ function NsPsy() { } -function III_psy_xmin() { - this.l = new_float(Encoder.SBMAX_l); - this.s = new_float_n([Encoder.SBMAX_s, 3]); - - var self = this; - this.assign = function (iii_psy_xmin) { - System.arraycopy(iii_psy_xmin.l, 0, self.l, 0, Encoder.SBMAX_l); - for (var i = 0; i < Encoder.SBMAX_s; i++) { - for (var j = 0; j < 3; j++) { - self.s[i][j] = iii_psy_xmin.s[i][j]; - } - } - } -} - - LameInternalFlags.MFSIZE = (3 * 1152 + Encoder.ENCDELAY - Encoder.MDCTDELAY); @@ -15345,7 +15345,6 @@ function Lame() { - function GetAudio() { var parse; var mpg; @@ -15492,7 +15491,6 @@ WavHeader.readHeader = function (dataView) { break; default: throw 'extended fmt chunk not implemented'; - break; } pos += fmtLen; var data = WavHeader.data; @@ -15510,78 +15508,6 @@ WavHeader.readHeader = function (dataView) { return w; }; -function testFullLength() { - var r = fs.readFileSync("testdata/IMG_0373.wav"); - var sampleBuf = new Uint8Array(r).buffer; - var w = WavHeader.readHeader(new DataView(sampleBuf)); - var samples = new Int16Array(sampleBuf, w.dataOffset, w.dataLen / 2); - var remaining = samples.length; - var lameEnc = new Mp3Encoder(); //w.channels, w.sampleRate, 128); - var maxSamples = 1152; - - var fd = fs.openSync("testjs2.mp3", "w"); - var time = new Date().getTime(); - for (var i = 0; remaining >= maxSamples; i += maxSamples) { - var left = samples.subarray(i, i + maxSamples); - var right = samples.subarray(i, i + maxSamples); - - var mp3buf = lameEnc.encodeBuffer(left, right); - if (mp3buf.length > 0) { - fs.writeSync(fd, new Buffer(mp3buf), 0, mp3buf.length); - } - remaining -= maxSamples; - } - var mp3buf = lameEnc.flush(); - if (mp3buf.length > 0) { - fs.writeSync(fd, new Buffer(mp3buf), 0, mp3buf.length); - } - fs.closeSync(fd); - time = new Date().getTime() - time; - console.log('done in ' + time + 'msec'); -} - -function testStereo44100() { - var r1 = fs.readFileSync("testdata/Left44100.wav"); - var r2 = fs.readFileSync("testdata/Right44100.wav"); - var fd = fs.openSync("stereo.mp3", "w"); - - var sampleBuf1 = new Uint8Array(r1).buffer; - var sampleBuf2 = new Uint8Array(r2).buffer; - var w1 = WavHeader.readHeader(new DataView(sampleBuf1)); - var w2 = WavHeader.readHeader(new DataView(sampleBuf2)); - - var samples1 = new Int16Array(sampleBuf1, w1.dataOffset, w1.dataLen / 2); - var samples2 = new Int16Array(sampleBuf2, w2.dataOffset, w2.dataLen / 2); - var remaining1 = samples1.length; - var remaining2 = samples2.length; - - var lameEnc = new Mp3Encoder(2, w1.sampleRate, 128); - var maxSamples = 1152; - - var time = new Date().getTime(); - for (var i = 0; remaining1 >= maxSamples; i += maxSamples) { - var left = samples1.subarray(i, i + maxSamples); - var right = samples2.subarray(i, i + maxSamples); - - var mp3buf = lameEnc.encodeBuffer(left, right); - if (mp3buf.length > 0) { - fs.writeSync(fd, new Buffer(mp3buf), 0, mp3buf.length); - } - remaining1 -= maxSamples; - - } - var mp3buf = lameEnc.flush(); - if (mp3buf.length > 0) { - fs.writeSync(fd, new Buffer(mp3buf), 0, mp3buf.length); - } - fs.closeSync(fd); - time = new Date().getTime() - time; - console.log('done in ' + time + 'msec'); -} - -//testStereo44100(); -//testFullLength(); - L3Side.SFBMAX = (Encoder.SBMAX_s * 3); //testFullLength(); lamejs.Mp3Encoder = Mp3Encoder; diff --git a/lame.min.js b/lame.min.js index 6ebe697..363c7ba 100644 --- a/lame.min.js +++ b/lame.min.js @@ -1,309 +1,307 @@ -function lamejs(){function T(e){return new Int32Array(e)}function K(e){return new Float32Array(e)}function qa(e){if(1==e.length)return K(e[0]);for(var p=e[0],e=e.slice(1),l=[],z=0;z
f&&(f=0);9l[c.VBR_max_bitrate]&&(g[j][i]*=l[c.VBR_max_bitrate],g[j][i]/=q),k[j][i]>g[j][i]&&(k[j][i]=g[j][i]);return p};this.bitpressure_strategy=function(h,b,n,a){for(var f=0;f