Beispiel #1
0
        /* pack side */

        static public int _vorbis_pack_info(ref Ogg.oggpack_buffer opb, ref vorbis_info vi)
        {
            codec_setup_info ci = vi.codec_setup as codec_setup_info;

            if (ci == null)
            {
                return(OV_EFAULT);
            }

            /* preamble */
            Ogg.oggpack_write(ref opb, 0x01, 8);
            _v_writestring(ref opb, new char[] { 'v', 'o', 'r', 'b', 'i', 's' }, 6);

            /* basic information about the stream */
            Ogg.oggpack_write(ref opb, 0x00, 32);
            Ogg.oggpack_write(ref opb, (uint)vi.channels, 8);
            Ogg.oggpack_write(ref opb, (uint)vi.rate, 32);

            Ogg.oggpack_write(ref opb, (uint)vi.bitrate_upper, 32);
            Ogg.oggpack_write(ref opb, (uint)vi.bitrate_nominal, 32);
            Ogg.oggpack_write(ref opb, (uint)vi.bitrate_lower, 32);

            Ogg.oggpack_write(ref opb, (uint)ilog2((uint)ci.blocksizes[0]), 4);
            Ogg.oggpack_write(ref opb, (uint)ilog2((uint)ci.blocksizes[1]), 4);
            Ogg.oggpack_write(ref opb, 1, 1);

            return(0);
        }
Beispiel #2
0
        /* helpers */

        static void _v_writestring(ref Ogg.oggpack_buffer o, char[] s, int bytes)
        {
            for (int i = 0; i < bytes; i++)
            {
                Ogg.oggpack_write(ref o, s[i], 8);
            }
        }
Beispiel #3
0
        static void mapping0_pack(ref vorbis_info vi, vorbis_info_mapping vm, ref Ogg.oggpack_buffer opb)
        {
            int i;
            vorbis_info_mapping0 info = vm as vorbis_info_mapping0;

            /* another 'we meant to do it this way' hack...  up to beta 4, we packed 4 binary zeros here to signify one submapping in use.  We
             * now redefine that to mean four bitflags that indicate use of deeper features; bit0:submappings, bit1:coupling,
             * bit2,3: reserved. This is backward compatable with all actual uses of the beta code. */

            if (info.submaps > 1)
            {
                Ogg.oggpack_write(ref opb, 1, 1);
                Ogg.oggpack_write(ref opb, (uint)(info.submaps - 1), 4);
            }
            else
            {
                Ogg.oggpack_write(ref opb, 0, 1);
            }

            if (info.coupling_steps > 0)
            {
                Ogg.oggpack_write(ref opb, 1, 1);
                Ogg.oggpack_write(ref opb, (uint)(info.coupling_steps - 1), 8);

                for (i = 0; i < info.coupling_steps; i++)
                {
                    Ogg.oggpack_write(ref opb, (uint)info.coupling_mag[i], ilog((uint)vi.channels));
                    Ogg.oggpack_write(ref opb, (uint)info.coupling_ang[i], ilog((uint)vi.channels));
                }
            }
            else
            {
                Ogg.oggpack_write(ref opb, 0, 1);
            }

            Ogg.oggpack_write(ref opb, 0, 2); /* 2,3:reserved */

            /* we don't write the channel submappings if we only have one... */
            if (info.submaps > 1)
            {
                for (i = 0; i < vi.channels; i++)
                {
                    Ogg.oggpack_write(ref opb, (uint)info.chmuxlist[i], 4);
                }
            }

            for (i = 0; i < info.submaps; i++)
            {
                Ogg.oggpack_write(ref opb, 0, 8); /* time submap unused */
                Ogg.oggpack_write(ref opb, (uint)info.floorsubmap[i], 8);
                Ogg.oggpack_write(ref opb, (uint)info.residuesubmap[i], 8);
            }
        }
