/// <summary> /// <PRE> /// some simple statistics /// bitrate index 0: free bitrate . not allowed in VBR mode /// : bitrates, kbps depending on MPEG version /// bitrate index 15: forbidden /// mode_ext: /// 0: LR /// 1: LR-i /// 2: MS /// 3: MS-i /// </PRE> /// </summary> private void updateStats(LameInternalFlags gfc) { int gr, ch; Debug.Assert(0 <= gfc.bitrate_index && gfc.bitrate_index < 16); Debug.Assert(0 <= gfc.mode_ext && gfc.mode_ext < 4); /* count bitrate indices */ gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][4]++; gfc.bitrate_stereoMode_Hist[15][4]++; /* count 'em for every mode extension in case of 2 channel encoding */ if (gfc.channels_out == 2) { gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][gfc.mode_ext]++; gfc.bitrate_stereoMode_Hist[15][gfc.mode_ext]++; } for (gr = 0; gr < gfc.mode_gr; ++gr) { for (ch = 0; ch < gfc.channels_out; ++ch) { var bt = gfc.l3_side.tt[gr][ch].block_type; if (gfc.l3_side.tt[gr][ch].mixed_block_flag != 0) { bt = 4; } gfc.bitrate_blockType_Hist[gfc.bitrate_index][bt]++; gfc.bitrate_blockType_Hist[gfc.bitrate_index][5]++; gfc.bitrate_blockType_Hist[15][bt]++; gfc.bitrate_blockType_Hist[15][5]++; } } }
private int LongHuffmancodebits(LameInternalFlags gfc, GrInfo gi) { int bigvalues, bits; int region1Start, region2Start; bigvalues = gi.big_values; Debug.Assert(0 <= bigvalues && bigvalues <= 576); var i = gi.region0_count + 1; Debug.Assert(0 <= i); Debug.Assert(i < gfc.scalefac_band.l.Length); region1Start = gfc.scalefac_band.l[i]; i += gi.region1_count + 1; Debug.Assert(0 <= i); Debug.Assert(i < gfc.scalefac_band.l.Length); region2Start = gfc.scalefac_band.l[i]; if (region1Start > bigvalues) { region1Start = bigvalues; } if (region2Start > bigvalues) { region2Start = bigvalues; } bits = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi); bits += Huffmancode(gfc, gi.table_select[1], region1Start, region2Start, gi); bits += Huffmancode(gfc, gi.table_select[2], region2Start, bigvalues, gi); return(bits); }
internal void bitpressure_strategy(LameInternalFlags gfc, float[][][] l3_xmin, int[][] min_bits, int[][] max_bits) { for (var gr = 0; gr < gfc.mode_gr; gr++) { for (var ch = 0; ch < gfc.channels_out; ch++) { var gi = gfc.l3_side.tt[gr][ch]; var pxmin = l3_xmin[gr][ch]; var pxminPos = 0; for (var sfb = 0; sfb < gi.psy_lmax; sfb++) { pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_l / Encoder.SBMAX_l); } if (gi.block_type == Encoder.SHORT_TYPE) { for (var sfb = gi.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s); pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s); pxmin[pxminPos++] *= (float)(1.0 + .029 * sfb * sfb / Encoder.SBMAX_s / Encoder.SBMAX_s); } } max_bits[gr][ch] = (int)Math.Max(min_bits[gr][ch], 0.9 * max_bits[gr][ch]); } } }
/// <summary> /// write j bits into the bit stream, ignoring frame headers /// </summary> private void putbits_noheaders(LameInternalFlags gfc, int val, int j) { Debug.Assert(j < MAX_LENGTH - 2); while (j > 0) { int k; if (bufBitIdx == 0) { bufBitIdx = 8; bufByteIdx++; Debug.Assert(bufByteIdx < Lame.LAME_MAXMP3BUFFER); buf[bufByteIdx] = 0; } k = Math.Min(j, bufBitIdx); j -= k; bufBitIdx -= k; Debug.Assert(j < MAX_LENGTH); // 32 too large on 32 bit machines Debug.Assert(bufBitIdx < MAX_LENGTH); buf[bufByteIdx] |= (byte)((val >> j) << bufBitIdx); totbit += k; } }
/// <summary> /// write j bits into the bit stream /// </summary> private void putbits2(LameInternalFlags gfc, int val, int j) { Debug.Assert(j < MAX_LENGTH - 2); while (j > 0) { int k; if (bufBitIdx == 0) { bufBitIdx = 8; bufByteIdx++; Debug.Assert(bufByteIdx < Lame.LAME_MAXMP3BUFFER); Debug.Assert(gfc.header[gfc.w_ptr].write_timing >= totbit); if (gfc.header[gfc.w_ptr].write_timing == totbit) { putheader_bits(gfc); } buf[bufByteIdx] = 0; } k = Math.Min(j, bufBitIdx); j -= k; bufBitIdx -= k; Debug.Assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */ Debug.Assert(bufBitIdx < MAX_LENGTH); buf[bufByteIdx] |= (byte)((val >> j) << bufBitIdx); totbit += k; } }
private void putheader_bits(LameInternalFlags gfc) { Array.Copy(gfc.header[gfc.w_ptr].buf, 0, buf, bufByteIdx, gfc.sideinfo_len); bufByteIdx += gfc.sideinfo_len; totbit += gfc.sideinfo_len * 8; gfc.w_ptr = (gfc.w_ptr + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1); }
internal bool init_xrpow(LameInternalFlags gfc, GrInfo cod_info, float[] xrpow) { float sum = 0; var upper = cod_info.max_nonzero_coeff; Debug.Assert(xrpow != null); cod_info.xrpow_max = 0; Debug.Assert(0 <= upper && upper <= 575); Arrays.Fill(xrpow, upper, 576, 0); sum = init_xrpow_core(cod_info, xrpow, upper, sum); if (sum > 1E-20f) { var j = 0; if ((gfc.substep_shaping & 2) != 0) { j = 1; } for (var i = 0; i < cod_info.psymax; i++) { gfc.pseudohalf[i] = j; } return(true); } Arrays.Fill(cod_info.l3_enc, 0, 576, 0); return(false); }
internal void init_bit_stream_w(LameInternalFlags gfc) { buf = new byte[Lame.LAME_MAXMP3BUFFER]; gfc.h_ptr = gfc.w_ptr = 0; gfc.header[gfc.h_ptr].write_timing = 0; bufByteIdx = -1; bufBitIdx = 0; totbit = 0; }
internal void iteration_finish_one(LameInternalFlags gfc, int gr, int ch) { var l3_side = gfc.l3_side; var cod_info = l3_side.tt[gr][ch]; tk.best_scalefac_store(gfc, gr, ch, l3_side); if (gfc.use_best_huffman == 1) { tk.best_huffman_divide(gfc, cod_info); } rv.ResvAdjust(gfc, cod_info); }
internal void fft_short(LameInternalFlags gfc, float[][] x_real, int chn, float[][] buffer, int bufPos) { for (var b = 0; b < 3; b++) { var x = Encoder.BLKSIZE_s / 2; var k = (short)(576 / 3 * (b + 1)); var j = Encoder.BLKSIZE_s / 8 - 1; do { float f0, f1, f2, f3, w; var i = rv_tbl[j << 2] & 0xff; f0 = window_s[i] * buffer[chn][bufPos + i + k]; w = window_s[0x7f - i] * buffer[chn][bufPos + i + k + 0x80]; f1 = f0 - w; f0 = f0 + w; f2 = window_s[i + 0x40] * buffer[chn][bufPos + i + k + 0x40]; w = window_s[0x3f - i] * buffer[chn][bufPos + i + k + 0xc0]; f3 = f2 - w; f2 = f2 + w; x -= 4; x_real[b][x + 0] = f0 + f2; x_real[b][x + 2] = f0 - f2; x_real[b][x + 1] = f1 + f3; x_real[b][x + 3] = f1 - f3; f0 = window_s[i + 0x01] * buffer[chn][bufPos + i + k + 0x01]; w = window_s[0x7e - i] * buffer[chn][bufPos + i + k + 0x81]; f1 = f0 - w; f0 = f0 + w; f2 = window_s[i + 0x41] * buffer[chn][bufPos + i + k + 0x41]; w = window_s[0x3e - i] * buffer[chn][bufPos + i + k + 0xc1]; f3 = f2 - w; f2 = f2 + w; x_real[b][x + Encoder.BLKSIZE_s / 2 + 0] = f0 + f2; x_real[b][x + Encoder.BLKSIZE_s / 2 + 2] = f0 - f2; x_real[b][x + Encoder.BLKSIZE_s / 2 + 1] = f1 + f3; x_real[b][x + Encoder.BLKSIZE_s / 2 + 3] = f1 - f3; }while (--j >= 0); fht(x_real[b], x, Encoder.BLKSIZE_s / 2); /* BLKSIZE_s/2 because of 3DNow! ASM routine */ /* BLKSIZE/2 because of 3DNow! ASM routine */ } }
/// <summary> /// Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, as /// well as the definitions of the side information on pages 26 and 27. /// </summary> private int ShortHuffmancodebits(LameInternalFlags gfc, GrInfo gi) { var region1Start = 3 * gfc.scalefac_band.s[3]; if (region1Start > gi.big_values) { region1Start = gi.big_values; } /* short blocks do not have a region2 */ var bits = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi); bits += Huffmancode(gfc, gi.table_select[1], region1Start, gi.big_values, gi); return(bits); }
private int reduce_bit_usage(LameInternalFlags gfc, int gr, int ch) { var cod_info = gfc.l3_side.tt[gr][ch]; // try some better scalefac storage tak.best_scalefac_store(gfc, gr, ch, gfc.l3_side); // best huffman_divide may save some bits too if (gfc.use_best_huffman == 1) { tak.best_huffman_divide(gfc, cod_info); } return(cod_info.part2_3_length + cod_info.part2_length); }
internal void CRC_writeheader(LameInternalFlags gfc, byte[] header) { var crc = 0xffff; /* (jo) init crc16 for error_protection */ crc = CRC_update(header[2] & 0xff, crc); crc = CRC_update(header[3] & 0xff, crc); for (var i = 6; i < gfc.sideinfo_len; i++) { crc = CRC_update(header[i] & 0xff, crc); } header[4] = (byte)(crc >> 8); header[5] = unchecked ((byte)(crc & 255)); }
/// <summary> /// write N bits into the header /// </summary> private void writeheader(LameInternalFlags gfc, int val, int j) { var ptr = gfc.header[gfc.h_ptr].ptr; while (j > 0) { var k = Math.Min(j, 8 - (ptr & 7)); j -= k; Debug.Assert(j < MAX_LENGTH); // >> 32 too large for 32 bit machines gfc.header[gfc.h_ptr].buf[ptr >> 3] = (byte)(gfc.header[gfc.h_ptr].buf[ptr >> 3] | (byte)((val >> j) << (8 - (ptr & 7) - k))); ptr += k; } gfc.header[gfc.h_ptr].ptr = ptr; }
internal void fft_long(LameInternalFlags gfc, float[] y, int chn, float[][] buffer, int bufPos) { var jj = Encoder.BLKSIZE / 8 - 1; var x = Encoder.BLKSIZE / 2; do { float f0, f1, f2, f3, w; var i = rv_tbl[jj] & 0xff; f0 = window[i] * buffer[chn][bufPos + i]; w = window[i + 0x200] * buffer[chn][bufPos + i + 0x200]; f1 = f0 - w; f0 = f0 + w; f2 = window[i + 0x100] * buffer[chn][bufPos + i + 0x100]; w = window[i + 0x300] * buffer[chn][bufPos + i + 0x300]; f3 = f2 - w; f2 = f2 + w; x -= 4; y[x + 0] = f0 + f2; y[x + 2] = f0 - f2; y[x + 1] = f1 + f3; y[x + 3] = f1 - f3; f0 = window[i + 0x001] * buffer[chn][bufPos + i + 0x001]; w = window[i + 0x201] * buffer[chn][bufPos + i + 0x201]; f1 = f0 - w; f0 = f0 + w; f2 = window[i + 0x101] * buffer[chn][bufPos + i + 0x101]; w = window[i + 0x301] * buffer[chn][bufPos + i + 0x301]; f3 = f2 - w; f2 = f2 + w; y[x + Encoder.BLKSIZE / 2 + 0] = f0 + f2; y[x + Encoder.BLKSIZE / 2 + 2] = f0 - f2; y[x + Encoder.BLKSIZE / 2 + 1] = f1 + f3; y[x + Encoder.BLKSIZE / 2 + 3] = f1 - f3; }while (--jj >= 0); fht(y, x, Encoder.BLKSIZE / 2); /* BLKSIZE/2 because of 3DNow! ASM routine */ }
internal void init_fft(LameInternalFlags gfc) { /* The type of window used here will make no real difference, but */ /* * in the interest of merging nspsytune stuff - switch to blackman * window */ for (var i = 0; i < Encoder.BLKSIZE; i++) { /* blackman window */ window[i] = (float)(0.42 - 0.5 * Math.Cos(2 * Math.PI * (i + .5) / Encoder.BLKSIZE) + 0.08 * Math.Cos(4 * Math.PI * (i + .5) / Encoder.BLKSIZE)); } for (var i = 0; i < Encoder.BLKSIZE_s / 2; i++) { window_s[i] = (float)(0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (i + 0.5) / Encoder.BLKSIZE_s))); } }
internal void trancate_smallspectrums(LameInternalFlags gfc, GrInfo gi, float[] l3_xmin, float[] work) { var distort = new float[L3Side.SFBMAX]; if (0 == (gfc.substep_shaping & 4) && gi.block_type == Encoder.SHORT_TYPE || (gfc.substep_shaping & 0x80) != 0) { return; } qupvt.calc_noise(gi, l3_xmin, distort, new CalcNoiseResult(), null); for (var jj = 0; jj < 576; jj++) { var xr = 0.0f; if (gi.l3_enc[jj] != 0) { xr = Math.Abs(gi.xr[jj]); } work[jj] = xr; } var j = 0; var sfb = 8; if (gi.block_type == Encoder.SHORT_TYPE) { sfb = 6; } do { float allowedNoise, trancateThreshold; int nsame, start; var width = gi.width[sfb]; j += width; if (distort[sfb] >= 1.0) { continue; } Arrays.Sort(work, j - width, width); if (BitStream.EQ(work[j - 1], 0.0f)) { continue; } allowedNoise = (1.0f - distort[sfb]) * l3_xmin[sfb]; trancateThreshold = 0.0f; start = 0; do { float noise; for (nsame = 1; start + nsame < width; nsame++) { if (BitStream.NEQ(work[start + j - width], work[start + j + nsame - width])) { break; } } noise = work[start + j - width] * work[start + j - width] * nsame; if (allowedNoise < noise) { if (start != 0) { trancateThreshold = work[start + j - width - 1]; } break; } allowedNoise -= noise; start += nsame; }while (start < width); if (BitStream.EQ(trancateThreshold, 0.0f)) { continue; } do { if (Math.Abs(gi.xr[j - width]) <= trancateThreshold) { gi.l3_enc[j - width] = 0; } }while (--width > 0); }while (++sfb < gi.psymax); gi.part2_3_length = tk.noquant_count_bits(gfc, gi, null); }
private int bin_search_StepSize(LameInternalFlags gfc, GrInfo cod_info, int desired_rate, int ch, float[] xrpow) { int nBits; var CurrentStep = gfc.CurrentStep[ch]; var flagGoneOver = false; var start = gfc.OldValue[ch]; var Direction = BinSearchDirection.BINSEARCH_NONE; cod_info.global_gain = start; desired_rate -= cod_info.part2_length; Debug.Assert(CurrentStep != 0); for (;;) { int step; nBits = tk.count_bits(gfc, xrpow, cod_info, null); if (CurrentStep == 1 || nBits == desired_rate) { break; } if (nBits > desired_rate) { if (Direction == BinSearchDirection.BINSEARCH_DOWN) { flagGoneOver = true; } if (flagGoneOver) { CurrentStep /= 2; } Direction = BinSearchDirection.BINSEARCH_UP; step = CurrentStep; } else { if (Direction == BinSearchDirection.BINSEARCH_UP) { flagGoneOver = true; } if (flagGoneOver) { CurrentStep /= 2; } Direction = BinSearchDirection.BINSEARCH_DOWN; step = -CurrentStep; } cod_info.global_gain += step; if (cod_info.global_gain < 0) { cod_info.global_gain = 0; flagGoneOver = true; } if (cod_info.global_gain > 255) { cod_info.global_gain = 255; flagGoneOver = true; } } Debug.Assert(cod_info.global_gain >= 0); Debug.Assert(cod_info.global_gain < 256); while (nBits > desired_rate && cod_info.global_gain < 255) { cod_info.global_gain++; nBits = tk.count_bits(gfc, xrpow, cod_info, null); } gfc.CurrentStep[ch] = start - cod_info.global_gain >= 4 ? 4 : 2; gfc.OldValue[ch] = cod_info.global_gain; cod_info.part2_3_length = nBits; return(nBits); }
internal void init_outer_loop(LameInternalFlags gfc, GrInfo cod_info) { cod_info.part2_3_length = 0; cod_info.big_values = 0; cod_info.count1 = 0; cod_info.global_gain = 210; cod_info.scalefac_compress = 0; cod_info.table_select[0] = 0; cod_info.table_select[1] = 0; cod_info.table_select[2] = 0; cod_info.subblock_gain[0] = 0; cod_info.subblock_gain[1] = 0; cod_info.subblock_gain[2] = 0; cod_info.subblock_gain[3] = 0; cod_info.region0_count = 0; cod_info.region1_count = 0; cod_info.preflag = 0; cod_info.scalefac_scale = 0; cod_info.count1table_select = 0; cod_info.part2_length = 0; cod_info.sfb_lmax = Encoder.SBPSY_l; cod_info.sfb_smin = Encoder.SBPSY_s; cod_info.psy_lmax = gfc.sfb21_extra ? Encoder.SBMAX_l : Encoder.SBPSY_l; cod_info.psymax = cod_info.psy_lmax; cod_info.sfbmax = cod_info.sfb_lmax; cod_info.sfbdivide = 11; for (var sfb = 0; sfb < Encoder.SBMAX_l; sfb++) { cod_info.width[sfb] = gfc.scalefac_band.l[sfb + 1] - gfc.scalefac_band.l[sfb]; cod_info.window[sfb] = 3; } if (cod_info.block_type == Encoder.SHORT_TYPE) { var ixwork = new float[576]; cod_info.sfb_smin = 0; cod_info.sfb_lmax = 0; if (cod_info.mixed_block_flag != 0) { cod_info.sfb_smin = 3; cod_info.sfb_lmax = gfc.mode_gr * 2 + 4; } cod_info.psymax = cod_info.sfb_lmax + 3 * ((gfc.sfb21_extra ? Encoder.SBMAX_s : Encoder.SBPSY_s) - cod_info.sfb_smin); cod_info.sfbmax = cod_info.sfb_lmax + 3 * (Encoder.SBPSY_s - cod_info.sfb_smin); cod_info.sfbdivide = cod_info.sfbmax - 18; cod_info.psy_lmax = cod_info.sfb_lmax; var ix = gfc.scalefac_band.l[cod_info.sfb_lmax]; Array.Copy(cod_info.xr, 0, ixwork, 0, 576); for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { var start = gfc.scalefac_band.s[sfb]; var end = gfc.scalefac_band.s[sfb + 1]; for (var window = 0; window < 3; window++) { for (var l = start; l < end; l++) { cod_info.xr[ix++] = ixwork[3 * l + window]; } } } var j = cod_info.sfb_lmax; for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { cod_info.width[j] = cod_info.width[j + 1] = cod_info.width[j + 2] = gfc.scalefac_band.s[sfb + 1] - gfc.scalefac_band.s[sfb]; cod_info.window[j] = 0; cod_info.window[j + 1] = 1; cod_info.window[j + 2] = 2; j += 3; } } cod_info.count1bits = 0; cod_info.sfb_partition_table = qupvt.nr_of_sfb_block[0][0]; cod_info.slen[0] = 0; cod_info.slen[1] = 0; cod_info.slen[2] = 0; cod_info.slen[3] = 0; cod_info.max_nonzero_coeff = 575; Arrays.Fill(cod_info.scalefac, 0); psfb21_analogsilence(gfc, cod_info); }
private void psfb21_analogsilence(LameInternalFlags gfc, GrInfo cod_info) { var ath = gfc.ATH; var xr = cod_info.xr; if (cod_info.block_type != Encoder.SHORT_TYPE) { var stop = false; for (var gsfb = Encoder.PSFB21 - 1; gsfb >= 0 && !stop; gsfb--) { var start = gfc.scalefac_band.psfb21[gsfb]; var end = gfc.scalefac_band.psfb21[gsfb + 1]; var ath21 = qupvt.athAdjust(ath.adjust, ath.psfb21[gsfb], ath.floor); if (gfc.nsPsy.longfact[21] > 1e-12f) { ath21 *= gfc.nsPsy.longfact[21]; } for (var j = end - 1; j >= start; j--) { if (Math.Abs(xr[j]) < ath21) { xr[j] = 0; } else { stop = true; break; } } } } else { for (var block = 0; block < 3; block++) { var stop = false; for (var gsfb = Encoder.PSFB12 - 1; gsfb >= 0 && !stop; gsfb--) { var start = gfc.scalefac_band.s[12] * 3 + (gfc.scalefac_band.s[13] - gfc.scalefac_band.s[12]) * block + (gfc.scalefac_band.psfb12[gsfb] - gfc.scalefac_band.psfb12[0]); var end = start + (gfc.scalefac_band.psfb12[gsfb + 1] - gfc.scalefac_band.psfb12[gsfb]); var ath12 = qupvt.athAdjust(ath.adjust, ath.psfb12[gsfb], ath.floor); if (gfc.nsPsy.shortfact[12] > 1e-12f) { ath12 *= gfc.nsPsy.shortfact[12]; } for (var j = end - 1; j >= start; j--) { if (Math.Abs(xr[j]) < ath12) { xr[j] = 0; } else { stop = true; break; } } } } } }
private int huffman_coder_count1(LameInternalFlags gfc, GrInfo gi) { /* Write count1 area */ var h = Tables.ht[gi.count1table_select + 32]; int i, bits = 0; var ix = gi.big_values; var xr = gi.big_values; Debug.Assert(gi.count1table_select < 2); for (i = (gi.count1 - gi.big_values) / 4; i > 0; --i) { var huffbits = 0; int p = 0, v; v = gi.l3_enc[ix + 0]; if (v != 0) { p += 8; if (gi.xr[xr + 0] < 0) { huffbits++; } Debug.Assert(v <= 1); } v = gi.l3_enc[ix + 1]; if (v != 0) { p += 4; huffbits *= 2; if (gi.xr[xr + 1] < 0) { huffbits++; } Debug.Assert(v <= 1); } v = gi.l3_enc[ix + 2]; if (v != 0) { p += 2; huffbits *= 2; if (gi.xr[xr + 2] < 0) { huffbits++; } Debug.Assert(v <= 1); } v = gi.l3_enc[ix + 3]; if (v != 0) { p++; huffbits *= 2; if (gi.xr[xr + 3] < 0) { huffbits++; } Debug.Assert(v <= 1); } ix += 4; xr += 4; putbits2(gfc, huffbits + h.table[p], h.hlen[p]); bits += h.hlen[p]; } return(bits); }
/// <summary> /// auto-adjust of ATH, useful for low volume Gabriel Bouvigne 3 feb 2001 /// modifies some values in gfp.internal_flags.ATH (gfc.ATH) /// </summary> private void adjust_ATH(LameInternalFlags gfc) { float gr2_max, max_pow; if (gfc.ATH.useAdjust == 0) { gfc.ATH.adjust = 1.0f; /* no adjustment */ return; } /* jd - 2001 mar 12, 27, jun 30 */ /* loudness based on equal loudness curve; */ /* use granule with maximum combined loudness */ max_pow = gfc.loudness_sq[0][0]; gr2_max = gfc.loudness_sq[1][0]; if (gfc.channels_out == 2) { max_pow += gfc.loudness_sq[0][1]; gr2_max += gfc.loudness_sq[1][1]; } else { max_pow += max_pow; gr2_max += gr2_max; } if (gfc.mode_gr == 2) { max_pow = Math.Max(max_pow, gr2_max); } max_pow *= (float)0.5; // max_pow approaches 1.0 for full band noise /* jd - 2001 mar 31, jun 30 */ /* user tuning of ATH adjustment region */ max_pow *= gfc.ATH.aaSensitivityP; /* * adjust ATH depending on range of maximum value */ /* jd - 2001 feb27, mar12,20, jun30, jul22 */ /* continuous curves based on approximation */ /* to GB's original values. */ /* For an increase in approximate loudness, */ /* set ATH adjust to adjust_limit immediately */ /* after a delay of one frame. */ /* For a loudness decrease, reduce ATH adjust */ /* towards adjust_limit gradually. */ /* max_pow is a loudness squared or a power. */ if (max_pow > 0.03125) { // ((1 - 0.000625)/ 31.98) from curve below if (gfc.ATH.adjust >= 1.0) { gfc.ATH.adjust = 1.0f; } else { /* preceding frame has lower ATH adjust; */ /* ascend only to the preceding adjust_limit */ /* in case there is leading low volume */ if (gfc.ATH.adjust < gfc.ATH.adjustLimit) { gfc.ATH.adjust = gfc.ATH.adjustLimit; } } gfc.ATH.adjustLimit = 1.0f; } else { // adjustment curve /* about 32 dB maximum adjust (0.000625) */ var adj_lim_new = 31.98f * max_pow + 0.000625f; if (gfc.ATH.adjust >= adj_lim_new) { // descend gradually gfc.ATH.adjust = (float)(gfc.ATH.adjust * adj_lim_new * 0.075 + 0.925); if (gfc.ATH.adjust < adj_lim_new) { gfc.ATH.adjust = adj_lim_new; } } else { // ascend if (gfc.ATH.adjustLimit >= adj_lim_new) { gfc.ATH.adjust = adj_lim_new; } else { /* preceding frame has lower ATH adjust; */ /* ascend only to the preceding adjust_limit */ if (gfc.ATH.adjust < gfc.ATH.adjustLimit) { gfc.ATH.adjust = gfc.ATH.adjustLimit; } } } gfc.ATH.adjustLimit = adj_lim_new; } }
/// <summary> /// Implements the pseudocode of page 98 of the IS /// </summary> private int Huffmancode(LameInternalFlags gfc, int tableindex, int start, int end, GrInfo gi) { var h = Tables.ht[tableindex]; var bits = 0; Debug.Assert(tableindex < 32); if (0 == tableindex) { return(bits); } for (var i = start; i < end; i += 2) { var cbits = 0; var xbits = 0; var linbits = h.xlen; var xlen = h.xlen; var ext = 0; var x1 = gi.l3_enc[i]; var x2 = gi.l3_enc[i + 1]; if (x1 != 0) { if (gi.xr[i] < 0) { ext++; } cbits--; } if (tableindex > 15) { /* use ESC-words */ if (x1 > 14) { var linbits_x1 = x1 - 15; Debug.Assert(linbits_x1 <= h.linmax); ext |= linbits_x1 << 1; xbits = linbits; x1 = 15; } if (x2 > 14) { var linbits_x2 = x2 - 15; Debug.Assert(linbits_x2 <= h.linmax); ext <<= linbits; ext |= linbits_x2; xbits += linbits; x2 = 15; } xlen = 16; } if (x2 != 0) { ext <<= 1; if (gi.xr[i + 1] < 0) { ext++; } cbits--; } Debug.Assert((x1 | x2) < 16); x1 = x1 * xlen + x2; xbits -= cbits; cbits += h.hlen[x1]; Debug.Assert(cbits <= MAX_LENGTH); Debug.Assert(xbits <= MAX_LENGTH); putbits2(gfc, h.table[x1], cbits); putbits2(gfc, ext, xbits); bits += cbits + xbits; } return(bits); }
internal void mdct_sub48(LameInternalFlags gfc, float[] w0, float[] w1) { var wk = w0; var wkPos = 286; for (var ch = 0; ch < gfc.channels_out; ch++) { for (var gr = 0; gr < gfc.mode_gr; gr++) { int band; var gi = gfc.l3_side.tt[gr][ch]; var mdct_enc = gi.xr; var mdct_encPos = 0; var samp = gfc.sb_sample[ch][1 - gr]; var sampPos = 0; for (var k = 0; k < 18 / 2; k++) { window_subband(wk, wkPos, samp[sampPos]); window_subband(wk, wkPos + 32, samp[sampPos + 1]); sampPos += 2; wkPos += 64; for (band = 1; band < 32; band += 2) { samp[sampPos - 1][band] *= -1; } } for (band = 0; band < 32; band++, mdct_encPos += 18) { var type = gi.block_type; var band0 = gfc.sb_sample[ch][gr]; var band1 = gfc.sb_sample[ch][1 - gr]; if (gi.mixed_block_flag != 0 && band < 2) { type = 0; } if (gfc.amp_filter[band] < 1e-12) { Arrays.Fill(mdct_enc, mdct_encPos + 0, mdct_encPos + 18, 0); } else { if (gfc.amp_filter[band] < 1.0) { for (var k = 0; k < 18; k++) { band1[k][order[band]] *= gfc.amp_filter[band]; } } if (type == Encoder.SHORT_TYPE) { for (var k = -NS / 4; k < 0; k++) { var w = win[Encoder.SHORT_TYPE][k + 3]; mdct_enc[mdct_encPos + k * 3 + 9] = band0[9 + k][order[band]] * w - band0[8 - k][order[band]]; mdct_enc[mdct_encPos + k * 3 + 18] = band0[14 - k][order[band]] * w + band0[15 + k][order[band]]; mdct_enc[mdct_encPos + k * 3 + 10] = band0[15 + k][order[band]] * w - band0[14 - k][order[band]]; mdct_enc[mdct_encPos + k * 3 + 19] = band1[2 - k][order[band]] * w + band1[3 + k][order[band]]; mdct_enc[mdct_encPos + k * 3 + 11] = band1[3 + k][order[band]] * w - band1[2 - k][order[band]]; mdct_enc[mdct_encPos + k * 3 + 20] = band1[8 - k][order[band]] * w + band1[9 + k][order[band]]; } mdct_short(mdct_enc, mdct_encPos); } else { var work = new float[18]; for (var k = -NL / 4; k < 0; k++) { float a, b; a = win[type][k + 27] * band1[k + 9][order[band]] + win[type][k + 36] * band1[8 - k][order[band]]; b = win[type][k + 9] * band0[k + 9][order[band]] - win[type][k + 18] * band0[8 - k][order[band]]; work[k + 9] = a - b * tantab_l[3 + k + 9]; work[k + 18] = a * tantab_l[3 + k + 9] + b; } mdct_long(mdct_enc, mdct_encPos, work); } } if (type != Encoder.SHORT_TYPE && band != 0) { for (var k = 7; k >= 0; --k) { float bu, bd; bu = mdct_enc[mdct_encPos + k] * ca[20 + k] + mdct_enc[mdct_encPos + -1 - k] * cs[28 + k]; bd = mdct_enc[mdct_encPos + k] * cs[28 + k] - mdct_enc[mdct_encPos + -1 - k] * ca[20 + k]; mdct_enc[mdct_encPos + -1 - k] = bu; mdct_enc[mdct_encPos + k] = bd; } } } } wk = w1; wkPos = 286; if (gfc.mode_gr == 1) { for (var i = 0; i < 18; i++) { Array.Copy(gfc.sb_sample[ch][1][i], 0, gfc.sb_sample[ch][0][i], 0, 32); } } } }
private bool inc_subblock_gain(LameInternalFlags gfc, GrInfo cod_info, float[] xrpow) { int sfb; var scalefac = cod_info.scalefac; for (sfb = 0; sfb < cod_info.sfb_lmax; sfb++) { if (scalefac[sfb] >= 16) { return(true); } } for (var window = 0; window < 3; window++) { var s1 = 0; var s2 = 0; for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbdivide; sfb += 3) { if (s1 < scalefac[sfb]) { s1 = scalefac[sfb]; } } for (; sfb < cod_info.sfbmax; sfb += 3) { if (s2 < scalefac[sfb]) { s2 = scalefac[sfb]; } } if (s1 < 16 && s2 < 8) { continue; } if (cod_info.subblock_gain[window] >= 7) { return(true); } cod_info.subblock_gain[window]++; var j = gfc.scalefac_band.l[cod_info.sfb_lmax]; for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbmax; sfb += 3) { float amp; var width = cod_info.width[sfb]; var s = scalefac[sfb]; Debug.Assert(s >= 0); s = s - (4 >> cod_info.scalefac_scale); if (s >= 0) { scalefac[sfb] = s; j += width * 3; continue; } scalefac[sfb] = 0; { var gain = 210 + (s << (cod_info.scalefac_scale + 1)); amp = qupvt.IPOW20(gain); } j += width * (window + 1); for (var l = -width; l < 0; l++) { xrpow[j + l] *= amp; if (xrpow[j + l] > cod_info.xrpow_max) { cod_info.xrpow_max = xrpow[j + l]; } } j += width * (3 - window - 1); } { var amp = qupvt.IPOW20(202); j += cod_info.width[sfb] * (window + 1); for (var l = -cod_info.width[sfb]; l < 0; l++) { xrpow[j + l] *= amp; if (xrpow[j + l] > cod_info.xrpow_max) { cod_info.xrpow_max = xrpow[j + l]; } } } } return(false); }
internal virtual int VBR_encode_frame( LameInternalFlags gfc, float[][][] xr34orig, float[][][] l3_xmin, int[][] max_bits) { var sfwork_ = Arrays.ReturnRectangularArray <int>(2, 2, L3Side.SFBMAX); var vbrsfmin_ = Arrays.ReturnRectangularArray <int>(2, 2, L3Side.SFBMAX); var that_ = Arrays.ReturnRectangularArray <algo_t>(2, 2); var ngr = gfc.mode_gr; var nch = gfc.channels_out; var max_nbits_ch = Arrays.ReturnRectangularArray <int>(2, 2); var max_nbits_gr = new int[2]; var max_nbits_fr = 0; var use_nbits_ch = Arrays.ReturnRectangularArray <int>(2, 2); var use_nbits_gr = new int[2]; var use_nbits_fr = 0; /* * set up some encoding parameters */ for (var gr = 0; gr < ngr; ++gr) { max_nbits_gr[gr] = 0; for (var ch = 0; ch < nch; ++ch) { max_nbits_ch[gr][ch] = max_bits[gr][ch]; use_nbits_ch[gr][ch] = 0; max_nbits_gr[gr] += max_bits[gr][ch]; max_nbits_fr += max_bits[gr][ch]; that_[gr][ch] = new algo_t(); that_[gr][ch].gfc = gfc; that_[gr][ch].cod_info = gfc.l3_side.tt[gr][ch]; that_[gr][ch].xr34orig = xr34orig[gr][ch]; if (that_[gr][ch].cod_info.block_type == Encoder.SHORT_TYPE) { that_[gr][ch].alloc = new ShortBlockConstrain(this); } else { that_[gr][ch].alloc = new LongBlockConstrain(this); } } // for ch } /* * searches scalefactors */ for (var gr = 0; gr < ngr; ++gr) { for (var ch = 0; ch < nch; ++ch) { if (max_bits[gr][ch] > 0) { var that = that_[gr][ch]; var sfwork = sfwork_[gr][ch]; var vbrsfmin = vbrsfmin_[gr][ch]; int vbrmax; vbrmax = block_sf(that, l3_xmin[gr][ch], sfwork, vbrsfmin); that.alloc.alloc(that, sfwork, vbrsfmin, vbrmax); bitcount(that); } } } /* * encode 'as is' */ use_nbits_fr = 0; for (var gr = 0; gr < ngr; ++gr) { use_nbits_gr[gr] = 0; for (var ch = 0; ch < nch; ++ch) { var that = that_[gr][ch]; if (max_bits[gr][ch] > 0) { var max_nonzero_coeff = that.cod_info.max_nonzero_coeff; Debug.Assert(max_nonzero_coeff < 576); Arrays.Fill(that.cod_info.l3_enc, max_nonzero_coeff, 576, 0); quantizeAndCountBits(that); } use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); use_nbits_gr[gr] += use_nbits_ch[gr][ch]; } // for ch use_nbits_fr += use_nbits_gr[gr]; } /* * check bit constrains */ if (use_nbits_fr <= max_nbits_fr) { var ok = true; for (var gr = 0; gr < ngr; ++gr) { if (use_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE) { ok = false; } for (var ch = 0; ch < nch; ++ch) { if (use_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { ok = false; } } } if (ok) { return(use_nbits_fr); } } /* * OK, we are in trouble and have to define how many bits are to be used * for each granule */ { var ok = true; var sum_fr = 0; for (var gr = 0; gr < ngr; ++gr) { max_nbits_gr[gr] = 0; for (var ch = 0; ch < nch; ++ch) { if (use_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { max_nbits_ch[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL; } else { max_nbits_ch[gr][ch] = use_nbits_ch[gr][ch]; } max_nbits_gr[gr] += max_nbits_ch[gr][ch]; } if (max_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE) { var f = new float[2]; float s = 0; for (var ch = 0; ch < nch; ++ch) { if (max_nbits_ch[gr][ch] > 0) { f[ch] = (float)Math.Sqrt(Math.Sqrt(max_nbits_ch[gr][ch])); s += f[ch]; } else { f[ch] = 0; } } for (var ch = 0; ch < nch; ++ch) { if (s > 0) { max_nbits_ch[gr][ch] = (int)(LameInternalFlags.MAX_BITS_PER_GRANULE * f[ch] / s); } else { max_nbits_ch[gr][ch] = 0; } } if (nch > 1) { if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; } if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; } if (max_nbits_ch[gr][0] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { max_nbits_ch[gr][0] = LameInternalFlags.MAX_BITS_PER_CHANNEL; } if (max_nbits_ch[gr][1] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { max_nbits_ch[gr][1] = LameInternalFlags.MAX_BITS_PER_CHANNEL; } } max_nbits_gr[gr] = 0; for (var ch = 0; ch < nch; ++ch) { max_nbits_gr[gr] += max_nbits_ch[gr][ch]; } } sum_fr += max_nbits_gr[gr]; } if (sum_fr > max_nbits_fr) { { var f = new float[2]; float s = 0; for (var gr = 0; gr < ngr; ++gr) { if (max_nbits_gr[gr] > 0) { f[gr] = (float)Math.Sqrt(max_nbits_gr[gr]); s += f[gr]; } else { f[gr] = 0; } } for (var gr = 0; gr < ngr; ++gr) { if (s > 0) { max_nbits_gr[gr] = (int)(max_nbits_fr * f[gr] / s); } else { max_nbits_gr[gr] = 0; } } } if (ngr > 1) { if (max_nbits_gr[0] > use_nbits_gr[0] + 125) { max_nbits_gr[1] += max_nbits_gr[0]; max_nbits_gr[1] -= use_nbits_gr[0] + 125; max_nbits_gr[0] = use_nbits_gr[0] + 125; } if (max_nbits_gr[1] > use_nbits_gr[1] + 125) { max_nbits_gr[0] += max_nbits_gr[1]; max_nbits_gr[0] -= use_nbits_gr[1] + 125; max_nbits_gr[1] = use_nbits_gr[1] + 125; } for (var gr = 0; gr < ngr; ++gr) { if (max_nbits_gr[gr] > LameInternalFlags.MAX_BITS_PER_GRANULE) { max_nbits_gr[gr] = LameInternalFlags.MAX_BITS_PER_GRANULE; } } } for (var gr = 0; gr < ngr; ++gr) { var f = new float[2]; float s = 0; for (var ch = 0; ch < nch; ++ch) { if (max_nbits_ch[gr][ch] > 0) { f[ch] = (float)Math.Sqrt(max_nbits_ch[gr][ch]); s += f[ch]; } else { f[ch] = 0; } } for (var ch = 0; ch < nch; ++ch) { if (s > 0) { max_nbits_ch[gr][ch] = (int)(max_nbits_gr[gr] * f[ch] / s); } else { max_nbits_ch[gr][ch] = 0; } } if (nch > 1) { if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; } if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; } for (var ch = 0; ch < nch; ++ch) { if (max_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { max_nbits_ch[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL; } } } } } /* sanity check */ sum_fr = 0; for (var gr = 0; gr < ngr; ++gr) { var sum_gr = 0; for (var ch = 0; ch < nch; ++ch) { sum_gr += max_nbits_ch[gr][ch]; if (max_nbits_ch[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { ok = false; } } sum_fr += sum_gr; if (sum_gr > LameInternalFlags.MAX_BITS_PER_GRANULE) { ok = false; } } if (sum_fr > max_nbits_fr) { ok = false; } if (!ok) { for (var gr = 0; gr < ngr; ++gr) { for (var ch = 0; ch < nch; ++ch) { max_nbits_ch[gr][ch] = max_bits[gr][ch]; } } } } /* we already called the 'best_scalefac_store' function, so we need to reset some variables before we can do it again. */ for (var ch = 0; ch < nch; ++ch) { gfc.l3_side.scfsi[ch][0] = 0; gfc.l3_side.scfsi[ch][1] = 0; gfc.l3_side.scfsi[ch][2] = 0; gfc.l3_side.scfsi[ch][3] = 0; } for (var gr = 0; gr < ngr; ++gr) { for (var ch = 0; ch < nch; ++ch) { gfc.l3_side.tt[gr][ch].scalefac_compress = 0; } } /* alter our encoded data, until it fits into the target bitrate */ use_nbits_fr = 0; for (var gr = 0; gr < ngr; ++gr) { use_nbits_gr[gr] = 0; for (var ch = 0; ch < nch; ++ch) { var that = that_[gr][ch]; use_nbits_ch[gr][ch] = 0; if (max_bits[gr][ch] > 0) { var sfwork = sfwork_[gr][ch]; var vbrsfmin = vbrsfmin_[gr][ch]; cutDistribution(sfwork, sfwork, that.cod_info.global_gain); outOfBitsStrategy(that, sfwork, vbrsfmin, max_nbits_ch[gr][ch]); } use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); Debug.Assert(use_nbits_ch[gr][ch] <= max_nbits_ch[gr][ch]); use_nbits_gr[gr] += use_nbits_ch[gr][ch]; } // for ch use_nbits_fr += use_nbits_gr[gr]; } /* check bit constrains, but it should always be ok, if there are no bugs ;-) */ if (use_nbits_fr <= max_nbits_fr) { return(use_nbits_fr); } throw new Exception( string.Format( "INTERNAL ERROR IN VBR NEW CODE (1313), please send bug report\n" + "maxbits={0:D} usedbits={1:D}\n", max_nbits_fr, use_nbits_fr)); }
/// <summary> /// <PRE> /// copy data out of the internal MP3 bit buffer into a user supplied /// unsigned char buffer. /// mp3data=0 indicates data in buffer is an id3tags and VBR tags /// mp3data=1 data is real mp3 frame data. /// </PRE> /// </summary> internal int copy_buffer(LameInternalFlags gfc, byte[] buffer, int bufferPos, int size, int mp3data) { var minimum = bufByteIdx + 1; if (minimum <= 0) { return(0); } if (size != 0 && minimum > size) { return(-1); } Array.Copy(buf, 0, buffer, bufferPos, minimum); bufByteIdx = -1; bufBitIdx = 0; if (mp3data != 0) { var crc = new int[1]; crc[0] = gfc.nMusicCRC; vbr.updateMusicCRC(crc, buffer, bufferPos, minimum); gfc.nMusicCRC = crc[0]; /// <summary> /// sum number of bytes belonging to the mp3 stream this info will be /// written into the Xing/LAME header for seeking /// </summary> if (minimum > 0) { gfc.VBR_seek_table.nBytesWritten += minimum; } if (gfc.decode_on_the_fly) { // decode the frame var pcm_buf = Arrays.ReturnRectangularArray <float>(2, 1152); var mp3_in = minimum; var samples_out = -1; int i; /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ while (samples_out != 0) { samples_out = mpg.hip_decode1_unclipped( gfc.hip, buffer, bufferPos, mp3_in, pcm_buf[0], pcm_buf[1]); /* * samples_out = 0: need more data to decode samples_out = * -1: error. Lets assume 0 pcm output samples_out = number * of samples output */ /* * set the lenght of the mp3 input buffer to zero, so that * in the next iteration of the loop we will be querying * mpglib about buffered data */ mp3_in = 0; if (samples_out == -1) { samples_out = 0; } if (samples_out > 0) { /* process the PCM data */ /* * this should not be possible, and indicates we have * overflown the pcm_buf buffer */ Debug.Assert(samples_out <= 1152); if (gfc.findPeakSample) { for (i = 0; i < samples_out; i++) { if (pcm_buf[0][i] > gfc.PeakSample) { gfc.PeakSample = pcm_buf[0][i]; } else if (-pcm_buf[0][i] > gfc.PeakSample) { gfc.PeakSample = -pcm_buf[0][i]; } } if (gfc.channels_out > 1) { for (i = 0; i < samples_out; i++) { if (pcm_buf[1][i] > gfc.PeakSample) { gfc.PeakSample = pcm_buf[1][i]; } else if (-pcm_buf[1][i] > gfc.PeakSample) { gfc.PeakSample = -pcm_buf[1][i]; } } } } if (gfc.findReplayGain) { if (ga.AnalyzeSamples( gfc.rgdata, pcm_buf[0], 0, pcm_buf[1], 0, samples_out, gfc.channels_out) == GainAnalysis.GAIN_ANALYSIS_ERROR) { return(-6); } } } // if (samples_out>0) } // while (samples_out!=0) } // if (gfc.decode_on_the_fly) } // if (mp3data) return(minimum); }