private void set_pinfo(LameGlobalFlags gfp, GrInfo cod_info, III_psy_ratio ratio, int gr, int ch) { var gfc = gfp.internal_flags; int sfb, sfb2; int l; float en0, en1; var ifqstep = cod_info.scalefac_scale == 0 ? .5f : 1.0f; var scalefac = cod_info.scalefac; var l3_xmin = new float[L3Side.SFBMAX]; var xfsf = new float[L3Side.SFBMAX]; var noise = new CalcNoiseResult(); calc_xmin(gfp, ratio, cod_info, l3_xmin); calc_noise(cod_info, l3_xmin, xfsf, noise, null); var j = 0; sfb2 = cod_info.sfb_lmax; if (cod_info.block_type != Encoder.SHORT_TYPE && 0 == cod_info.mixed_block_flag) { sfb2 = 22; } for (sfb = 0; sfb < sfb2; sfb++) { var start = gfc.scalefac_band.l[sfb]; var end = gfc.scalefac_band.l[sfb + 1]; var bw = end - start; for (en0 = 0.0f; j < end; j++) { en0 += cod_info.xr[j] * cod_info.xr[j]; } en0 /= bw; en1 = 1e15f; gfc.pinfo.en[gr][ch][sfb] = en1 * en0; gfc.pinfo.xfsf[gr][ch][sfb] = en1 * l3_xmin[sfb] * xfsf[sfb] / bw; if (ratio.en.l[sfb] > 0 && !gfp.ATHonly) { en0 = en0 / ratio.en.l[sfb]; } else { en0 = 0.0f; } gfc.pinfo.thr[gr][ch][sfb] = en1 * Math.Max(en0 * ratio.thm.l[sfb], gfc.ATH.l[sfb]); gfc.pinfo.LAMEsfb[gr][ch][sfb] = 0; if (cod_info.preflag != 0 && sfb >= 11) { gfc.pinfo.LAMEsfb[gr][ch][sfb] = -ifqstep * pretab[sfb]; } if (sfb < Encoder.SBPSY_l) { Debug.Assert(scalefac[sfb] >= 0); gfc.pinfo.LAMEsfb[gr][ch][sfb] -= ifqstep * scalefac[sfb]; } } if (cod_info.block_type == Encoder.SHORT_TYPE) { sfb2 = sfb; for (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]; var bw = end - start; for (var i = 0; i < 3; i++) { for (en0 = 0.0f, l = start; l < end; l++) { en0 += cod_info.xr[j] * cod_info.xr[j]; j++; } en0 = (float)Math.Max(en0 / bw, 1e-20); en1 = 1e15f; gfc.pinfo.en_s[gr][ch][3 * sfb + i] = en1 * en0; gfc.pinfo.xfsf_s[gr][ch][3 * sfb + i] = en1 * l3_xmin[sfb2] * xfsf[sfb2] / bw; if (ratio.en.s[sfb][i] > 0) { en0 = en0 / ratio.en.s[sfb][i]; } else { en0 = 0.0f; } if (gfp.ATHonly || gfp.ATHshort) { en0 = 0; } gfc.pinfo.thr_s[gr][ch][3 * sfb + i] = en1 * Math.Max(en0 * ratio.thm.s[sfb][i], gfc.ATH.s[sfb]); gfc.pinfo.LAMEsfb_s[gr][ch][3 * sfb + i] = -2.0 * cod_info.subblock_gain[i]; if (sfb < Encoder.SBPSY_s) { gfc.pinfo.LAMEsfb_s[gr][ch][3 * sfb + i] -= ifqstep * scalefac[sfb2]; } sfb2++; } } } gfc.pinfo.LAMEqss[gr][ch] = cod_info.global_gain; gfc.pinfo.LAMEmainbits[gr][ch] = cod_info.part2_3_length + cod_info.part2_length; gfc.pinfo.LAMEsfbits[gr][ch] = cod_info.part2_length; gfc.pinfo.over[gr][ch] = noise.over_count; gfc.pinfo.max_noise[gr][ch] = noise.max_noise * 10.0; gfc.pinfo.over_noise[gr][ch] = noise.over_noise * 10.0; gfc.pinfo.tot_noise[gr][ch] = noise.tot_noise * 10.0; gfc.pinfo.over_SSD[gr][ch] = noise.over_SSD; }
internal int lame_encode_mp3_frame( LameGlobalFlags gfp, float[] inbuf_l, float[] inbuf_r, byte[] mp3buf, int mp3bufPos, int mp3buf_size) { int mp3count; var masking_LR = Arrays.ReturnRectangularArray <III_psy_ratio>(2, 2); /* * LR masking & * energy */ masking_LR[0][0] = new III_psy_ratio(); masking_LR[0][1] = new III_psy_ratio(); masking_LR[1][0] = new III_psy_ratio(); masking_LR[1][1] = new III_psy_ratio(); var masking_MS = Arrays.ReturnRectangularArray <III_psy_ratio>(2, 2); /* MS masking & energy */ masking_MS[0][0] = new III_psy_ratio(); masking_MS[0][1] = new III_psy_ratio(); masking_MS[1][0] = new III_psy_ratio(); masking_MS[1][1] = new III_psy_ratio(); III_psy_ratio[][] masking; /* pointer to selected maskings */ var inbuf = new float[2][]; var gfc = gfp.internal_flags; var tot_ener = Arrays.ReturnRectangularArray <float>(2, 4); var ms_ener_ratio = new[] { .5f, .5f }; float[][] pe = { new[] { 0.0f, 0.0f }, new[] { 0.0f, 0.0f } }, pe_MS = { new[] { 0.0f, 0.0f }, new[] { 0.0f, 0.0f } }; float[][] pe_use; int ch, gr; inbuf[0] = inbuf_l; inbuf[1] = inbuf_r; if (gfc.lame_encode_frame_init == 0) { lame_encode_frame_init(gfp, inbuf); } /// <summary> ///******************** padding **************************** </summary> /// <summary> /// <PRE> /// padding method as described in /// "MPEG-Layer3 / Bitstream Syntax and Decoding" /// by Martin Sieler, Ralph Sperschneider /// /// note: there is no padding for the very first frame /// /// Robert Hegemann 2000-06-22 /// </PRE> /// </summary> gfc.padding = 0; if ((gfc.slot_lag -= gfc.frac_SpF) < 0) { gfc.slot_lag += gfp.out_samplerate; gfc.padding = 1; } /// <summary> ///************************************** /// Stage 1: psychoacoustic model * /// *************************************** /// </summary> if (gfc.psymodel != 0) { /* * psychoacoustic model psy model has a 1 granule (576) delay that * we must compensate for (mt 6/99). */ int ret; var bufp = new float[2][]; /* address of beginning of left & right granule */ var bufpPos = 0; /* address of beginning of left & right granule */ var blocktype = new int[2]; for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { bufp[ch] = inbuf[ch]; bufpPos = 576 + gr * 576 - FFTOFFSET; } if (gfp.VBR == VbrMode.vbr_mtrh || gfp.VBR == VbrMode.vbr_mt) { ret = psy.L3psycho_anal_vbr( gfp, bufp, bufpPos, gr, masking_LR, masking_MS, pe[gr], pe_MS[gr], tot_ener[gr], blocktype); } else { ret = psy.L3psycho_anal_ns( gfp, bufp, bufpPos, gr, masking_LR, masking_MS, pe[gr], pe_MS[gr], tot_ener[gr], blocktype); } if (ret != 0) { return(-4); } if (gfp.mode == MPEGMode.JOINT_STEREO) { ms_ener_ratio[gr] = tot_ener[gr][2] + tot_ener[gr][3]; if (ms_ener_ratio[gr] > 0) { ms_ener_ratio[gr] = tot_ener[gr][3] / ms_ener_ratio[gr]; } } /* block type flags */ for (ch = 0; ch < gfc.channels_out; ch++) { var cod_info = gfc.l3_side.tt[gr][ch]; cod_info.block_type = blocktype[ch]; cod_info.mixed_block_flag = 0; } } } else { /* no psy model */ for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { gfc.l3_side.tt[gr][ch].block_type = NORM_TYPE; gfc.l3_side.tt[gr][ch].mixed_block_flag = 0; pe_MS[gr][ch] = pe[gr][ch] = 700; } } } /* auto-adjust of ATH, useful for low volume */ adjust_ATH(gfc); /// <summary> ///************************************** /// Stage 2: MDCT * /// *************************************** /// </summary> /* polyphase filtering / mdct */ newMDCT.mdct_sub48(gfc, inbuf[0], inbuf[1]); /// <summary> ///************************************** /// Stage 3: MS/LR decision * /// *************************************** /// </summary> /* Here will be selected MS or LR coding of the 2 stereo channels */ gfc.mode_ext = MPG_MD_LR_LR; if (gfp.force_ms) { gfc.mode_ext = MPG_MD_MS_LR; } else if (gfp.mode == MPEGMode.JOINT_STEREO) { /* * ms_ratio = is scaled, for historical reasons, to look like a * ratio of side_channel / total. 0 = signal is 100% mono .5 = L & R * uncorrelated */ /// <summary> /// <PRE> /// [0] and [1] are the results for the two granules in MPEG-1, /// in MPEG-2 it's only a faked averaging of the same value /// _prev is the value of the last granule of the previous frame /// _next is the value of the first granule of the next frame /// </PRE> /// </summary> float sum_pe_MS = 0; float sum_pe_LR = 0; for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { sum_pe_MS += pe_MS[gr][ch]; sum_pe_LR += pe[gr][ch]; } } /* based on PE: M/S coding would not use much more bits than L/R */ if (sum_pe_MS <= 1.00 * sum_pe_LR) { var gi0 = gfc.l3_side.tt[0]; var gi1 = gfc.l3_side.tt[gfc.mode_gr - 1]; if (gi0[0].block_type == gi0[1].block_type && gi1[0].block_type == gi1[1].block_type) { gfc.mode_ext = MPG_MD_MS_LR; } } } /* bit and noise allocation */ if (gfc.mode_ext == MPG_MD_MS_LR) { masking = masking_MS; // use MS masking pe_use = pe_MS; } else { masking = masking_LR; // use LR masking pe_use = pe; } /* copy data for MP3 frame analyzer */ if (gfp.analysis && gfc.pinfo != null) { for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { gfc.pinfo.ms_ratio[gr] = gfc.ms_ratio[gr]; gfc.pinfo.ms_ener_ratio[gr] = ms_ener_ratio[gr]; gfc.pinfo.blocktype[gr][ch] = gfc.l3_side.tt[gr][ch].block_type; gfc.pinfo.pe[gr][ch] = pe_use[gr][ch]; Array.Copy(gfc.l3_side.tt[gr][ch].xr, 0, gfc.pinfo.xr[gr][ch], 0, 576); /* * in psymodel, LR and MS data was stored in pinfo. switch * to MS data: */ if (gfc.mode_ext == MPG_MD_MS_LR) { gfc.pinfo.ers[gr][ch] = gfc.pinfo.ers[gr][ch + 2]; Array.Copy( gfc.pinfo.energy[gr][ch + 2], 0, gfc.pinfo.energy[gr][ch], 0, gfc.pinfo.energy[gr][ch].Length); } } } } /// <summary> ///************************************** /// Stage 4: quantization loop * /// *************************************** /// </summary> if (gfp.VBR == VbrMode.vbr_off || gfp.VBR == VbrMode.vbr_abr) { int i; float f; for (i = 0; i < 18; i++) { gfc.nsPsy.pefirbuf[i] = gfc.nsPsy.pefirbuf[i + 1]; } f = 0.0f; for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { f += pe_use[gr][ch]; } } gfc.nsPsy.pefirbuf[18] = f; f = gfc.nsPsy.pefirbuf[9]; for (i = 0; i < 9; i++) { f += (gfc.nsPsy.pefirbuf[i] + gfc.nsPsy.pefirbuf[18 - i]) * fircoef[i]; } f = 670 * 5 * gfc.mode_gr * gfc.channels_out / f; for (gr = 0; gr < gfc.mode_gr; gr++) { for (ch = 0; ch < gfc.channels_out; ch++) { pe_use[gr][ch] *= f; } } } gfc.iteration_loop.iteration_loop(gfp, pe_use, ms_ener_ratio, masking); /// <summary> ///************************************** /// Stage 5: bitstream formatting * /// *************************************** /// </summary> /* write the frame to the bitstream */ bs.format_bitstream(gfp); /* copy mp3 bit buffer into array */ mp3count = bs.copy_buffer(gfc, mp3buf, mp3bufPos, mp3buf_size, 1); if (gfp.bWriteVbrTag) { vbr.addVbrFrame(gfp); } if (gfp.analysis && gfc.pinfo != null) { for (ch = 0; ch < gfc.channels_out; ch++) { int j; for (j = 0; j < FFTOFFSET; j++) { gfc.pinfo.pcmdata[ch][j] = gfc.pinfo.pcmdata[ch][j + gfp.framesize]; } for (j = FFTOFFSET; j < 1600; j++) { gfc.pinfo.pcmdata[ch][j] = inbuf[ch][j - FFTOFFSET]; } } qupvt.set_frame_pinfo(gfp, masking); } updateStats(gfc); return(mp3count); }
internal int calc_xmin(LameGlobalFlags gfp, III_psy_ratio ratio, GrInfo cod_info, float[] pxmin) { var pxminPos = 0; var gfc = gfp.internal_flags; int gsfb, j = 0, ath_over = 0; var ATH = gfc.ATH; var xr = cod_info.xr; var enable_athaa_fix = gfp.VBR == VbrMode.vbr_mtrh ? 1 : 0; var masking_lower = gfc.masking_lower; if (gfp.VBR == VbrMode.vbr_mtrh || gfp.VBR == VbrMode.vbr_mt) { masking_lower = 1.0f; } for (gsfb = 0; gsfb < cod_info.psy_lmax; gsfb++) { float en0, xmin; float rh1, rh2; int width, l; if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh) { xmin = athAdjust(ATH.adjust, ATH.l[gsfb], ATH.floor); } else { xmin = ATH.adjust * ATH.l[gsfb]; } width = cod_info.width[gsfb]; rh1 = xmin / width; rh2 = DBL_EPSILON; l = width >> 1; en0 = 0.0f; do { float xa, xb; xa = xr[j] * xr[j]; en0 += xa; rh2 += xa < rh1 ? xa : rh1; j++; xb = xr[j] * xr[j]; en0 += xb; rh2 += xb < rh1 ? xb : rh1; j++; }while (--l > 0); if (en0 > xmin) { ath_over++; } if (gsfb == Encoder.SBPSY_l) { var x = xmin * gfc.nsPsy.longfact[gsfb]; if (rh2 < x) { rh2 = x; } } if (enable_athaa_fix != 0) { xmin = rh2; } if (!gfp.ATHonly) { var e = ratio.en.l[gsfb]; if (e > 0.0f) { float x; x = en0 * ratio.thm.l[gsfb] * masking_lower / e; if (enable_athaa_fix != 0) { x *= gfc.nsPsy.longfact[gsfb]; } if (xmin < x) { xmin = x; } } } if (enable_athaa_fix != 0) { pxmin[pxminPos++] = xmin; } else { pxmin[pxminPos++] = xmin * gfc.nsPsy.longfact[gsfb]; } } var max_nonzero = 575; if (cod_info.block_type != Encoder.SHORT_TYPE) { var k = 576; while (k-- != 0 && BitStream.EQ(xr[k], 0)) { max_nonzero = k; } } cod_info.max_nonzero_coeff = max_nonzero; for (var sfb = cod_info.sfb_smin; gsfb < cod_info.psymax; sfb++, gsfb += 3) { int width, b; float tmpATH; if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh) { tmpATH = athAdjust(ATH.adjust, ATH.s[sfb], ATH.floor); } else { tmpATH = ATH.adjust * ATH.s[sfb]; } width = cod_info.width[gsfb]; for (b = 0; b < 3; b++) { float en0 = 0.0f, xmin; float rh1, rh2; var l = width >> 1; rh1 = tmpATH / width; rh2 = DBL_EPSILON; do { float xa, xb; xa = xr[j] * xr[j]; en0 += xa; rh2 += xa < rh1 ? xa : rh1; j++; xb = xr[j] * xr[j]; en0 += xb; rh2 += xb < rh1 ? xb : rh1; j++; }while (--l > 0); if (en0 > tmpATH) { ath_over++; } if (sfb == Encoder.SBPSY_s) { var x = tmpATH * gfc.nsPsy.shortfact[sfb]; if (rh2 < x) { rh2 = x; } } if (enable_athaa_fix != 0) { xmin = rh2; } else { xmin = tmpATH; } if (!gfp.ATHonly && !gfp.ATHshort) { var e = ratio.en.s[sfb][b]; if (e > 0.0f) { float x; x = en0 * ratio.thm.s[sfb][b] * masking_lower / e; if (enable_athaa_fix != 0) { x *= gfc.nsPsy.shortfact[sfb]; } if (xmin < x) { xmin = x; } } } if (enable_athaa_fix != 0) { pxmin[pxminPos++] = xmin; } else { pxmin[pxminPos++] = xmin * gfc.nsPsy.shortfact[sfb]; } } if (gfp.useTemporal == true) { if (pxmin[pxminPos - 3] > pxmin[pxminPos - 3 + 1]) { pxmin[pxminPos - 3 + 1] += (pxmin[pxminPos - 3] - pxmin[pxminPos - 3 + 1]) * gfc.decay; } if (pxmin[pxminPos - 3 + 1] > pxmin[pxminPos - 3 + 2]) { pxmin[pxminPos - 3 + 2] += (pxmin[pxminPos - 3 + 1] - pxmin[pxminPos - 3 + 2]) * gfc.decay; } } } return(ath_over); }