Beispiel #4
0
        static void ClipTest(uint[] b, int vals, int bits, uint[] comp, int compsize)
        {
            int   bytes;
            byte *buffer;

            Ogg.oggpack_reset(ref o);

            for (int i = 0; i < vals; i++)
            {
                Ogg.oggpack_write(ref o, b[i], bits > 0 ? bits : iLog(b[i]));
            }

            buffer = Ogg.oggpack_get_buffer(ref o);
            bytes  = Ogg.oggpack_bytes(ref o);

            if (bytes != compsize)
            {
                throw new Exception("wrong number of bytes!");
            }

            for (int i = 0; i < bytes; i++)
            {
                if (buffer[i] != comp[i])
                {
                    for (int j = 0; j < bytes; j++)
                    {
                        Console.WriteLine(buffer[j] + " , " + comp[j]);
                    }

                    throw new Exception("wrote incorrect value!");
                }
            }

            Ogg.oggpack_readinit(ref r, buffer, bytes);

            for (int i = 0; i < vals; i++)
            {
                int tbit = bits > 0 ? bits : iLog(b[i]);

                if (Ogg.oggpack_look(ref r, tbit) == -1)
                {
                    throw new Exception("out of data!");
                }

                if (Ogg.oggpack_look(ref r, tbit) != (b[i] & mask[tbit]))
                {
                    throw new Exception("looked at incorrect value!");
                }

                if (tbit == 1)
                {
                    if (Ogg.oggpack_look1(ref r) != (b[i] & mask[tbit]))
                    {
                        throw new Exception("looked at single bit incorrect value!");
                    }
                }

                if (tbit == 1)
                {
                    if (Ogg.oggpack_read1(ref r) != (b[i] & mask[tbit]))
                    {
                        throw new Exception("read incorrect single bit value!");
                    }
                }
                else if (Ogg.oggpack_read(ref r, tbit) != (b[i] & mask[tbit]))
                {
                    throw new Exception("read incorrect value!");
                }
            }

            if (Ogg.oggpack_bytes(ref r) != bytes)
            {
                throw new Exception("leftover bytes after read!");
            }
        }
