static void _v_readstring(ref Ogg.oggpack_buffer o, ref char[] buf, int bytes) { for (int i = 0; i < bytes; i++) { buf[i] = (char)Ogg.oggpack_read(ref o, 8); } }
/* 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); }
/* 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); } }
/* used to track pcm position without actually performing decode. Useful for sequential 'fast forward' */ static public int vorbis_synthesis_trackonly(ref vorbis_block vb, ref Ogg.ogg_packet op) { vorbis_dsp_state vd = vb.vd; private_state b = vd.backend_state as private_state; vorbis_info vi = vd.vi; codec_setup_info ci = vi.codec_setup as codec_setup_info; Ogg.oggpack_buffer opb = vb.opb; int mode; /* first things first. Make sure decode is ready */ _vorbis_block_ripcord(ref vb); Ogg.oggpack_readinit(ref opb, op.packet, op.bytes); /* Check the packet type */ if (Ogg.oggpack_read(ref opb, 1) != 0) { /* Oops. This is not an audio data packet */ return(OV_ENOTAUDIO); } /* read our mode and pre/post windowsize */ mode = Ogg.oggpack_read(ref opb, b.modebits); if (mode == -1) { return(OV_EBADPACKET); } vb.mode = mode; vb.W = ci.mode_param[mode].blockflag; if (vb.W > 0) { vb.lW = Ogg.oggpack_read(ref opb, 1); vb.nW = Ogg.oggpack_read(ref opb, 1); if (vb.nW == -1) { return(OV_EBADPACKET); } } else { vb.lW = 0; vb.nW = 0; } /* more setup */ vb.granulepos = op.granulepos; vb.sequence = op.packetno; vb.eofflag = op.e_o_s; /* no pcm */ vb.pcmend = 0; vb.pcm = null; return(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); } }
/* Is this packet a vorbis ID header? */ static public int vorbis_synthesis_idheader(ref Ogg.ogg_packet op) { Ogg.oggpack_buffer opb = new Ogg.oggpack_buffer(); char[] buffer = new char[6]; if (op == null) { return(0); } Ogg.oggpack_readinit(ref opb, op.packet, op.bytes); if (op.b_o_s == 0) { return(0); /* Not the initial packet */ } if (Ogg.oggpack_read(ref opb, 8) != 1) { return(0); /* Not an ID header */ } _v_readstring(ref opb, ref buffer, 6); if ( buffer[0] != 'v' || buffer[1] != 'o' || buffer[2] != 'r' || buffer[3] != 'b' || buffer[4] != 'i' || buffer[5] != 's' ) { return(0); /* not vorbis */ } return(1); }
static public int vorbis_packet_blocksize(ref vorbis_info vi, ref Ogg.ogg_packet op) { codec_setup_info ci = vi.codec_setup as codec_setup_info; Ogg.oggpack_buffer opb = new Ogg.oggpack_buffer(); int mode; Ogg.oggpack_readinit(ref opb, op.packet, op.bytes); /* Check the packet type */ if (Ogg.oggpack_read(ref opb, 1) != 0) { /* Oops. This is not an audio data packet */ return(OV_ENOTAUDIO); } { int modebits = 0; int v = ci.modes; while (v > 1) { modebits++; v >>= 1; } /* read our mode and pre/post windowsize */ mode = Ogg.oggpack_read(ref opb, modebits); } if (mode == -1) { return(OV_EBADPACKET); } return(ci.blocksizes[ci.mode_param[mode].blockflag]); }
static public int vorbis_synthesis(ref vorbis_block vb, ref Ogg.ogg_packet op) { vorbis_dsp_state vd = (vb != null) ? vb.vd : null; private_state b = (vd != null) ? (vd.backend_state as private_state) : null; vorbis_info vi = (vd != null) ? vd.vi : null; codec_setup_info ci = (vi != null) ? (vi.codec_setup as codec_setup_info) : null; Ogg.oggpack_buffer opb = (vb != null) ? vb.opb : null; int type, mode, i; if (vd == null || b == null || vi == null || ci == null || opb == null) { return(OV_EBADHEADER); } /* first things first. Make sure decode is ready */ _vorbis_block_ripcord(ref vb); Ogg.oggpack_readinit(ref opb, op.packet, op.bytes); /* Check the packet type */ if (Ogg.oggpack_read(ref opb, 1) != 0) { /* Oops. This is not an audio data packet */ return(OV_ENOTAUDIO); } /* read our mode and pre/post windowsize */ mode = Ogg.oggpack_read(ref opb, b.modebits); if (mode == -1) { return(OV_EBADPACKET); } vb.mode = mode; if (ci.mode_param[mode] == null) { return(OV_EBADPACKET); } vb.W = ci.mode_param[mode].blockflag; if (vb.W > 0) { /* this doesn't get mapped through mode selection as it's used only for window selection */ vb.lW = Ogg.oggpack_read(ref opb, 1); vb.nW = Ogg.oggpack_read(ref opb, 1); if (vb.nW == -1) { return(OV_EBADPACKET); } } else { vb.lW = 0; vb.nW = 0; } /* more setup */ vb.granulepos = op.granulepos; vb.sequence = op.packetno; vb.eofflag = op.e_o_s; /* alloc pcm passback storage */ vb.pcmend = ci.blocksizes[vb.W]; vb.pcm = (float **)_vorbis_block_alloc(ref vb, sizeof(float *) * vi.channels); for (i = 0; i < vi.channels; i++) { vb.pcm[i] = (float *)_vorbis_block_alloc(ref vb, sizeof(float) * vb.pcmend); } /* unpack_header enforces range checking */ type = ci.map_type[ci.mode_param[mode].mapping]; return(_mapping_P[type].inverse(ref vb, ci.map_param[ci.mode_param[mode].mapping])); }
/* The Vorbis header is in three packets; the initial small packet in the first page that identifies basic parameters, a second packet * with bitstream comments and a third packet that holds the codebook. */ static public int vorbis_synthesis_headerin(ref vorbis_info vi, ref vorbis_comment vc, ref Ogg.ogg_packet op) { Ogg.oggpack_buffer opb = new Ogg.oggpack_buffer(); Ogg.oggpack_readinit(ref opb, op.packet, op.bytes); /* Which of the three types of header is this? */ /* Also verify header-ness, vorbis */ { char[] buffer = new char[6]; int packtype = Ogg.oggpack_read(ref opb, 8); _v_readstring(ref opb, ref buffer, 6); if ( buffer[0] != 'v' || buffer[1] != 'o' || buffer[2] != 'r' || buffer[3] != 'b' || buffer[4] != 'i' || buffer[5] != 's' ) { /* not a vorbis header */ return(OV_ENOTVORBIS); } switch (packtype) { case 0x01: /* least significant *bit* is read first */ { if (op.b_o_s == 0) { /* Not the initial packet */ return(OV_EBADHEADER); } if (vi.rate != 0) { /* previously initialized info header */ return(OV_EBADHEADER); } } return(_vorbis_unpack_info(ref vi, ref opb)); case 0x03: /* least significant *bit* is read first */ { if (vi.rate == 0) { /* um... we didn't get the initial header */ return(OV_EBADHEADER); } } return(_vorbis_unpack_comment(ref vc, ref opb)); case 0x05: /* least significant *bit* is read first */ { if (vi.rate == 0 || vc.vendor == null) { /* um... we didn;t get the initial header or comments yet */ return(OV_EBADHEADER); } } return(_vorbis_unpack_books(ref vi, ref opb)); default: { /* Not a valid vorbis header type */ return(OV_EBADHEADER); } } } }
/* all of the real encoding details are here. The modes, books, everything */ static public int _vorbis_unpack_books(ref vorbis_info vi, ref Ogg.oggpack_buffer opb) { codec_setup_info ci = vi.codec_setup as codec_setup_info; if (ci == null) { return(OV_EFAULT); } /* code books */ ci.books = Ogg.oggpack_read(ref opb, 8) + 1; if (ci.books <= 0) { goto err_out; } for (int i = 0; i < ci.books; i++) { ci.book_param[i] = vorbis_staticbook_unpack(ref opb); if (ci.book_param[i] == null) { goto err_out; } } /* time backend settings; hooks are unused */ { int times = Ogg.oggpack_read(ref opb, 6) + 1; if (times <= 0) { goto err_out; } for (int i = 0; i < times; i++) { int test = Ogg.oggpack_read(ref opb, 16); if (test < 0 || test >= VI_TIMEB) { goto err_out; } } } /* floor backend settings */ ci.floors = Ogg.oggpack_read(ref opb, 6) + 1; if (ci.floors <= 0) { goto err_out; } for (int i = 0; i < ci.floors; i++) { ci.floor_type[i] = Ogg.oggpack_read(ref opb, 16); if (ci.floor_type[i] < 0 || ci.floor_type[i] >= VI_FLOORB) { goto err_out; } ci.floor_param[i] = _floor_P[ci.floor_type[i]].unpack(ref vi, ref opb); if (ci.floor_param[i] == null) { goto err_out; } } /* residue backend settings */ ci.residues = Ogg.oggpack_read(ref opb, 6) + 1; if (ci.residues <= 0) { goto err_out; } for (int i = 0; i < ci.residues; i++) { ci.residue_type[i] = Ogg.oggpack_read(ref opb, 16); if (ci.residue_type[i] < 0 || ci.residue_type[i] >= VI_RESB) { goto err_out; } ci.residue_param[i] = _residue_P[ci.residue_type[i]].unpack(ref vi, ref opb); if (ci.residue_param == null) { goto err_out; } } /* map backed settings */ ci.maps = Ogg.oggpack_read(ref opb, 6) + 1; if (ci.maps <= 0) { goto err_out; } for (int i = 0; i < ci.maps; i++) { ci.map_type[i] = Ogg.oggpack_read(ref opb, 16); if (ci.map_type[i] < 0 || ci.map_type[i] >= VI_MAPB) { goto err_out; } ci.map_param[i] = _mapping_P[ci.map_type[i]].unpack(ref vi, ref opb); if (ci.map_param[i] == null) { goto err_out; } } /* mode settings */ ci.modes = Ogg.oggpack_read(ref opb, 6) + 1; if (ci.modes <= 0) { goto err_out; } for (int i = 0; i < ci.modes; i++) { ci.mode_param[i] = new vorbis_info_mode(); ci.mode_param[i].blockflag = Ogg.oggpack_read(ref opb, 1); ci.mode_param[i].windowtype = Ogg.oggpack_read(ref opb, 16); ci.mode_param[i].transformtype = Ogg.oggpack_read(ref opb, 16); ci.mode_param[i].mapping = Ogg.oggpack_read(ref opb, 8); if (ci.mode_param[i].windowtype >= VI_WINDOWB) { goto err_out; } if (ci.mode_param[i].transformtype >= VI_WINDOWB) { goto err_out; } if (ci.mode_param[i].mapping >= ci.maps) { goto err_out; } if (ci.mode_param[i].mapping < 0) { goto err_out; } } if (Ogg.oggpack_read(ref opb, 1) != 1) { goto err_out; } return(0); err_out: vorbis_info_clear(ref vi); return(OV_EBADHEADER); }
static int _vorbis_unpack_comment(ref vorbis_comment vc, ref Ogg.oggpack_buffer opb) { int i; int vendorlen = Ogg.oggpack_read(ref opb, 32); if (vendorlen < 0) { goto err_out; } if (vendorlen > opb.storage - 8) { goto err_out; } vc.vendor = new char[vendorlen + 1]; _v_readstring(ref opb, ref vc.vendor, vendorlen); i = Ogg.oggpack_read(ref opb, 32); if (i < 0) { goto err_out; } if (i > ((opb.storage - Ogg.oggpack_bytes(ref opb) >> 2))) { goto err_out; } vc.comments = i; vc.user_comments = new char[vc.comments + 1][]; vc.comment_lengths = new int[vc.comments + 1]; for (i = 0; i < vc.comments; i++) { int len = Ogg.oggpack_read(ref opb, 32); if (len < 0) { goto err_out; } if (len > opb.storage - Ogg.oggpack_bytes(ref opb)) { goto err_out; } vc.comment_lengths[i] = len; vc.user_comments[i] = new char[len + 1]; _v_readstring(ref opb, ref vc.user_comments[i], len); } /* EOP check */ if (Ogg.oggpack_read(ref opb, 1) != 1) { goto err_out; } return(0); err_out: vorbis_comment_clear(ref vc); return(OV_EBADHEADER); }
/* Header packing/unpacking */ static public int _vorbis_unpack_info(ref vorbis_info vi, ref Ogg.oggpack_buffer opb) { codec_setup_info ci = vi.codec_setup as codec_setup_info; if (ci == null) { return(OV_EFAULT); } vi.version = Ogg.oggpack_read(ref opb, 32); if (vi.version != 0) { return(OV_EVERSION); } vi.channels = Ogg.oggpack_read(ref opb, 8); vi.rate = Ogg.oggpack_read(ref opb, 32); vi.bitrate_upper = Ogg.oggpack_read(ref opb, 32); vi.bitrate_nominal = Ogg.oggpack_read(ref opb, 32); vi.bitrate_lower = Ogg.oggpack_read(ref opb, 32); ci.blocksizes[0] = 1 << Ogg.oggpack_read(ref opb, 4); ci.blocksizes[1] = 1 << Ogg.oggpack_read(ref opb, 4); if (vi.rate < 1) { goto err_out; } if (vi.channels < 1) { goto err_out; } if (ci.blocksizes[0] < 64) { goto err_out; } if (ci.blocksizes[1] < ci.blocksizes[0]) { goto err_out; } if (ci.blocksizes[1] > 8192) { goto err_out; } if (Ogg.oggpack_read(ref opb, 1) != 1) { goto err_out; /* EOP check */ } return(0); err_out: vorbis_info_clear(ref vi); return(OV_EBADHEADER); }
/* also responsible for range checking */ static vorbis_info_mapping mapping0_unpack(ref vorbis_info vi, ref Ogg.oggpack_buffer opb) { int i, b; vorbis_info_mapping _info = new vorbis_info_mapping0(); vorbis_info_mapping0 info = _info as vorbis_info_mapping0; codec_setup_info ci = vi.codec_setup as codec_setup_info; b = Ogg.oggpack_read(ref opb, 1); if (b < 0) { goto err_out; } if (b != 0) { info.submaps = Ogg.oggpack_read(ref opb, 4) + 1; if (info.submaps <= 0) { goto err_out; } } else { info.submaps = 1; } b = Ogg.oggpack_read(ref opb, 1); if (b < 0) { goto err_out; } if (b != 0) { info.coupling_steps = Ogg.oggpack_read(ref opb, 8) + 1; if (info.coupling_steps <= 0) { goto err_out; } for (i = 0; i < info.coupling_steps; i++) { int testM = info.coupling_mag[i] = Ogg.oggpack_read(ref opb, ilog((uint)vi.channels)); int testA = info.coupling_ang[i] = Ogg.oggpack_read(ref opb, ilog((uint)vi.channels)); if (testM < 0 || testA < 0 || testM == testA || testM >= vi.channels || testA >= vi.channels) { goto err_out; } } } if (Ogg.oggpack_read(ref opb, 2) != 0) /* 2,3:reserved */ { goto err_out; } if (info.submaps > 1) { for (i = 0; i < vi.channels; i++) { info.chmuxlist[i] = Ogg.oggpack_read(ref opb, 4); if (info.chmuxlist[i] >= info.submaps || info.chmuxlist[i] < 0) { goto err_out; } } } for (i = 0; i < info.submaps; i++) { Ogg.oggpack_read(ref opb, 8); /* time submap unused */ info.floorsubmap[i] = Ogg.oggpack_read(ref opb, 8); if (info.floorsubmap[i] >= ci.floors || info.floorsubmap[i] < 0) { goto err_out; } info.residuesubmap[i] = Ogg.oggpack_read(ref opb, 8); if (info.residuesubmap[i] >= ci.residues || info.residuesubmap[i] < 0) { goto err_out; } } return(info); err_out: mapping0_free_info(ref _info); return(null); }
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); } }