Пример #1
0
        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);
        }