Beispiel #5
0
        static public void Test()
        {
            byte *buffer;
            int   bytes = 0;

            /* Test read/write together */
            /* Later we test against pregenerated bitstreams */
            Ogg.oggpack_writeinit(ref o);

            Console.Write("Small preclipped packing (LSb): ");
            ClipTest(testBuffer1, testSize1, 0, one, oneSize);
            Console.WriteLine("ok.");

            Console.Write("Null bit call (LSb): ");
            ClipTest(testBuffer3, testSize3, 0, two, twoSize);
            Console.WriteLine("ok.");

            Console.Write("Large preclipped packing (LSb): ");
            ClipTest(testBuffer2, testSize2, 0, three, threeSize);
            Console.WriteLine("ok.");

            Console.Write("32 bit precliiped packing (LSb): ");
            {
                Ogg.oggpack_reset(ref o);

                for (int i = 0; i < testSize2; i++)
                {
                    Ogg.oggpack_write(ref o, large[i], 32);
                }

                buffer = Ogg.oggpack_get_buffer(ref o);
                bytes  = Ogg.oggpack_bytes(ref o);

                Ogg.oggpack_readinit(ref r, buffer, bytes);

                for (int i = 0; i < testSize2; i++)
                {
                    if (Ogg.oggpack_look(ref r, 32) == -1)
                    {
                        throw new Exception("out of data. failed!");
                    }

                    if (Ogg.oggpack_look(ref r, 32) != large[i])
                    {
                        throw new Exception("read incorrect value! " + Ogg.oggpack_look(ref r, 32) + " != " + large[1]);
                    }

                    Ogg.oggpack_adv(ref r, 32);
                }

                if (Ogg.oggpack_bytes(ref r) != bytes)
                {
                    throw new Exception("leftover bytes after read!");
                }

                Console.WriteLine("ok.");
            }

            Console.Write("Small unclipped packing (LSb): ");
            ClipTest(testBuffer1, testSize1, 7, four, fourSize);
            Console.WriteLine("ok.");

            Console.Write("Large unclipped packing (LSb): ");
            ClipTest(testBuffer2, testSize2, 17, five, fiveSize);
            Console.WriteLine("ok.");

            Console.Write("Single bit unclipped packing (LSb): ");
            ClipTest(testBuffer3, testSize3, 1, six, sixSize);
            Console.WriteLine("ok.");

            Console.Write("Testing read past end (LSb): ");
            {
                byte *temp = (byte *)Ogg._ogg_malloc(8);

                try
                {
                    for (int i = 0; i < 8; i++)
                    {
                        temp[i] = 0;
                    }

                    Ogg.oggpack_readinit(ref r, temp, 8);

                    for (int i = 0; i < 64; i++)
                    {
                        if (Ogg.oggpack_read(ref r, 1) != 0)
                        {
                            throw new Exception("failed; got -1 prematurely.");
                        }
                    }

                    if (Ogg.oggpack_look(ref r, 1) != -1 || Ogg.oggpack_read(ref r, 1) != -1)
                    {
                        throw new Exception("failed; read past end without -1");
                    }

                    for (int i = 0; i < 8; i++)
                    {
                        temp[i] = 0;
                    }

                    Ogg.oggpack_readinit(ref r, temp, 8);

                    if (Ogg.oggpack_read(ref r, 30) != 0 || Ogg.oggpack_read(ref r, 16) != 0)
                    {
                        throw new Exception("failed 2; got -1 prematurely.");
                    }

                    if (Ogg.oggpack_look(ref r, 18) != 0 || Ogg.oggpack_look(ref r, 18) != 0)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    if (Ogg.oggpack_look(ref r, 19) != -1 || Ogg.oggpack_look(ref r, 19) != -1)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    if (Ogg.oggpack_look(ref r, 32) != -1 || Ogg.oggpack_look(ref r, 32) != -1)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    Ogg.oggpack_writeclear(ref o);
                    Console.WriteLine("ok.");
                }
                finally
                {
                    Ogg._ogg_free(temp);
                }
            }

            /********** lazy, cut-n-paste retest with MSb packing ***********/

            /* Test read/write together */
            /* Later we test against pregenerated bitstreams */

            Ogg.oggpackB_writeinit(ref o);

            Console.Write("Small preclipped packing (MSb): ");
            ClipTestB(testBuffer1, testSize1, 0, oneB, oneSize);
            Console.WriteLine("ok.");

            Console.Write("Null bit call (LSb): ");
            ClipTestB(testBuffer3, testSize3, 0, twoB, twoSize);
            Console.WriteLine("ok.");

            Console.Write("Large preclipped packing (LSb): ");
            ClipTestB(testBuffer2, testSize2, 0, threeB, threeSize);
            Console.WriteLine("ok.");

            Console.Write("32 bit precliiped packing (LSb): ");
            {
                Ogg.oggpackB_reset(ref o);

                for (int i = 0; i < testSize2; i++)
                {
                    Ogg.oggpackB_write(ref o, large[i], 32);
                }

                buffer = Ogg.oggpackB_get_buffer(ref o);
                bytes  = Ogg.oggpackB_bytes(ref o);

                Ogg.oggpackB_readinit(ref r, buffer, bytes);

                for (int i = 0; i < testSize2; i++)
                {
                    if (Ogg.oggpackB_look(ref r, 32) == -1)
                    {
                        throw new Exception("out of data. failed!");
                    }

                    if (Ogg.oggpackB_look(ref r, 32) != large[i])
                    {
                        throw new Exception("read incorrect value! " + Ogg.oggpackB_look(ref r, 32) + " != " + large[1]);
                    }

                    Ogg.oggpackB_adv(ref r, 32);
                }

                if (Ogg.oggpackB_bytes(ref r) != bytes)
                {
                    throw new Exception("leftover bytes after read!");
                }

                Console.WriteLine("ok.");
            }

            Console.Write("Small unclipped packing (LSb): ");
            ClipTestB(testBuffer1, testSize1, 7, fourB, fourSize);
            Console.WriteLine("ok.");

            Console.Write("Large unclipped packing (LSb): ");
            ClipTestB(testBuffer2, testSize2, 17, fiveB, fiveSize);
            Console.WriteLine("ok.");

            Console.Write("Single bit unclipped packing (LSb): ");
            ClipTestB(testBuffer3, testSize3, 1, sixB, sixSize);
            Console.WriteLine("ok.");

            Console.Write("Testing read past end (LSb): ");
            {
                byte *temp = (byte *)Ogg._ogg_malloc(8);

                try
                {
                    for (int i = 0; i < 8; i++)
                    {
                        temp[i] = 0;
                    }

                    Ogg.oggpackB_readinit(ref r, temp, 8);

                    for (int i = 0; i < 64; i++)
                    {
                        if (Ogg.oggpackB_read(ref r, 1) != 0)
                        {
                            throw new Exception("failed; got -1 prematurely.");
                        }
                    }

                    if (Ogg.oggpackB_look(ref r, 1) != -1 || Ogg.oggpackB_read(ref r, 1) != -1)
                    {
                        throw new Exception("failed; read past end without -1");
                    }

                    for (int i = 0; i < 8; i++)
                    {
                        temp[i] = 0;
                    }

                    Ogg.oggpackB_readinit(ref r, temp, 8);

                    if (Ogg.oggpackB_read(ref r, 30) != 0 || Ogg.oggpackB_read(ref r, 16) != 0)
                    {
                        throw new Exception("failed 2; got -1 prematurely.");
                    }

                    if (Ogg.oggpackB_look(ref r, 18) != 0 || Ogg.oggpackB_look(ref r, 18) != 0)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    if (Ogg.oggpackB_look(ref r, 19) != -1 || Ogg.oggpackB_look(ref r, 19) != -1)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    if (Ogg.oggpackB_look(ref r, 32) != -1 || Ogg.oggpackB_look(ref r, 32) != -1)
                    {
                        throw new Exception("failed 3; got -1 prematurely.");
                    }

                    Ogg.oggpackB_writeclear(ref o);
                    Console.WriteLine("ok.");
                }
                finally
                {
                    Ogg._ogg_free(temp);
                }
            }
        }
