internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel) { var data = _reusablePacketData[channel]; data.BlockSize = blockSize; data.ForceEnergy = false; data.ForceNoEnergy = false; data.Amp = packet.ReadUBits(_ampBits); if (data.Amp > 0f) { // this is pretty well stolen directly from libvorbis... BSD license Array.Clear(data.Coeff, 0, data.Coeff.Length); data.Amp = data.Amp / _ampDiv * _ampOfs; uint bookNum = (uint)packet.ReadUBits(_bookBits); if (bookNum >= _books.Length) { // we ran out of data or the packet is corrupt... 0 the floor and return data.Amp = 0; return(data); } VorbisCodebook book = _books[bookNum]; // first, the book decode... for (int i = 0; i < _order;) { int entry = book.DecodeScalar(packet); if (entry == -1) { // we ran out of data or the packet is corrupt... 0 the floor and return data.Amp = 0; return(data); } for (int j = 0; i < _order && j < book.Dimensions; j++, i++) { data.Coeff[i] = book[entry, j]; } } // then, the "averaging" float last = 0f; for (int j = 0; j < _order;) { for (int k = 0; j < _order && k < book.Dimensions; j++, k++) { data.Coeff[j] += last; } last = data.Coeff[j - 1]; } } return(data); }
internal override PacketData UnpackPacket(DataPacket packet, int blockSize, int channel) { var data = _reusablePacketData[channel]; data.BlockSize = blockSize; data.ForceEnergy = false; data.ForceNoEnergy = false; data.PostCount = 0; Array.Clear(data.Posts, 0, 64); // hoist ReadPosts to here since that's all we're doing... if (packet.ReadBit()) { var postCount = 2; data.Posts[0] = (int)packet.ReadUBits(_yBits); data.Posts[1] = (int)packet.ReadUBits(_yBits); for (int i = 0; i < _partitionClass.Length; i++) { var clsNum = _partitionClass[i]; var cdim = _classDimensions[clsNum]; var cbits = _classSubclasses[clsNum]; var csub = (1 << cbits) - 1; var cval = 0U; if (cbits > 0) { if ((cval = (uint)_classMasterBooks[clsNum].DecodeScalar(packet)) == uint.MaxValue) { // we read a bad value... bail postCount = 0; break; } } for (int j = 0; j < cdim; j++) { var book = _subclassBooks[clsNum][cval & csub]; cval >>= cbits; if (book != null) { if ((data.Posts[postCount] = book.DecodeScalar(packet)) == -1) { // we read a bad value... bail postCount = 0; i = _partitionClass.Length; break; } } ++postCount; } } data.PostCount = postCount; } return(data); }
bool ProcessStreamHeader(DataPacket packet) { if (!CheckForHeader(packet, streamHeader)) { // don't mark the packet as done... it might be used elsewhere _glueBits += packet.Length * 8; return(false); } if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } _glueBits += 56; long startPos = packet.BitsRead; if (packet.ReadInt32() != 0) { throw new InvalidDataException("Only Vorbis stream version 0 is supported."); } _channels = packet.ReadByte(); _sampleRate = packet.ReadInt32(); _upperBitrate = packet.ReadInt32(); _nominalBitrate = packet.ReadInt32(); _lowerBitrate = packet.ReadInt32(); Block0Size = 1 << (int)packet.ReadUBits(4); Block1Size = 1 << (int)packet.ReadUBits(4); if (_nominalBitrate == 0) { if (_upperBitrate > 0 && _lowerBitrate > 0) { _nominalBitrate = (_upperBitrate + _lowerBitrate) / 2; } } _metaBits += packet.BitsRead - startPos + 8; _wasteHdrBits += 8 * packet.Length - packet.BitsRead; return(true); }
internal void Init(DataPacket packet) { // first, check the sync pattern ulong chkVal = packet.ReadUBits(24); if (chkVal != 0x564342UL) { throw new InvalidDataException(); } // get the counts Dimensions = (int)packet.ReadUBits(16); Entries = (int)packet.ReadUBits(24); // init the storage Lengths = new int[Entries]; InitTree(packet); InitLookupTable(packet); }
public static VorbisMode Init(VorbisStreamDecoder vorbis, DataPacket packet) { var mode = new VorbisMode(vorbis); mode.BlockFlag = packet.ReadBit(); mode.WindowType = (int)packet.ReadUBits(16); mode.TransformType = (int)packet.ReadUBits(16); var mapping = (int)packet.ReadUBits(8); if (mode.WindowType != 0 || mode.TransformType != 0 || mapping >= vorbis.Maps.Length) { throw new InvalidDataException(); } mode.Mapping = vorbis.Maps[mapping]; mode.BlockSize = mode.BlockFlag ? vorbis.Block1Size : vorbis.Block0Size; // now pre-calc the window(s)... if (mode.BlockFlag) { // long block mode._windows = new float[4][]; mode._windows[0] = new float[vorbis.Block1Size]; mode._windows[1] = new float[vorbis.Block1Size]; mode._windows[2] = new float[vorbis.Block1Size]; mode._windows[3] = new float[vorbis.Block1Size]; } else { // short block mode._windows = new float[1][]; mode._windows[0] = new float[vorbis.Block0Size]; } mode.CalcWindows(); return(mode); }
internal static VorbisTime Init(VorbisStreamDecoder vorbis, DataPacket packet) { var type = (int)packet.ReadUBits(16); VorbisTime time = null; switch (type) { case 0: time = new Time0(vorbis); break; } if (time == null) { throw new InvalidDataException(); } time.Init(packet); return(time); }
internal static VorbisMapping Create(VorbisStreamDecoder vorbis, DataPacket packet) { int type = (int)packet.ReadUBits(16); VorbisMapping mapping = null; switch (type) { case 0: mapping = new Mapping0(vorbis); break; } if (mapping == null) { throw new InvalidDataException(); } mapping.Init(packet); return(mapping); }
internal static VorbisResidue Init(VorbisStreamDecoder vorbis, DataPacket packet) { var type = (int)packet.ReadUBits(16); VorbisResidue residue = null; switch (type) { case 0: residue = new Residue0(vorbis); break; case 1: residue = new Residue1(vorbis); break; case 2: residue = new Residue2(vorbis); break; } if (residue == null) { throw new InvalidDataException(); } residue.Init(packet); return(residue); }
internal int GetPacketLength(DataPacket curPacket, DataPacket lastPacket) { // if we don't have a previous packet, or we're re-syncing, this packet has no audio data to return if (lastPacket == null || curPacket.IsResync) { return(0); } // make sure they are audio packets if (curPacket.ReadBit()) { return(0); } if (lastPacket.ReadBit()) { return(0); } // get the current packet's information int modeIndex = (int)curPacket.ReadUBits(_modeFieldBits); if (modeIndex < 0 || modeIndex >= Modes.Length) { return(0); } var mode = Modes[modeIndex]; // get the last packet's information modeIndex = (int)lastPacket.ReadUBits(_modeFieldBits); if (modeIndex < 0 || modeIndex >= Modes.Length) { return(0); } // now calculate the totals... var prevMode = Modes[modeIndex]; return(mode.BlockSize / 4 + prevMode.BlockSize / 4); }
internal static VorbisFloor Create(VorbisStreamDecoder vorbis, DataPacket packet) { int type = (int)packet.ReadUBits(16); VorbisFloor floor = null; switch (type) { case 0: floor = new Floor0(vorbis); break; case 1: floor = new Floor1(vorbis); break; } if (floor == null) { throw new InvalidDataException(); } floor.Init(packet); return(floor); }
bool UnpackPacket(DataPacket packet) { // make sure we're on an audio packet if (packet.ReadBit()) { // we really can't do anything... count the bits as waste return(false); } // get mode and prev/next flags var modeBits = _modeFieldBits; _mode = Modes[(int)packet.ReadUBits(_modeFieldBits)]; if (_mode.BlockFlag) { _prevFlag = packet.ReadBit(); _nextFlag = packet.ReadBit(); modeBits += 2; } else { _prevFlag = _nextFlag = false; } if (packet.IsShort) { return(false); } var startBits = packet.BitsRead; var halfBlockSize = _mode.BlockSize / 2; // read the noise floor data (but don't decode yet) for (int i = 0; i < _channels; i++) { _floorData[i] = _mode.Mapping.ChannelSubmap[i].Floor.UnpackPacket(packet, _mode.BlockSize, i); _noExecuteChannel[i] = !_floorData[i].ExecuteChannel; // go ahead and clear the residue buffers Array.Clear(_residue[i], 0, halfBlockSize); } // make sure we handle no-energy channels correctly given the couplings... foreach (var step in _mode.Mapping.CouplingSteps) { if (_floorData[step.Angle].ExecuteChannel || _floorData[step.Magnitude].ExecuteChannel) { _floorData[step.Angle].ForceEnergy = true; _floorData[step.Magnitude].ForceEnergy = true; } } var floorBits = packet.BitsRead - startBits; startBits = packet.BitsRead; foreach (var subMap in _mode.Mapping.Submaps) { for (int j = 0; j < _channels; j++) { if (_mode.Mapping.ChannelSubmap[j] != subMap) { _floorData[j].ForceNoEnergy = true; } } float[][] rTemp = subMap.Residue.Decode(packet, _noExecuteChannel, _channels, _mode.BlockSize); for (int c = 0; c < _channels; c++) { var r = _residue[c]; var rt = rTemp[c]; for (int i = 0; i < halfBlockSize; i++) { r[i] += rt[i]; } } } _glueBits += 1; _modeBits += modeBits; _floorBits += floorBits; _resBits += packet.BitsRead - startBits; _wasteBits += 8 * packet.Length - packet.BitsRead; _packetCount += 1; return(true); }
void InitLookupTable(DataPacket packet) { MapType = (int)packet.ReadUBits(4); if (MapType == 0) { return; } float minValue = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32()); float deltaValue = Utils.ConvertFromVorbisFloat32(packet.ReadUInt32()); int valueBits = (int)packet.ReadUBits(4) + 1; bool sequence_p = packet.ReadBit(); int lookupValueCount = Entries * Dimensions; LookupTable = new float[lookupValueCount]; if (MapType == 1) { lookupValueCount = Lookup1_values(); } Span <uint> multiplicands = stackalloc uint[lookupValueCount]; for (var i = 0; i < lookupValueCount; i++) { multiplicands[i] = (uint)packet.ReadUBits(valueBits); } // now that we have the initial data read in, calculate the entry tree if (MapType == 1) { for (int idx = 0; idx < Entries; idx++) { double last = 0.0; int idxDiv = 1; for (var i = 0; i < Dimensions; i++) { int moff = idx / idxDiv % lookupValueCount; double value = multiplicands[moff] * deltaValue + minValue + last; LookupTable[idx * Dimensions + i] = (float)value; if (sequence_p) { last = value; } idxDiv *= lookupValueCount; } } } else { for (int idx = 0; idx < Entries; idx++) { double last = 0.0; int moff = idx * Dimensions; for (var i = 0; i < Dimensions; i++) { double value = multiplicands[moff] * deltaValue + minValue + last; LookupTable[idx * Dimensions + i] = (float)value; if (sequence_p) { last = value; } moff++; } } } }
bool LoadBooks(DataPacket packet) { if (!CheckForHeader(packet, bookHeader)) { return(false); } if (!_pagesSeen.Contains(_lastPageSeen = packet.PageSequenceNumber)) { _pagesSeen.Add(_lastPageSeen); } var bits = packet.BitsRead; _glueBits += packet.BitsRead; // get books Books = new VorbisCodebook[packet.ReadByte() + 1]; for (int i = 0; i < Books.Length; i++) { Books[i] = VorbisCodebook.Create(this, packet, i); } _bookBits += packet.BitsRead - bits; bits = packet.BitsRead; // get times Times = new VorbisTime[(int)packet.ReadUBits(6) + 1]; for (int i = 0; i < Times.Length; i++) { Times[i] = VorbisTime.Init(this, packet); } _timeHdrBits += packet.BitsRead - bits; bits = packet.BitsRead; // get floor Floors = new VorbisFloor[(int)packet.ReadUBits(6) + 1]; for (int i = 0; i < Floors.Length; i++) { Floors[i] = VorbisFloor.Create(this, packet); } _floorHdrBits += packet.BitsRead - bits; bits = packet.BitsRead; // get residue Residues = new VorbisResidue[(int)packet.ReadUBits(6) + 1]; for (int i = 0; i < Residues.Length; i++) { Residues[i] = VorbisResidue.Init(this, packet); } _resHdrBits += packet.BitsRead - bits; bits = packet.BitsRead; // get map Maps = new VorbisMapping[(int)packet.ReadUBits(6) + 1]; for (int i = 0; i < Maps.Length; i++) { Maps[i] = VorbisMapping.Create(this, packet); } _mapHdrBits += packet.BitsRead - bits; bits = packet.BitsRead; // get mode settings Modes = new VorbisMode[(int)packet.ReadUBits(6) + 1]; for (int i = 0; i < Modes.Length; i++) { Modes[i] = VorbisMode.Init(this, packet); } _modeHdrBits += packet.BitsRead - bits; // check the framing bit if (!packet.ReadBit()) { throw new InvalidDataException(); } ++_glueBits; _wasteHdrBits += 8 * packet.Length - packet.BitsRead; _modeFieldBits = Utils.ILog(Modes.Length - 1); return(true); }
protected override void Init(DataPacket packet) { // this is pretty well stolen directly from libvorbis... BSD license _order = (int)packet.ReadUBits(8); _rate = (int)packet.ReadUBits(16); _bark_map_size = (int)packet.ReadUBits(16); _ampBits = (int)packet.ReadUBits(6); _ampOfs = (int)packet.ReadUBits(8); _books = new VorbisCodebook[(int)packet.ReadUBits(4) + 1]; if (_order < 1 || _rate < 1 || _bark_map_size < 1 || _books.Length == 0) { throw new InvalidDataException(); } _ampDiv = (1 << _ampBits) - 1; for (int i = 0; i < _books.Length; i++) { int num = (int)packet.ReadUBits(8); if (num < 0 || num >= _vorbis.Books.Length) { throw new InvalidDataException(); } VorbisCodebook book = _vorbis.Books[num]; if (book.MapType == 0 || book.Dimensions < 1) { throw new InvalidDataException(); } _books[i] = book; } _bookBits = Utils.ILog(_books.Length); _barkMaps = new Dictionary <int, int[]>(); _barkMaps[_vorbis.Block0Size] = SynthesizeBarkCurve(_vorbis.Block0Size / 2); _barkMaps[_vorbis.Block1Size] = SynthesizeBarkCurve(_vorbis.Block1Size / 2); _wMap = new Dictionary <int, float[]>(); _wMap[_vorbis.Block0Size] = SynthesizeWDelMap(_vorbis.Block0Size / 2); _wMap[_vorbis.Block1Size] = SynthesizeWDelMap(_vorbis.Block1Size / 2); _reusablePacketData = new PacketData0[_vorbis._channels]; for (int i = 0; i < _reusablePacketData.Length; i++) { _reusablePacketData[i] = new PacketData0() { Coeff = new float[_order + 1] } } ; } int[] SynthesizeBarkCurve(int n) { float scale = _bark_map_size / ToBARK(_rate / 2); int[] map = new int[n + 1]; for (int i = 0; i < n - 1; i++) { map[i] = Math.Min(_bark_map_size - 1, (int)MathF.Floor(ToBARK(_rate / 2f / n * i) * scale)); } map[n] = -1; return(map); }
void InitTree(DataPacket packet) { bool sparse; int total = 0; if (packet.ReadBit()) { // ordered var len = (int)packet.ReadUBits(5) + 1; for (var i = 0; i < Entries;) { int cnt = (int)packet.ReadUBits(Utils.ILog(Entries - i)); while (--cnt >= 0) { Lengths[i++] = len; } len++; } total = 0; sparse = false; } else { // unordered sparse = packet.ReadBit(); for (var i = 0; i < Entries; i++) { if (!sparse || packet.ReadBit()) { Lengths[i] = (int)packet.ReadUBits(5) + 1; total++; } else { // mark the entry as unused Lengths[i] = -1; } } } // figure out the maximum bit size; if all are unused, don't do anything else if ((MaxBits = Lengths.Max()) > -1) { Span <int> codewordLengths = stackalloc int[0]; if (sparse && total >= Entries >> 2) { codewordLengths = stackalloc int[Entries]; for (int i = 0; i < Entries; i++) { codewordLengths[i] = Lengths[i]; } sparse = false; } // compute size of sorted tables int sortedEntries = sparse ? total : 0; Span <int> values = stackalloc int[0]; Span <int> codewords = stackalloc int[0]; if (!sparse) { codewords = stackalloc int[Entries]; } else if (sortedEntries != 0) { codewordLengths = stackalloc int[sortedEntries]; codewords = stackalloc int[sortedEntries]; values = stackalloc int[sortedEntries]; } if (!ComputeCodewords(sparse, sortedEntries, codewords, codewordLengths, Lengths, Entries, values)) { throw new InvalidDataException(); } Span <int> valueList = stackalloc int[codewords.Length]; if (values.Length != 0) { valueList = values; } else { for (int i = 0; i < codewords.Length; i++) { valueList[i] = i; } } Span <int> lengthList = codewordLengths.Length > 0 ? codewordLengths : Lengths.AsSpan(); PrefixList = Huffman.BuildPrefixedLinkedList( valueList, lengthList, codewords, out PrefixBitLength, out PrefixOverflowTree); } }
protected override void Init(DataPacket packet) { _partitionClass = new int[(int)packet.ReadUBits(5)]; for (int i = 0; i < _partitionClass.Length; i++) { _partitionClass[i] = (int)packet.ReadUBits(4); } int maximum_class = _partitionClass.Max(); _classDimensions = new int[maximum_class + 1]; _classSubclasses = new int[maximum_class + 1]; _classMasterBooks = new VorbisCodebook[maximum_class + 1]; _classMasterBookIndex = new int[maximum_class + 1]; _subclassBooks = new VorbisCodebook[maximum_class + 1][]; _subclassBookIndex = new int[maximum_class + 1][]; for (int i = 0; i <= maximum_class; i++) { _classDimensions[i] = (int)packet.ReadUBits(3) + 1; _classSubclasses[i] = (int)packet.ReadUBits(2); if (_classSubclasses[i] > 0) { _classMasterBookIndex[i] = (int)packet.ReadUBits(8); _classMasterBooks[i] = _vorbis.Books[_classMasterBookIndex[i]]; } _subclassBooks[i] = new VorbisCodebook[1 << _classSubclasses[i]]; _subclassBookIndex[i] = new int[_subclassBooks[i].Length]; for (int j = 0; j < _subclassBooks[i].Length; j++) { int bookNum = (int)packet.ReadUBits(8) - 1; if (bookNum >= 0) { _subclassBooks[i][j] = _vorbis.Books[bookNum]; } _subclassBookIndex[i][j] = bookNum; } } _multiplier = (int)packet.ReadUBits(2); _range = _rangeLookup[_multiplier]; _yBits = _yBitsLookup[_multiplier]; _multiplier++; int rangeBits = (int)packet.ReadUBits(4); int xListIndex = 0; int xListSize = 2; // we always add at least 2 elements for (int i = 0; i < _partitionClass.Length; i++) // precalc size of xList { int classNum = _partitionClass[i]; int dim = _classDimensions[classNum]; xListSize += dim; } _xList = new int[xListSize]; _xList[xListIndex++] = 0; _xList[xListIndex++] = 1 << rangeBits; for (int i = 0; i < _partitionClass.Length; i++) { int classNum = _partitionClass[i]; int dim = _classDimensions[classNum]; for (int j = 0; j < dim; j++) { _xList[xListIndex++] = (int)packet.ReadUBits(rangeBits); } } // precalc the low and high neighbors (and init the sort table) _lNeigh = new int[_xList.Length]; _hNeigh = new int[_xList.Length]; _sortIdx = new int[_xList.Length]; _sortIdx[0] = 0; _sortIdx[1] = 1; for (int i = 2; i < _lNeigh.Length; i++) { _lNeigh[i] = 0; _hNeigh[i] = 1; _sortIdx[i] = i; for (int j = 2; j < i; j++) { int tmp = _xList[j]; if (tmp < _xList[i]) { if (tmp > _xList[_lNeigh[i]]) { _lNeigh[i] = j; } } else { if (tmp < _xList[_hNeigh[i]]) { _hNeigh[i] = j; } } } } // precalc the sort table for (int i = 0; i < _sortIdx.Length - 1; i++) { for (int j = i + 1; j < _sortIdx.Length; j++) { if (_xList[i] == _xList[j]) { throw new InvalidDataException(); } if (_xList[_sortIdx[i]] > _xList[_sortIdx[j]]) { // swap the sort indexes int tmp = _sortIdx[i]; _sortIdx[i] = _sortIdx[j]; _sortIdx[j] = tmp; } } } // pre-create our packet data instances _reusablePacketData = new PacketData1[_vorbis._channels]; for (int i = 0; i < _reusablePacketData.Length; i++) { _reusablePacketData[i] = new PacketData1(); } }
protected override void Init(DataPacket packet) { // this is pretty well stolen directly from libvorbis... BSD license _begin = (int)packet.ReadUBits(24); _end = (int)packet.ReadUBits(24); _partitionSize = (int)packet.ReadUBits(24) + 1; _classifications = (int)packet.ReadUBits(6) + 1; _classBook = _vorbis.Books[(int)packet.ReadUBits(8)]; _cascade = new int[_classifications]; int acc = 0; for (int i = 0; i < _classifications; i++) { var low_bits = (int)packet.ReadUBits(3); if (packet.ReadBit()) { _cascade[i] = (int)packet.ReadUBits(5) << 3 | low_bits; } else { _cascade[i] = low_bits; } acc += ICount(_cascade[i]); } int[] bookNums = new int[acc]; for (var i = 0; i < acc; i++) { bookNums[i] = (int)packet.ReadUBits(8); if (_vorbis.Books[bookNums[i]].MapType == 0) { throw new InvalidDataException(); } } int entries = _classBook.Entries; int dim = _classBook.Dimensions; int partvals = 1; while (dim > 0) { partvals *= _classifications; if (partvals > entries) { throw new InvalidDataException(); } --dim; } // now the lookups _ = _classBook.Dimensions; _books = new VorbisCodebook[_classifications][]; acc = 0; var maxstage = 0; int stages; for (int j = 0; j < _classifications; j++) { stages = Utils.ILog(_cascade[j]); _books[j] = new VorbisCodebook[stages]; if (stages > 0) { maxstage = Math.Max(maxstage, stages); for (int k = 0; k < stages; k++) { if ((_cascade[j] & (1 << k)) > 0) { _books[j][k] = _vorbis.Books[bookNums[acc++]]; } } } } _maxStages = maxstage; _decodeMap = new int[partvals][]; for (int j = 0; j < partvals; j++) { var val = j; var mult = partvals / _classifications; _decodeMap[j] = new int[_classBook.Dimensions]; for (int k = 0; k < _classBook.Dimensions; k++) { var deco = val / mult; val -= deco * mult; mult /= _classifications; _decodeMap[j][k] = deco; } } _entryCache = new int[_partitionSize]; _partWordCache = new int[_vorbis._channels][][]; var maxPartWords = ((_end - _begin) / _partitionSize + _classBook.Dimensions - 1) / _classBook.Dimensions; for (int ch = 0; ch < _vorbis._channels; ch++) { _partWordCache[ch] = new int[maxPartWords][]; } }
protected override void Init(DataPacket packet) { var submapCount = 1; if (packet.ReadBit()) { submapCount += (int)packet.ReadUBits(4); } // square polar mapping var couplingSteps = 0; if (packet.ReadBit()) { couplingSteps = (int)packet.ReadUBits(8) + 1; } var couplingBits = Utils.ILog(_vorbis._channels - 1); CouplingSteps = new CouplingStep[couplingSteps]; for (int j = 0; j < couplingSteps; j++) { var magnitude = (int)packet.ReadUBits(couplingBits); var angle = (int)packet.ReadUBits(couplingBits); if (magnitude == angle || magnitude > _vorbis._channels - 1 || angle > _vorbis._channels - 1) { throw new InvalidDataException(); } CouplingSteps[j] = new CouplingStep { Angle = angle, Magnitude = magnitude }; } // reserved bits if (packet.ReadUBits(2) != 0UL) { throw new InvalidDataException(); } // channel multiplex var mux = new int[_vorbis._channels]; if (submapCount > 1) { for (int c = 0; c < ChannelSubmap.Length; c++) { mux[c] = (int)packet.ReadUBits(4); if (mux[c] >= submapCount) { throw new InvalidDataException(); } } } // submaps Submaps = new Submap[submapCount]; for (int j = 0; j < submapCount; j++) { packet.ReadUBits(8); // unused placeholder var floorNum = (int)packet.ReadUBits(8); if (floorNum >= _vorbis.Floors.Length) { throw new InvalidDataException(); } var residueNum = (int)packet.ReadUBits(8); if (residueNum >= _vorbis.Residues.Length) { throw new InvalidDataException(); } Submaps[j] = new Submap { Floor = _vorbis.Floors[floorNum], Residue = _vorbis.Residues[floorNum] }; } ChannelSubmap = new Submap[_vorbis._channels]; for (int c = 0; c < ChannelSubmap.Length; c++) { ChannelSubmap[c] = Submaps[mux[c]]; } }