1 /****************************************************************************
3 * Copyright (C) 2014, Andrew Ward <afward@gmail.com> *
5 * See COPYING for license terms (Ms-PL). *
7 ***************************************************************************/
14 abstract class VorbisResidue
16 internal static VorbisResidue Init(VorbisStreamDecoder vorbis, DataPacket packet)
18 var type = (int)packet.ReadBits(16);
20 VorbisResidue residue = null;
23 case 0: residue = new Residue0(vorbis); break;
24 case 1: residue = new Residue1(vorbis); break;
25 case 2: residue = new Residue2(vorbis); break;
27 if (residue == null) throw new InvalidDataException();
33 static int icount(int v)
44 VorbisStreamDecoder _vorbis;
47 protected VorbisResidue(VorbisStreamDecoder vorbis)
51 _residue = new float[_vorbis._channels][];
52 for (int i = 0; i < _vorbis._channels; i++)
54 _residue[i] = new float[_vorbis.Block1Size];
58 protected float[][] GetResidueBuffer(int channels)
61 if (channels < _vorbis._channels)
63 temp = new float[channels][];
64 Array.Copy(_residue, temp, channels);
66 for (int i = 0; i < channels; i++)
68 Array.Clear(temp[i], 0, temp[i].Length);
73 abstract internal float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize);
75 abstract protected void Init(DataPacket packet);
77 // residue type 0... samples are grouped by channel, then stored with non-interleaved dimensions (d0, d0, d0, d0, ..., d1, d1, d1, d1, ..., d2, d2, d2, d2, etc...)
78 class Residue0 : VorbisResidue
86 VorbisCodebook[][] _books;
87 VorbisCodebook _classBook;
89 int[] _cascade, _entryCache;
91 int[][][] _partWordCache;
93 internal Residue0(VorbisStreamDecoder vorbis) : base(vorbis) { }
95 protected override void Init(DataPacket packet)
97 // this is pretty well stolen directly from libvorbis... BSD license
98 _begin = (int)packet.ReadBits(24);
99 _end = (int)packet.ReadBits(24);
100 _partitionSize = (int)packet.ReadBits(24) + 1;
101 _classifications = (int)packet.ReadBits(6) + 1;
102 _classBook = _vorbis.Books[(int)packet.ReadBits(8)];
104 _cascade = new int[_classifications];
106 for (int i = 0; i < _classifications; i++)
108 var low_bits = (int)packet.ReadBits(3);
109 if (packet.ReadBit())
111 _cascade[i] = (int)packet.ReadBits(5) << 3 | low_bits;
115 _cascade[i] = low_bits;
117 acc += icount(_cascade[i]);
120 var bookNums = new int[acc];
121 for (var i = 0; i < acc; i++)
123 bookNums[i] = (int)packet.ReadBits(8);
124 if (_vorbis.Books[bookNums[i]].MapType == 0) throw new InvalidDataException();
127 var entries = _classBook.Entries;
128 var dim = _classBook.Dimensions;
132 partvals *= _classifications;
133 if (partvals > entries) throw new InvalidDataException();
138 dim = _classBook.Dimensions;
140 _books = new VorbisCodebook[_classifications][];
145 for (int j = 0; j < _classifications; j++)
147 stages = Utils.ilog(_cascade[j]);
148 _books[j] = new VorbisCodebook[stages];
151 maxstage = Math.Max(maxstage, stages);
152 for (int k = 0; k < stages; k++)
154 if ((_cascade[j] & (1 << k)) > 0)
156 _books[j][k] = _vorbis.Books[bookNums[acc++]];
161 _maxStages = maxstage;
163 _decodeMap = new int[partvals][];
164 for (int j = 0; j < partvals; j++)
167 var mult = partvals / _classifications;
168 _decodeMap[j] = new int[_classBook.Dimensions];
169 for (int k = 0; k < _classBook.Dimensions; k++)
171 var deco = val / mult;
173 mult /= _classifications;
174 _decodeMap[j][k] = deco;
178 _entryCache = new int[_partitionSize];
180 _partWordCache = new int[_vorbis._channels][][];
181 var maxPartWords = ((_end - _begin) / _partitionSize + _classBook.Dimensions - 1) / _classBook.Dimensions;
182 for (int ch = 0; ch < _vorbis._channels; ch++)
184 _partWordCache[ch] = new int[maxPartWords][];
188 internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize)
190 var residue = GetResidueBuffer(doNotDecode.Length);
192 // this is pretty well stolen directly from libvorbis... BSD license
193 var end = _end < blockSize / 2 ? _end : blockSize / 2;
194 var n = end - _begin;
196 if (n > 0 && doNotDecode.Contains(false))
198 var partVals = n / _partitionSize;
200 var partWords = (partVals + _classBook.Dimensions - 1) / _classBook.Dimensions;
201 for (int j = 0; j < channels; j++)
203 Array.Clear(_partWordCache[j], 0, partWords);
206 for (int s = 0; s < _maxStages; s++)
208 for (int i = 0, l = 0; i < partVals; l++)
212 for (int j = 0; j < channels; j++)
214 var idx = _classBook.DecodeScalar(packet);
215 if (idx >= 0 && idx < _decodeMap.Length)
217 _partWordCache[j][l] = _decodeMap[idx];
227 for (int k = 0; i < partVals && k < _classBook.Dimensions; k++, i++)
229 var offset = _begin + i * _partitionSize;
230 for (int j = 0; j < channels; j++)
232 var idx = _partWordCache[j][l][k];
233 if ((_cascade[idx] & (1 << s)) != 0)
235 var book = _books[idx][s];
238 if (WriteVectors(book, packet, residue, j, offset, _partitionSize))
240 // bad packet... exit now and try to use what we already have
256 virtual protected bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
258 var res = residue[channel];
259 var step = partitionSize / codebook.Dimensions;
261 for (int i = 0; i < step; i++)
263 if ((_entryCache[i] = codebook.DecodeScalar(packet)) == -1)
268 for (int i = 0; i < codebook.Dimensions; i++)
270 for (int j = 0; j < step; j++, offset++)
272 res[offset] += codebook[_entryCache[j], i];
279 // residue type 1... samples are grouped by channel, then stored with interleaved dimensions (d0, d1, d2, d0, d1, d2, etc...)
280 class Residue1 : Residue0
282 internal Residue1(VorbisStreamDecoder vorbis) : base(vorbis) { }
284 protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
286 var res = residue[channel];
288 for (int i = 0; i < partitionSize; )
290 var entry = codebook.DecodeScalar(packet);
295 for (int j = 0; j < codebook.Dimensions; i++, j++)
297 res[offset + i] += codebook[entry, j];
305 // residue type 2... basically type 0, but samples are interleaved between channels (ch0, ch1, ch0, ch1, etc...)
306 class Residue2 : Residue0
310 internal Residue2(VorbisStreamDecoder vorbis) : base(vorbis) { }
312 // We can use the type 0 logic by saying we're doing a single channel buffer big enough to hold the samples for all channels
313 // This works because WriteVectors(...) "knows" the correct channel count and processes the data accordingly.
314 internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize)
316 _channels = channels;
318 return base.Decode(packet, doNotDecode, 1, blockSize * channels);
321 protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
326 for (int c = 0; c < partitionSize; )
328 var entry = codebook.DecodeScalar(packet);
333 for (var d = 0; d < codebook.Dimensions; d++, c++)
335 residue[chPtr][offset] += codebook[entry, d];
336 if (++chPtr == _channels)