OSDN Git Service

#39823 improved gradient of wailing chip image
[dtxmania/dtxmania.git] / NVorbis / VorbisResidue.cs
1 /****************************************************************************
2  * NVorbis                                                                  *
3  * Copyright (C) 2014, Andrew Ward <afward@gmail.com>                       *
4  *                                                                          *
5  * See COPYING for license terms (Ms-PL).                                   *
6  *                                                                          *
7  ***************************************************************************/
8 using System;
9 using System.Linq;
10 using System.IO;
11
12 namespace NVorbis
13 {
14     abstract class VorbisResidue
15     {
16         internal static VorbisResidue Init(VorbisStreamDecoder vorbis, DataPacket packet)
17         {
18             var type = (int)packet.ReadBits(16);
19
20             VorbisResidue residue = null;
21             switch (type)
22             {
23                 case 0: residue = new Residue0(vorbis); break;
24                 case 1: residue = new Residue1(vorbis); break;
25                 case 2: residue = new Residue2(vorbis); break;
26             }
27             if (residue == null) throw new InvalidDataException();
28
29             residue.Init(packet);
30             return residue;
31         }
32
33         static int icount(int v)
34         {
35             var ret = 0;
36             while (v != 0)
37             {
38                 ret += (v & 1);
39                 v >>= 1;
40             }
41             return ret;
42         }
43
44         VorbisStreamDecoder _vorbis;
45         float[][] _residue;
46
47         protected VorbisResidue(VorbisStreamDecoder vorbis)
48         {
49             _vorbis = vorbis;
50
51             _residue = new float[_vorbis._channels][];
52             for (int i = 0; i < _vorbis._channels; i++)
53             {
54                 _residue[i] = new float[_vorbis.Block1Size];
55             }
56         }
57
58         protected float[][] GetResidueBuffer(int channels)
59         {
60             var temp = _residue;
61             if (channels < _vorbis._channels)
62             {
63                 temp = new float[channels][];
64                 Array.Copy(_residue, temp, channels);
65             }
66             for (int i = 0; i < channels; i++)
67             {
68                 Array.Clear(temp[i], 0, temp[i].Length);
69             }
70             return temp;
71         }
72
73         abstract internal float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize);
74
75         abstract protected void Init(DataPacket packet);
76
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
79         {
80             int _begin;
81             int _end;
82             int _partitionSize;
83             int _classifications;
84             int _maxStages;
85
86             VorbisCodebook[][] _books;
87             VorbisCodebook _classBook;
88
89             int[] _cascade, _entryCache;
90             int[][] _decodeMap;
91             int[][][] _partWordCache;
92
93             internal Residue0(VorbisStreamDecoder vorbis) : base(vorbis) { }
94
95             protected override void Init(DataPacket packet)
96             {
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)];
103
104                 _cascade = new int[_classifications];
105                 var acc = 0;
106                 for (int i = 0; i < _classifications; i++)
107                 {
108                     var low_bits = (int)packet.ReadBits(3);
109                     if (packet.ReadBit())
110                     {
111                         _cascade[i] = (int)packet.ReadBits(5) << 3 | low_bits;
112                     }
113                     else
114                     {
115                         _cascade[i] = low_bits;
116                     }
117                     acc += icount(_cascade[i]);
118                 }
119
120                 var bookNums = new int[acc];
121                 for (var i = 0; i < acc; i++)
122                 {
123                     bookNums[i] = (int)packet.ReadBits(8);
124                     if (_vorbis.Books[bookNums[i]].MapType == 0) throw new InvalidDataException();
125                 }
126
127                 var entries = _classBook.Entries;
128                 var dim = _classBook.Dimensions;
129                 var partvals = 1;
130                 while (dim > 0)
131                 {
132                     partvals *= _classifications;
133                     if (partvals > entries) throw new InvalidDataException();
134                     --dim;
135                 }
136
137                 // now the lookups
138                 dim = _classBook.Dimensions;
139
140                 _books = new VorbisCodebook[_classifications][];
141
142                 acc = 0;
143                 var maxstage = 0;
144                 int stages;
145                 for (int j = 0; j < _classifications; j++)
146                 {
147                     stages = Utils.ilog(_cascade[j]);
148                     _books[j] = new VorbisCodebook[stages];
149                     if (stages > 0)
150                     {
151                         maxstage = Math.Max(maxstage, stages);
152                         for (int k = 0; k < stages; k++)
153                         {
154                             if ((_cascade[j] & (1 << k)) > 0)
155                             {
156                                 _books[j][k] = _vorbis.Books[bookNums[acc++]];
157                             }
158                         }
159                     }
160                 }
161                 _maxStages = maxstage;
162
163                 _decodeMap = new int[partvals][];
164                 for (int j = 0; j < partvals; j++)
165                 {
166                     var val = j;
167                     var mult = partvals / _classifications;
168                     _decodeMap[j] = new int[_classBook.Dimensions];
169                     for (int k = 0; k < _classBook.Dimensions; k++)
170                     {
171                         var deco = val / mult;
172                         val -= deco * mult;
173                         mult /= _classifications;
174                         _decodeMap[j][k] = deco;
175                     }
176                 }
177
178                 _entryCache = new int[_partitionSize];
179
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++)
183                 {
184                     _partWordCache[ch] = new int[maxPartWords][];
185                 }
186             }
187
188             internal override float[][] Decode(DataPacket packet, bool[] doNotDecode, int channels, int blockSize)
189             {
190                 var residue = GetResidueBuffer(doNotDecode.Length);
191
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;
195
196                 if (n > 0 && doNotDecode.Contains(false))
197                 {
198                     var partVals = n / _partitionSize;
199                     
200                     var partWords = (partVals + _classBook.Dimensions - 1) / _classBook.Dimensions;
201                     for (int j = 0; j < channels; j++)
202                     {
203                         Array.Clear(_partWordCache[j], 0, partWords);
204                     }
205
206                     for (int s = 0; s < _maxStages; s++)
207                     {
208                         for (int i = 0, l = 0; i < partVals; l++)
209                         {
210                             if (s == 0)
211                             {
212                                 for (int j = 0; j < channels; j++)
213                                 {
214                                     var idx = _classBook.DecodeScalar(packet);
215                                     if (idx >= 0 && idx < _decodeMap.Length)
216                                     {
217                                         _partWordCache[j][l] = _decodeMap[idx];
218                                     }
219                                     else
220                                     {
221                                         i = partVals;
222                                         s = _maxStages;
223                                         break;
224                                     }
225                                 }
226                             }
227                             for (int k = 0; i < partVals && k < _classBook.Dimensions; k++, i++)
228                             {
229                                 var offset = _begin + i * _partitionSize;
230                                 for (int j = 0; j < channels; j++)
231                                 {
232                                     var idx = _partWordCache[j][l][k];
233                                     if ((_cascade[idx] & (1 << s)) != 0)
234                                     {
235                                         var book = _books[idx][s];
236                                         if (book != null)
237                                         {
238                                             if (WriteVectors(book, packet, residue, j, offset, _partitionSize))
239                                             {
240                                                 // bad packet...  exit now and try to use what we already have
241                                                 i = partVals;
242                                                 s = _maxStages;
243                                                 break;
244                                             }
245                                         }
246                                     }
247                                 }
248                             }
249                         }
250                     }
251                 }
252
253                 return residue;
254             }
255
256             virtual protected bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
257             {
258                 var res = residue[channel];
259                 var step = partitionSize / codebook.Dimensions;
260
261                 for (int i = 0; i < step; i++)
262                 {
263                     if ((_entryCache[i] = codebook.DecodeScalar(packet)) == -1)
264                     {
265                         return true;
266                     }
267                 }
268                 for (int i = 0; i < codebook.Dimensions; i++)
269                 {
270                     for (int j = 0; j < step; j++, offset++)
271                     {
272                         res[offset] += codebook[_entryCache[j], i];
273                     }
274                 }
275                 return false;
276             }
277         }
278
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
281         {
282             internal Residue1(VorbisStreamDecoder vorbis) : base(vorbis) { }
283
284             protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
285             {
286                 var res = residue[channel];
287
288                 for (int i = 0; i < partitionSize; )
289                 {
290                     var entry = codebook.DecodeScalar(packet);
291                     if (entry == -1)
292                     {
293                         return true;
294                     }
295                     for (int j = 0; j < codebook.Dimensions; i++, j++)
296                     {
297                         res[offset + i] += codebook[entry, j];
298                     }
299                 }
300
301                 return false;
302             }
303         }
304
305         // residue type 2... basically type 0, but samples are interleaved between channels (ch0, ch1, ch0, ch1, etc...)
306         class Residue2 : Residue0
307         {
308             int _channels;
309
310             internal Residue2(VorbisStreamDecoder vorbis) : base(vorbis) { }
311
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)
315             {
316                 _channels = channels;
317
318                 return base.Decode(packet, doNotDecode, 1, blockSize * channels);
319             }
320
321             protected override bool WriteVectors(VorbisCodebook codebook, DataPacket packet, float[][] residue, int channel, int offset, int partitionSize)
322             {
323                 var chPtr = 0;
324
325                 offset /= _channels;
326                 for (int c = 0; c < partitionSize; )
327                 {
328                     var entry = codebook.DecodeScalar(packet);
329                     if (entry == -1)
330                     {
331                         return true;
332                     }
333                     for (var d = 0; d < codebook.Dimensions; d++, c++)
334                     {
335                         residue[chPtr][offset] += codebook[entry, d];
336                         if (++chPtr == _channels)
337                         {
338                             chPtr = 0;
339                             offset++;
340                         }
341                     }
342                 }
343
344                 return false;
345             }
346         }
347     }
348 }