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); }