Beispiel #6
0
        static int mapping0_forward(ref vorbis_block vb)
        {
            vorbis_dsp_state vd = vb.vd;
            vorbis_info      vi = vd.vi;

            codec_setup_info      ci  = vi.codec_setup as codec_setup_info;
            private_state         b   = vb.vd.backend_state as private_state;
            vorbis_block_internal vbi = vb._internal as vorbis_block_internal;

            int n = vb.pcmend;
            int i, j, k;

            int *   nonzero     = stackalloc int[vi.channels];
            float **gmdct       = (float **)_vorbis_block_alloc(ref vb, vi.channels * sizeof(float *));
            int **  iwork       = (int **)_vorbis_block_alloc(ref vb, vi.channels * sizeof(int *));
            int *** floor_posts = (int ***)_vorbis_block_alloc(ref vb, vi.channels * sizeof(int **));

            float  global_ampmax = vbi.ampmax;
            float *local_ampmax  = stackalloc float[vi.channels];

            int blocktype  = vbi.blocktype;
            int modenumber = vb.W;

            vorbis_info_mapping0 info     = ci.map_param[modenumber] as vorbis_info_mapping0;
            vorbis_look_psy      psy_look = b.psy[blocktype + (vb.W != 0 ? 2 : 0)];

            vb.mode = modenumber;

            for (i = 0; i < vi.channels; i++)
            {
                float scale = 4.0f / n;
                float scale_dB;

                float *pcm    = vb.pcm[i];
                float *logfft = pcm;

                iwork[i] = (int *)_vorbis_block_alloc(ref vb, (n / 2) * sizeof(int));
                gmdct[i] = (float *)_vorbis_block_alloc(ref vb, (n / 2) * sizeof(float));

                /* + .345 is a hack; the original todB estimation used on IEEE 754 compliant machines had a bug that
                 * returned dB values about a third of a decibel too high.  The bug was harmless because tunings
                 * implicitly took that into account.  However, fixing the bug in the estimator requires changing all the tunings as well.
                 * For now, it's easier to sync things back up here, and recalibrate the tunings in the next major model upgrade. */

                scale_dB = todB(scale) + 0.345f;

                /* window the PCM data */
                _vorbis_apply_window(pcm, ref b.window, ref ci.blocksizes, vb.lW, vb.W, vb.nW);

                /* transform the PCM data */
                /* only MDCT right now.... */
                mdct_forward(b.transform[vb.W][0] as mdct_lookup, pcm, gmdct[i]);

                /* FFT yields more accurate tonal estimation (not phase sensitive) */
                drft_forward(ref b.fft_look[vb.W], pcm);

                /* + .345 is a hack; the original todB estimation used on IEEE 754 compliant machines had a bug that
                 * returned dB values about a third of a decibel too high.  The bug was harmless because tunings
                 * implicitly took that into account.  However, fixing the bug in the estimator requires changing all the tunings as well.
                 * For now, it's easier to sync things back up here, and recalibrate the tunings in the next major model upgrade. */

                logfft[0]       = scale_dB + todB(*pcm) + 0.345f;
                local_ampmax[i] = logfft[0];

                for (j = 1; j < n - 1; j += 2)
                {
                    float temp = pcm[j] * pcm[j] + pcm[j + 1] * pcm[j + 1];

                    /* + .345 is a hack; the original todB estimation used on IEEE 754 compliant machines had a bug that
                     * returned dB values about a third of a decibel too high.  The bug was harmless because tunings
                     * implicitly took that into account.  However, fixing the bug in the estimator requires changing all the tunings as well.
                     * For now, it's easier to sync things back up here, and recalibrate the tunings in the next major model upgrade. */

                    temp = logfft[(j + 1) >> 1] = scale_dB + 0.5f * todB(temp) + 0.345f;

                    if (temp > local_ampmax[i])
                    {
                        local_ampmax[i] = temp;
                    }
                }

                if (local_ampmax[i] > 0.0f)
                {
                    local_ampmax[i] = 0.0f;
                }

                if (local_ampmax[i] > global_ampmax)
                {
                    global_ampmax = local_ampmax[i];
                }
            }

            {
                float *noise = (float *)_vorbis_block_alloc(ref vb, n / 2 * sizeof(float));
                float *tone  = (float *)_vorbis_block_alloc(ref vb, n / 2 * sizeof(float));

                for (i = 0; i < vi.channels; i++)
                {
                    /* the encoder setup assumes that all the modes used by any
                     * specific bitrate tweaking use the same floor */

                    int submap = info.chmuxlist[i];

                    /* the following makes things clearer to *me* anyway */

                    float *mdct   = gmdct[i];
                    float *logfft = vb.pcm[i];

                    float *logmdct = logfft + n / 2;
                    float *logmask = logfft;

                    vb.mode = modenumber;

                    floor_posts[i] = (int **)_vorbis_block_alloc(ref vb, PACKETBLOBS * sizeof(int *));
                    ZeroMemory(floor_posts[i], sizeof(int *) * PACKETBLOBS);

                    for (j = 0; j < n / 2; j++)
                    {
                        /* + .345 is a hack; the original todB estimation used on IEEE 754 compliant machines had a bug that
                         * returned dB values about a third of a decibel too high.  The bug was harmless because tunings
                         * implicitly took that into account.  However, fixing the bug in the estimator requires changing all the tunings as well.
                         * For now, it's easier to sync things back up here, and recalibrate the tunings in the next major model upgrade. */

                        logmdct[j] = todB(mdct[j]) + 0.345f;

                        /* first step; noise masking.  Not only does 'noise masking' give us curves from which we can decide how much resolution
                         * to give noise parts of the spectrum, it also implicitly hands us a tonality estimate (the larger the value in the
                         * 'noise_depth' vector, the more tonal that area is) */

                        _vp_noisemask(ref psy_look, logmdct, noise); /* noise does not have by-frequency offset bias applied yet */

                        /* second step: 'all the other crap'; all the stuff that isn't computed/fit for bitrate management goes in the second psy
                         * vector.  This includes tone masking, peak limiting and ATH */

                        _vp_tonemask(ref psy_look, logfft, tone, global_ampmax, local_ampmax[i]);

                        /* third step; we offset the noise vectors, overlay tone masking.  We then do a floor1-specific line fit.  If we're
                         * performing bitrate management, the line fit is performed multiple times for up/down tweakage on demand. */

                        _vp_offset_and_mix(ref psy_look, noise, tone, 1, logmask, mdct, logmdct);

                        /* this algorithm is hardwired to floor 1 for now; abort out if  we're *not* floor1.  This won't happen unless someone has
                         * broken the encode setup lib.  Guard it anyway. */

                        if (ci.floor_type[info.floorsubmap[submap]] != 1)
                        {
                            return(-1);
                        }

                        floor_posts[i][PACKETBLOBS / 2] = floor1_fit(ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, logmdct, logmask);

                        /* are we managing bitrate?  If so, perform two more fits for later rate tweaking (fits represent hi/lo) */
                        if (vorbis_bitrate_managed(ref vb) != 0 && floor_posts[i][PACKETBLOBS / 2] != null)
                        {
                            /* higher rate by way of lower noise curve */
                            _vp_offset_and_mix(ref psy_look, noise, tone, 2, logmask, mdct, logmdct);

                            floor_posts[i][PACKETBLOBS - 1] = floor1_fit(ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, logmdct, logmask);

                            /* lower rate by way of higher noise curve */
                            _vp_offset_and_mix(ref psy_look, noise, tone, 0, logmask, mdct, logmdct);

                            floor_posts[i][0] = floor1_fit(ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, logmdct, logmask);

                            /* we also interpolate a range of intermediate curves for
                             * intermediate rates */
                            for (k = 1; k < PACKETBLOBS / 2; k++)
                            {
                                floor_posts[i][k] = floor1_interpolate_fit(ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, floor_posts[i][0], floor_posts[i][PACKETBLOBS / 2], k * 65536 / (PACKETBLOBS / 2));
                            }

                            for (k = PACKETBLOBS / 2 + 1; k < PACKETBLOBS - 1; k++)
                            {
                                floor_posts[i][k] = floor1_interpolate_fit(ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, floor_posts[i][PACKETBLOBS / 2], floor_posts[i][PACKETBLOBS - 1], (k - PACKETBLOBS / 2) * 65536 / (PACKETBLOBS / 2));
                            }
                        }
                    }
                }

                vbi.ampmax = global_ampmax;

                /*
                 * the next phases are performed once for vbr-only and PACKETBLOB
                 * times for bitrate managed modes.
                 *
                 * 1) encode actual mode being used
                 * 2) encode the floor for each channel, compute coded mask curve/res
                 * 3) normalize and couple.
                 * 4) encode residue
                 * 5) save packet bytes to the packetblob vector
                 */

                /* iterate over the many masking curve fits we've created */

                {
                    int **couple_bundle = stackalloc int *[vi.channels];
                    int * zerobundle    = stackalloc int[vi.channels];

                    for (k = (vorbis_bitrate_managed(ref vb) != 0 ? 0 : PACKETBLOBS / 2); k <= (vorbis_bitrate_managed(ref vb) != 0 ? PACKETBLOBS - 1 : PACKETBLOBS / 2); k++)
                    {
                        Ogg.oggpack_buffer opb = vbi.packetblob[k];

                        /* start out our new packet blob with packet type and mode */
                        /* Encode the packet type */
                        Ogg.oggpack_write(ref opb, 0, 1);

                        /* Encode the modenumber */
                        /* Encode frame mode, pre,post windowsize, then dispatch */
                        Ogg.oggpack_write(ref opb, (uint)modenumber, b.modebits);

                        if (vb.W != 0)
                        {
                            Ogg.oggpack_write(ref opb, (uint)vb.lW, 1);
                            Ogg.oggpack_write(ref opb, (uint)vb.nW, 1);
                        }

                        /* encode floor, compute masking curve, sep out residue */
                        for (i = 0; i < vi.channels; i++)
                        {
                            int  submap   = info.chmuxlist[i];
                            int *ilogmask = iwork[i];

                            nonzero[i] = floor1_encode(ref opb, ref vb, b.flr[info.floorsubmap[submap]] as vorbis_look_floor1, floor_posts[i][k], ilogmask);
                        }

                        /* our iteration is now based on masking curve, not prequant and coupling.  Only one prequant/coupling step */

                        /* quantize/couple */
                        /* incomplete implementation that assumes the tree is all depth one, or no tree at all */
                        _vp_couple_quantize_normalize(k, ci.psy_g_param, ref psy_look, info, gmdct, iwork, nonzero, ci.psy_g_param.sliding_lowpass[vb.W, k], vi.channels);

                        /* classify and encode by submap */
                        for (i = 0; i < info.submaps; i++)
                        {
                            int   ch_in_bundle = 0;
                            int **classifications;
                            int   resnum = info.residuesubmap[i];

                            for (j = 0; j < vi.channels; j++)
                            {
                                if (info.chmuxlist[j] == i)
                                {
                                    zerobundle[ch_in_bundle] = 0;

                                    if (nonzero[j] != 0)
                                    {
                                        zerobundle[ch_in_bundle] = 1;
                                    }

                                    couple_bundle[ch_in_bundle++] = iwork[j];
                                }
                            }

                            classifications = _residue_P[ci.residue_type[resnum]]._class(ref vb, b.residue[resnum], couple_bundle, zerobundle, ch_in_bundle);
                            ch_in_bundle    = 0;

                            for (j = 0; j < vi.channels; j++)
                            {
                                if (info.chmuxlist[j] == i)
                                {
                                    couple_bundle[ch_in_bundle++] = iwork[j];
                                }
                            }

                            _residue_P[ci.residue_type[resnum]].forward(ref opb, ref vb, b.residue[resnum], couple_bundle, zerobundle, ch_in_bundle, classifications, i);
                        }

                        /* ok, done encoding.  Next protopacket. */
                    }
                }

                return(0);
            }
        }