@modplayjs/stb-vorbis 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/dist/codebook.d.ts +19 -0
- package/dist/codebook.d.ts.map +1 -0
- package/dist/codebook.js +332 -0
- package/dist/codebook.js.map +1 -0
- package/dist/crc32.d.ts +4 -0
- package/dist/crc32.d.ts.map +1 -0
- package/dist/crc32.js +22 -0
- package/dist/crc32.js.map +1 -0
- package/dist/imdct.d.ts +9 -0
- package/dist/imdct.d.ts.map +1 -0
- package/dist/imdct.js +197 -0
- package/dist/imdct.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/mdct.d.ts +3 -0
- package/dist/mdct.d.ts.map +1 -0
- package/dist/mdct.js +185 -0
- package/dist/mdct.js.map +1 -0
- package/dist/residue.d.ts +3 -0
- package/dist/residue.d.ts.map +1 -0
- package/dist/residue.js +180 -0
- package/dist/residue.js.map +1 -0
- package/dist/stream.d.ts +26 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +233 -0
- package/dist/stream.js.map +1 -0
- package/dist/tables.d.ts +2 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +4 -0
- package/dist/tables.js.map +1 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/dist/vorbis.d.ts +12 -0
- package/dist/vorbis.d.ts.map +1 -0
- package/dist/vorbis.js +1053 -0
- package/dist/vorbis.js.map +1 -0
- package/package.json +51 -4
package/dist/vorbis.js
ADDED
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
// Ported from stb_vorbis.c — decoder core: setup header parsing, packet
|
|
3
|
+
// decode (floors/residue/mapping/coupling/MDCT), frame finishing.
|
|
4
|
+
// Memory-source pull API (stb_vorbis_open_memory + get_frame_float).
|
|
5
|
+
import { NO_CODE, FAST_HUFFMAN_TABLE_SIZE, STB_VORBIS_FAST_HUFFMAN_LENGTH, } from './types.js';
|
|
6
|
+
import { get8, get32, getn, skip, startPage, startPacket, maybeStartPacket, nextSegment, get8Packet, get32Packet, flushPacket, prepHuffman, getBits, error, setFileOffset, getFileOffset, EOP, INVALID_BITS, } from './stream.js';
|
|
7
|
+
import { ilog, float32Unpack, lookup1Values, computeCodewords, computeAcceleratedHuffman, computeSortedHuffman, bitReverse, decodeRawShared, } from './codebook.js';
|
|
8
|
+
import { decodeResidue } from './residue.js';
|
|
9
|
+
import { inverseMdct } from './mdct.js';
|
|
10
|
+
import { computeTwiddleFactors, computeWindow, computeBitReverse, } from './imdct.js';
|
|
11
|
+
import { crc32Init } from './crc32.js';
|
|
12
|
+
import { INVERSE_DB_TABLE } from './tables.js';
|
|
13
|
+
const PAGEFLAG_first_page = 2;
|
|
14
|
+
const PAGEFLAG_last_page = 4;
|
|
15
|
+
const PAGEFLAG_continued_packet = 1;
|
|
16
|
+
export function vorbisValidate(data) {
|
|
17
|
+
return (data[0] === 0x76 && data[1] === 0x6f && data[2] === 0x72 &&
|
|
18
|
+
data[3] === 0x62 && data[4] === 0x69 && data[5] === 0x73);
|
|
19
|
+
}
|
|
20
|
+
/** draw_line (stb_vorbis.c:2043-2091) — LINE_OP(a,b) = a = b (NO_DEFER_FLOOR off). */
|
|
21
|
+
function drawLine(output, x0, y0, x10, y1, n) {
|
|
22
|
+
const dy = y1 - y0;
|
|
23
|
+
const adx = x10 - x0;
|
|
24
|
+
const ady = Math.abs(dy);
|
|
25
|
+
let x = x0, y = y0;
|
|
26
|
+
let err = 0;
|
|
27
|
+
const base = Math.trunc(dy / adx);
|
|
28
|
+
const sy = dy < 0 ? base - 1 : base + 1;
|
|
29
|
+
const ady2 = ady - Math.abs(base) * adx;
|
|
30
|
+
let x1 = x10;
|
|
31
|
+
if (x1 > n)
|
|
32
|
+
x1 = n;
|
|
33
|
+
if (x < x1) {
|
|
34
|
+
// LINE_OP(a,b) = a *= b (stb_vorbis.c:2032, deferred-floor flow):
|
|
35
|
+
// the floor multiplies the decoded residue.
|
|
36
|
+
output[x] = (output[x] ?? 0) * INVERSE_DB_TABLE[y & 255];
|
|
37
|
+
for (++x; x < x1; ++x) {
|
|
38
|
+
err += ady2;
|
|
39
|
+
if (err >= adx) {
|
|
40
|
+
err -= adx;
|
|
41
|
+
y += sy;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
y += base;
|
|
45
|
+
}
|
|
46
|
+
output[x] = (output[x] ?? 0) * INVERSE_DB_TABLE[y & 255];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function predictPoint(x, x0, x1, y0, y1) {
|
|
51
|
+
const dy = y1 - y0;
|
|
52
|
+
const adx = x1 - x0;
|
|
53
|
+
const err = Math.abs(dy) * (x - x0);
|
|
54
|
+
let off = 0;
|
|
55
|
+
if (err >= 0)
|
|
56
|
+
off = Math.floor(err / adx);
|
|
57
|
+
else
|
|
58
|
+
off = -Math.floor(-err / adx);
|
|
59
|
+
return dy >= 0 ? y0 + off : y0 - off;
|
|
60
|
+
}
|
|
61
|
+
function neighborsOf(x, n) {
|
|
62
|
+
// C neighbors() (stb_vorbis.c:1958-1969): the low/high LOCALS hold X
|
|
63
|
+
// coordinates; the returned *plow/*phigh are the INDICES of those
|
|
64
|
+
// neighbors.
|
|
65
|
+
let low = -1, lowI = -1;
|
|
66
|
+
let high = 65536, highI = -1;
|
|
67
|
+
for (let i = 0; i < n; ++i) {
|
|
68
|
+
const xi = x[i] ?? 0;
|
|
69
|
+
if (xi > low && xi < (x[n] ?? 0)) {
|
|
70
|
+
low = xi;
|
|
71
|
+
lowI = i;
|
|
72
|
+
}
|
|
73
|
+
if (xi < high && xi > (x[n] ?? 0)) {
|
|
74
|
+
high = xi;
|
|
75
|
+
highI = i;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [lowI, highI];
|
|
79
|
+
}
|
|
80
|
+
function computeBlocksize(f, b, n) {
|
|
81
|
+
const n2 = n >> 1, n4 = n >> 2, n8 = n >> 3;
|
|
82
|
+
f.A[b] = new Float32Array(n2);
|
|
83
|
+
f.B[b] = new Float32Array(n2);
|
|
84
|
+
f.C[b] = new Float32Array(n4);
|
|
85
|
+
computeTwiddleFactorsInto(n, f.A[b], f.B[b], f.C[b]);
|
|
86
|
+
f.window[b] = new Float32Array(n2);
|
|
87
|
+
computeWindow(n, f.window[b]);
|
|
88
|
+
f.bitReverse[b] = new Uint16Array(n8);
|
|
89
|
+
computeBitReverse(n, f.bitReverse[b]);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
function computeTwiddleFactorsInto(n, A, B, C) {
|
|
93
|
+
computeTwiddleFactors(n, A, B, C);
|
|
94
|
+
}
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Setup header (start_decoder, stb_vorbis.c:3589-4213)
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
function startDecoder(f) {
|
|
99
|
+
let maxSubmaps = 0;
|
|
100
|
+
let longestFloorlist = 0;
|
|
101
|
+
f.firstDecode = true;
|
|
102
|
+
f.nextSeg = -1; // no mid-packet start yet
|
|
103
|
+
if (!startPage(f))
|
|
104
|
+
return false;
|
|
105
|
+
if (!(f.pageFlag & PAGEFLAG_first_page))
|
|
106
|
+
return error(f, 4);
|
|
107
|
+
if (f.pageFlag & PAGEFLAG_last_page)
|
|
108
|
+
return error(f, 4);
|
|
109
|
+
if (f.pageFlag & PAGEFLAG_continued_packet)
|
|
110
|
+
return error(f, 4);
|
|
111
|
+
if (f.segmentCount !== 1)
|
|
112
|
+
return error(f, 4);
|
|
113
|
+
if (f.segments[0] !== 30)
|
|
114
|
+
return error(f, 4);
|
|
115
|
+
// id packet
|
|
116
|
+
if (get8(f) !== 1)
|
|
117
|
+
return error(f, 4);
|
|
118
|
+
const header = new Uint8Array(6);
|
|
119
|
+
if (!getn(f, header, 6))
|
|
120
|
+
return error(f, 10);
|
|
121
|
+
if (!vorbisValidate(header))
|
|
122
|
+
return error(f, 4);
|
|
123
|
+
if (get32(f) !== 0)
|
|
124
|
+
return error(f, 4);
|
|
125
|
+
f.channels = get8(f);
|
|
126
|
+
if (!f.channels)
|
|
127
|
+
return error(f, 4);
|
|
128
|
+
if (f.channels > 256)
|
|
129
|
+
return error(f, 31);
|
|
130
|
+
f.sampleRate = get32(f);
|
|
131
|
+
if (!f.sampleRate)
|
|
132
|
+
return error(f, 4);
|
|
133
|
+
get32(f);
|
|
134
|
+
get32(f);
|
|
135
|
+
get32(f); // bitrates
|
|
136
|
+
let x = get8(f);
|
|
137
|
+
{
|
|
138
|
+
const log0 = x & 15;
|
|
139
|
+
const log1 = (x >> 4) & 15;
|
|
140
|
+
f.blocksize0 = 1 << log0;
|
|
141
|
+
f.blocksize1 = 1 << log1;
|
|
142
|
+
if (log0 < 6 || log0 > 13)
|
|
143
|
+
return error(f, 20);
|
|
144
|
+
if (log1 < 6 || log1 > 13)
|
|
145
|
+
return error(f, 20);
|
|
146
|
+
if (log0 > log1)
|
|
147
|
+
return error(f, 20);
|
|
148
|
+
}
|
|
149
|
+
x = get8(f);
|
|
150
|
+
if (!(x & 1))
|
|
151
|
+
return error(f, 4);
|
|
152
|
+
// comment packet
|
|
153
|
+
if (!startPage(f))
|
|
154
|
+
return false;
|
|
155
|
+
if (!startPacket(f))
|
|
156
|
+
return false;
|
|
157
|
+
if (!nextSegment(f))
|
|
158
|
+
return false;
|
|
159
|
+
if (get8Packet(f) !== 3)
|
|
160
|
+
return error(f, 20);
|
|
161
|
+
for (let i = 0; i < 6; ++i)
|
|
162
|
+
header[i] = get8Packet(f);
|
|
163
|
+
if (!vorbisValidate(header))
|
|
164
|
+
return error(f, 20);
|
|
165
|
+
{
|
|
166
|
+
const len = get32Packet(f);
|
|
167
|
+
for (let i = 0; i < len; ++i)
|
|
168
|
+
get8Packet(f); // vendor
|
|
169
|
+
const nComments = get32Packet(f);
|
|
170
|
+
for (let i = 0; i < nComments; ++i) {
|
|
171
|
+
const l = get32Packet(f);
|
|
172
|
+
for (let j = 0; j < l; ++j)
|
|
173
|
+
get8Packet(f);
|
|
174
|
+
}
|
|
175
|
+
x = get8Packet(f);
|
|
176
|
+
if (!(x & 1))
|
|
177
|
+
return error(f, 20);
|
|
178
|
+
}
|
|
179
|
+
skip(f, f.bytesInSeg);
|
|
180
|
+
f.bytesInSeg = 0;
|
|
181
|
+
{
|
|
182
|
+
let len = nextSegment(f);
|
|
183
|
+
while (len !== 0) {
|
|
184
|
+
skip(f, len);
|
|
185
|
+
f.bytesInSeg = 0;
|
|
186
|
+
len = nextSegment(f);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// setup packet
|
|
190
|
+
if (!startPacket(f))
|
|
191
|
+
return false;
|
|
192
|
+
crc32Init();
|
|
193
|
+
if (get8Packet(f) !== 5)
|
|
194
|
+
return error(f, 20);
|
|
195
|
+
for (let i = 0; i < 6; ++i)
|
|
196
|
+
header[i] = get8Packet(f);
|
|
197
|
+
if (!vorbisValidate(header))
|
|
198
|
+
return error(f, 20);
|
|
199
|
+
// codebooks
|
|
200
|
+
f.codebookCount = getBits(f, 8) + 1;
|
|
201
|
+
f.codebooks = [];
|
|
202
|
+
for (let i = 0; i < f.codebookCount; ++i) {
|
|
203
|
+
let values = null;
|
|
204
|
+
let total = 0;
|
|
205
|
+
const c = {
|
|
206
|
+
dimensions: 0, entries: 0, codewordLengths: null,
|
|
207
|
+
minimumValue: 0, deltaValue: 0, valueBits: 0, lookupType: 0,
|
|
208
|
+
sequenceP: 0, sparse: 0, lookupValues: 0, multiplicands: null,
|
|
209
|
+
codewords: null, fastHuffman: new Int32Array(FAST_HUFFMAN_TABLE_SIZE),
|
|
210
|
+
sortedCodewords: null, sortedValues: null, sortedEntries: 0,
|
|
211
|
+
};
|
|
212
|
+
f.codebooks.push(c);
|
|
213
|
+
let xx = getBits(f, 8);
|
|
214
|
+
if (xx !== 0x42)
|
|
215
|
+
return error(f, 20);
|
|
216
|
+
xx = getBits(f, 8);
|
|
217
|
+
if (xx !== 0x43)
|
|
218
|
+
return error(f, 20);
|
|
219
|
+
xx = getBits(f, 8);
|
|
220
|
+
if (xx !== 0x56)
|
|
221
|
+
return error(f, 20);
|
|
222
|
+
xx = getBits(f, 8);
|
|
223
|
+
c.dimensions = (getBits(f, 8) << 8) + xx;
|
|
224
|
+
xx = getBits(f, 8);
|
|
225
|
+
const y = getBits(f, 8);
|
|
226
|
+
c.entries = (getBits(f, 8) << 16) + (y << 8) + xx;
|
|
227
|
+
const ordered = getBits(f, 1);
|
|
228
|
+
c.sparse = ordered ? 0 : getBits(f, 1);
|
|
229
|
+
if (c.dimensions === 0 && c.entries !== 0)
|
|
230
|
+
return error(f, 20);
|
|
231
|
+
const lengths = new Uint8Array(c.entries);
|
|
232
|
+
if (ordered) {
|
|
233
|
+
let currentEntry = 0;
|
|
234
|
+
let currentLength = getBits(f, 5) + 1;
|
|
235
|
+
while (currentEntry < c.entries) {
|
|
236
|
+
const limit = c.entries - currentEntry;
|
|
237
|
+
const nn = getBits(f, ilog(limit));
|
|
238
|
+
if (currentLength >= 32)
|
|
239
|
+
return error(f, 20);
|
|
240
|
+
if (currentEntry + nn > c.entries)
|
|
241
|
+
return error(f, 20);
|
|
242
|
+
lengths.fill(currentLength, currentEntry, currentEntry + nn);
|
|
243
|
+
currentEntry += nn;
|
|
244
|
+
++currentLength;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
for (let j = 0; j < c.entries; ++j) {
|
|
249
|
+
const present = c.sparse ? getBits(f, 1) : 1;
|
|
250
|
+
if (present) {
|
|
251
|
+
lengths[j] = getBits(f, 5) + 1;
|
|
252
|
+
++total;
|
|
253
|
+
if (lengths[j] === 32)
|
|
254
|
+
return error(f, 20);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
lengths[j] = NO_CODE;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (c.sparse && total >= c.entries >> 2) {
|
|
262
|
+
c.sparse = 0;
|
|
263
|
+
}
|
|
264
|
+
let sortedCount = 0;
|
|
265
|
+
if (c.sparse) {
|
|
266
|
+
sortedCount = total;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
for (let j = 0; j < c.entries; ++j) {
|
|
270
|
+
if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] !== NO_CODE)
|
|
271
|
+
++sortedCount;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
c.sortedEntries = sortedCount;
|
|
275
|
+
values = null;
|
|
276
|
+
if (!c.sparse) {
|
|
277
|
+
c.codewordLengths = lengths;
|
|
278
|
+
c.codewords = new Uint32Array(c.entries);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
if (c.sortedEntries) {
|
|
282
|
+
c.codewordLengths = new Uint8Array(c.sortedEntries);
|
|
283
|
+
c.codewords = new Uint32Array(c.sortedEntries);
|
|
284
|
+
values = new Uint32Array(c.sortedEntries);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!computeCodewords(c, lengths, c.entries, values))
|
|
288
|
+
return error(f, 20);
|
|
289
|
+
if (c.sortedEntries) {
|
|
290
|
+
c.sortedCodewords = new Uint32Array(c.sortedEntries + 1);
|
|
291
|
+
c.sortedValues = new Int32Array(c.sortedEntries + 1);
|
|
292
|
+
computeSortedHuffmanShared(c, lengths, values);
|
|
293
|
+
}
|
|
294
|
+
if (c.sparse) {
|
|
295
|
+
c.codewords = null;
|
|
296
|
+
}
|
|
297
|
+
computeAcceleratedHuffman(c);
|
|
298
|
+
c.lookupType = getBits(f, 4);
|
|
299
|
+
if (c.lookupType > 2)
|
|
300
|
+
return error(f, 20);
|
|
301
|
+
if (c.lookupType > 0) {
|
|
302
|
+
c.minimumValue = float32Unpack(getBits(f, 32));
|
|
303
|
+
c.deltaValue = float32Unpack(getBits(f, 32));
|
|
304
|
+
c.valueBits = getBits(f, 4) + 1;
|
|
305
|
+
c.sequenceP = getBits(f, 1);
|
|
306
|
+
if (c.lookupType === 1) {
|
|
307
|
+
const v = lookup1Values(c.entries, c.dimensions);
|
|
308
|
+
if (v < 0)
|
|
309
|
+
return error(f, 20);
|
|
310
|
+
c.lookupValues = v;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
c.lookupValues = c.entries * c.dimensions;
|
|
314
|
+
}
|
|
315
|
+
if (c.lookupValues === 0)
|
|
316
|
+
return error(f, 20);
|
|
317
|
+
const mults = new Int32Array(c.lookupValues);
|
|
318
|
+
for (let j = 0; j < c.lookupValues; ++j) {
|
|
319
|
+
const q = getBits(f, c.valueBits);
|
|
320
|
+
if (q === EOP)
|
|
321
|
+
return error(f, 20);
|
|
322
|
+
mults[j] = q;
|
|
323
|
+
}
|
|
324
|
+
if (c.lookupType === 1) {
|
|
325
|
+
// pre-expand lookup1 multiplicands
|
|
326
|
+
const len = c.sparse ? c.sortedEntries : c.entries;
|
|
327
|
+
c.multiplicands = new Float32Array(len * c.dimensions);
|
|
328
|
+
let last = 0;
|
|
329
|
+
for (let j = 0; j < len; ++j) {
|
|
330
|
+
const zz = c.sparse ? c.sortedValues[j] : j;
|
|
331
|
+
let div = 1;
|
|
332
|
+
for (let k = 0; k < c.dimensions; ++k) {
|
|
333
|
+
const off = Math.floor(zz / div) % c.lookupValues;
|
|
334
|
+
const val = mults[off] * c.deltaValue + c.minimumValue + last;
|
|
335
|
+
c.multiplicands[j * c.dimensions + k] = val;
|
|
336
|
+
if (c.sequenceP)
|
|
337
|
+
last = val;
|
|
338
|
+
if (k + 1 < c.dimensions)
|
|
339
|
+
div *= c.lookupValues;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
c.lookupType = 2;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
let last = 0;
|
|
346
|
+
c.multiplicands = new Float32Array(c.lookupValues);
|
|
347
|
+
for (let j = 0; j < c.lookupValues; ++j) {
|
|
348
|
+
const val = mults[j] * c.deltaValue + c.minimumValue + last;
|
|
349
|
+
c.multiplicands[j] = val;
|
|
350
|
+
if (c.sequenceP)
|
|
351
|
+
last = val;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// time domain transfers (unused)
|
|
357
|
+
{
|
|
358
|
+
const tCount = getBits(f, 6) + 1;
|
|
359
|
+
for (let i = 0; i < tCount; ++i) {
|
|
360
|
+
if (getBits(f, 16) !== 0)
|
|
361
|
+
return error(f, 20);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// floors
|
|
365
|
+
f.floorCount = getBits(f, 6) + 1;
|
|
366
|
+
f.floorTypes = new Array(f.floorCount).fill(0);
|
|
367
|
+
f.floor0Config = [];
|
|
368
|
+
f.floor1Config = [];
|
|
369
|
+
for (let i = 0; i < f.floorCount; ++i) {
|
|
370
|
+
const ftype = getBits(f, 16);
|
|
371
|
+
if (ftype > 1)
|
|
372
|
+
return error(f, 20);
|
|
373
|
+
f.floorTypes[i] = ftype;
|
|
374
|
+
if (ftype === 0) {
|
|
375
|
+
return error(f, 26); // floor0 not supported (as stb_vorbis)
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
const g = {
|
|
379
|
+
partitions: 0, partitionClassList: [], classDimensions: [], classSubclasses: [],
|
|
380
|
+
classMasterbooks: [], subclassBooks: [], Xlist: [], sortedOrder: [],
|
|
381
|
+
neighbors: [], floor1Multiplier: 0, rangebits: 0, values: 0,
|
|
382
|
+
};
|
|
383
|
+
f.floor1Config.push(g);
|
|
384
|
+
let maxClass = -1;
|
|
385
|
+
g.partitions = getBits(f, 5);
|
|
386
|
+
for (let j = 0; j < g.partitions; ++j) {
|
|
387
|
+
g.partitionClassList.push(getBits(f, 4));
|
|
388
|
+
if (g.partitionClassList[j] > maxClass)
|
|
389
|
+
maxClass = g.partitionClassList[j];
|
|
390
|
+
}
|
|
391
|
+
for (let j = 0; j <= maxClass; ++j) {
|
|
392
|
+
g.classDimensions[j] = getBits(f, 3) + 1;
|
|
393
|
+
g.classSubclasses[j] = getBits(f, 2);
|
|
394
|
+
if (g.classSubclasses[j]) {
|
|
395
|
+
g.classMasterbooks[j] = getBits(f, 8);
|
|
396
|
+
if ((g.classMasterbooks[j] ?? 0) >= f.codebookCount)
|
|
397
|
+
return error(f, 20);
|
|
398
|
+
}
|
|
399
|
+
for (let k = 0; k < (1 << g.classSubclasses[j]); ++k) {
|
|
400
|
+
g.subclassBooks[j] = g.subclassBooks[j] ?? [];
|
|
401
|
+
g.subclassBooks[j][k] = getBits(f, 8) - 1;
|
|
402
|
+
if ((g.subclassBooks[j][k] ?? 0) >= f.codebookCount)
|
|
403
|
+
return error(f, 20);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
g.floor1Multiplier = getBits(f, 2) + 1;
|
|
407
|
+
g.rangebits = getBits(f, 4);
|
|
408
|
+
g.Xlist[0] = 0;
|
|
409
|
+
g.Xlist[1] = 1 << g.rangebits;
|
|
410
|
+
g.values = 2;
|
|
411
|
+
for (let j = 0; j < g.partitions; ++j) {
|
|
412
|
+
const cl = g.partitionClassList[j];
|
|
413
|
+
for (let k = 0; k < g.classDimensions[cl]; ++k) {
|
|
414
|
+
g.Xlist[g.values] = getBits(f, g.rangebits);
|
|
415
|
+
++g.values;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// sort order
|
|
419
|
+
const p = [];
|
|
420
|
+
for (let j = 0; j < g.values; ++j)
|
|
421
|
+
p.push({ x: g.Xlist[j], id: j });
|
|
422
|
+
p.sort((a, b) => a.x - b.x);
|
|
423
|
+
for (let j = 0; j < g.values - 1; ++j) {
|
|
424
|
+
if (p[j].x === p[j + 1].x)
|
|
425
|
+
return error(f, 20);
|
|
426
|
+
}
|
|
427
|
+
for (let j = 0; j < g.values; ++j)
|
|
428
|
+
g.sortedOrder[j] = p[j].id;
|
|
429
|
+
// neighbors
|
|
430
|
+
for (let j = 2; j < g.values; ++j) {
|
|
431
|
+
const [low, high] = neighborsOf(g.Xlist, j);
|
|
432
|
+
g.neighbors[j] = [low, high];
|
|
433
|
+
}
|
|
434
|
+
if (g.values > longestFloorlist)
|
|
435
|
+
longestFloorlist = g.values;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
// residue
|
|
439
|
+
f.residueCount = getBits(f, 6) + 1;
|
|
440
|
+
f.residueTypes = new Array(f.residueCount).fill(0);
|
|
441
|
+
f.residueConfig = [];
|
|
442
|
+
for (let i = 0; i < f.residueCount; ++i) {
|
|
443
|
+
const r = { begin: 0, end: 0, partSize: 0, classifications: 0, classbook: 0, classdata: null, residueBooks: null };
|
|
444
|
+
f.residueConfig.push(r);
|
|
445
|
+
const rtype = getBits(f, 16);
|
|
446
|
+
if (rtype > 2)
|
|
447
|
+
return error(f, 20);
|
|
448
|
+
f.residueTypes[i] = rtype;
|
|
449
|
+
r.begin = getBits(f, 24);
|
|
450
|
+
r.end = getBits(f, 24);
|
|
451
|
+
if (r.end < r.begin)
|
|
452
|
+
return error(f, 20);
|
|
453
|
+
r.partSize = getBits(f, 24) + 1;
|
|
454
|
+
r.classifications = getBits(f, 6) + 1;
|
|
455
|
+
r.classbook = getBits(f, 8);
|
|
456
|
+
if (r.classbook >= f.codebookCount)
|
|
457
|
+
return error(f, 20);
|
|
458
|
+
const residueCascade = new Uint8Array(64);
|
|
459
|
+
for (let j = 0; j < r.classifications; ++j) {
|
|
460
|
+
let highBits = 0;
|
|
461
|
+
const lowBits = getBits(f, 3);
|
|
462
|
+
if (getBits(f, 1))
|
|
463
|
+
highBits = getBits(f, 5);
|
|
464
|
+
residueCascade[j] = highBits * 8 + lowBits;
|
|
465
|
+
}
|
|
466
|
+
r.residueBooks = [];
|
|
467
|
+
for (let j = 0; j < r.classifications; ++j) {
|
|
468
|
+
const books = new Int16Array(8);
|
|
469
|
+
for (let k = 0; k < 8; ++k) {
|
|
470
|
+
if (residueCascade[j] & (1 << k)) {
|
|
471
|
+
books[k] = getBits(f, 8);
|
|
472
|
+
if ((books[k] ?? 0) >= f.codebookCount)
|
|
473
|
+
return error(f, 20);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
books[k] = -1;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
r.residueBooks.push(books);
|
|
480
|
+
}
|
|
481
|
+
r.classdata = [];
|
|
482
|
+
const cbEntries = f.codebooks[r.classbook].entries;
|
|
483
|
+
const classwords = f.codebooks[r.classbook].dimensions;
|
|
484
|
+
for (let j = 0; j < cbEntries; ++j) {
|
|
485
|
+
const cd = new Uint8Array(classwords);
|
|
486
|
+
let temp = j;
|
|
487
|
+
for (let k = classwords - 1; k >= 0; --k) {
|
|
488
|
+
cd[k] = temp % r.classifications;
|
|
489
|
+
temp = Math.floor(temp / r.classifications);
|
|
490
|
+
}
|
|
491
|
+
r.classdata.push(cd);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// mapping
|
|
495
|
+
f.mappingCount = getBits(f, 6) + 1;
|
|
496
|
+
f.mapping = [];
|
|
497
|
+
for (let i = 0; i < f.mappingCount; ++i) {
|
|
498
|
+
const m = { couplingSteps: 0, chan: [], submaps: 0, submapFloor: [], submapResidue: [] };
|
|
499
|
+
f.mapping.push(m);
|
|
500
|
+
const mappingType = getBits(f, 16);
|
|
501
|
+
if (mappingType !== 0)
|
|
502
|
+
return error(f, 20);
|
|
503
|
+
if (getBits(f, 1))
|
|
504
|
+
m.submaps = getBits(f, 4) + 1;
|
|
505
|
+
else
|
|
506
|
+
m.submaps = 1;
|
|
507
|
+
if (m.submaps > maxSubmaps)
|
|
508
|
+
maxSubmaps = m.submaps;
|
|
509
|
+
if (getBits(f, 1)) {
|
|
510
|
+
m.couplingSteps = getBits(f, 8) + 1;
|
|
511
|
+
if (m.couplingSteps > f.channels)
|
|
512
|
+
return error(f, 20);
|
|
513
|
+
for (let k = 0; k < m.couplingSteps; ++k) {
|
|
514
|
+
const magnitude = getBits(f, ilog(f.channels - 1));
|
|
515
|
+
const angle = getBits(f, ilog(f.channels - 1));
|
|
516
|
+
if (magnitude >= f.channels || angle >= f.channels)
|
|
517
|
+
return error(f, 20);
|
|
518
|
+
if (magnitude === angle)
|
|
519
|
+
return error(f, 20);
|
|
520
|
+
m.chan.push({ magnitude, angle, mux: 0 });
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
m.couplingSteps = 0;
|
|
525
|
+
}
|
|
526
|
+
// Allocate one channel entry PER CHANNEL (C: setup_malloc of
|
|
527
|
+
// f->channels entries, stb_vorbis.c:4081); the coupling loop above
|
|
528
|
+
// already wrote magnitude/angle into the first coupling_steps slots.
|
|
529
|
+
while (m.chan.length < f.channels)
|
|
530
|
+
m.chan.push({ magnitude: 0, angle: 0, mux: 0 });
|
|
531
|
+
if (getBits(f, 2))
|
|
532
|
+
return error(f, 20);
|
|
533
|
+
for (let j = 0; j < f.channels; ++j) {
|
|
534
|
+
if (m.submaps > 1) {
|
|
535
|
+
const mux = getBits(f, 4);
|
|
536
|
+
if (mux >= m.submaps)
|
|
537
|
+
return error(f, 20);
|
|
538
|
+
m.chan[j].mux = mux;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
// @SPECIFICATION: this case is missing from the spec
|
|
542
|
+
m.chan[j].mux = 0;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
for (let j = 0; j < m.submaps; ++j) {
|
|
546
|
+
getBits(f, 8);
|
|
547
|
+
const fl = getBits(f, 8);
|
|
548
|
+
const rs = getBits(f, 8);
|
|
549
|
+
if (fl >= f.floorCount || rs >= f.residueCount)
|
|
550
|
+
return error(f, 20);
|
|
551
|
+
m.submapFloor.push(fl);
|
|
552
|
+
m.submapResidue.push(rs);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// modes
|
|
556
|
+
f.modeCount = getBits(f, 6) + 1;
|
|
557
|
+
f.modeConfig = [];
|
|
558
|
+
for (let i = 0; i < f.modeCount; ++i) {
|
|
559
|
+
const m = { blockflag: 0, mapping: 0, windowtype: 0, transformtype: 0 };
|
|
560
|
+
f.modeConfig.push(m);
|
|
561
|
+
m.blockflag = getBits(f, 1);
|
|
562
|
+
m.windowtype = getBits(f, 16);
|
|
563
|
+
m.transformtype = getBits(f, 16);
|
|
564
|
+
m.mapping = getBits(f, 8);
|
|
565
|
+
if (m.windowtype !== 0 || m.transformtype !== 0)
|
|
566
|
+
return error(f, 20);
|
|
567
|
+
if (m.mapping >= f.mappingCount)
|
|
568
|
+
return error(f, 20);
|
|
569
|
+
}
|
|
570
|
+
flushPacket(f);
|
|
571
|
+
f.previousLength = 0;
|
|
572
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
573
|
+
f.channelBuffers[i] = new Float32Array(f.blocksize1);
|
|
574
|
+
f.previousWindow[i] = new Float32Array(f.blocksize1 / 2);
|
|
575
|
+
f.finalY[i] = new Int16Array(longestFloorlist);
|
|
576
|
+
}
|
|
577
|
+
computeBlocksize(f, 0, f.blocksize0);
|
|
578
|
+
computeBlocksize(f, 1, f.blocksize1);
|
|
579
|
+
f.blocksize[0] = f.blocksize0;
|
|
580
|
+
f.blocksize[1] = f.blocksize1;
|
|
581
|
+
if (f.nextSeg === -1) {
|
|
582
|
+
f.firstAudioPageOffset = getFileOffset(f);
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
f.firstAudioPageOffset = 0;
|
|
586
|
+
}
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
function computeSortedHuffmanShared(c, lengths, values) {
|
|
590
|
+
computeSortedHuffman(c, lengths, values);
|
|
591
|
+
}
|
|
592
|
+
// ---------------------------------------------------------------------------
|
|
593
|
+
// Floor decode + draw (deferred-floor variant)
|
|
594
|
+
// ---------------------------------------------------------------------------
|
|
595
|
+
function doFloor(f, map, i, n, target, finalY) {
|
|
596
|
+
const n2 = n >> 1;
|
|
597
|
+
const s = map.chan[i].mux;
|
|
598
|
+
const floor = map.submapFloor[s];
|
|
599
|
+
if (f.floorTypes[floor] === 0) {
|
|
600
|
+
f.error = 11;
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
const g = f.floor1Config[floor];
|
|
604
|
+
let lx = 0;
|
|
605
|
+
let ly = finalY[0] * g.floor1Multiplier;
|
|
606
|
+
for (let q = 1; q < g.values; ++q) {
|
|
607
|
+
const j = g.sortedOrder[q];
|
|
608
|
+
if (finalY[j] >= 0) {
|
|
609
|
+
const hy = finalY[j] * g.floor1Multiplier;
|
|
610
|
+
const hx = g.Xlist[j];
|
|
611
|
+
if (lx !== hx) {
|
|
612
|
+
drawLine(target, lx, ly, hx, hy, n2);
|
|
613
|
+
}
|
|
614
|
+
lx = hx;
|
|
615
|
+
ly = hy;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (lx < n2) {
|
|
619
|
+
for (let j = lx; j < n2; ++j) {
|
|
620
|
+
target[j] = (target[j] ?? 0) * INVERSE_DB_TABLE[ly & 255];
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
// ---------------------------------------------------------------------------
|
|
626
|
+
// Packet decode (vorbis_decode_initial/rest, stb_vorbis.c:3133-3523)
|
|
627
|
+
// ---------------------------------------------------------------------------
|
|
628
|
+
function vorbisDecodeInitial(f, res) {
|
|
629
|
+
f.channelBufferStart = 0;
|
|
630
|
+
f.channelBufferEnd = 0;
|
|
631
|
+
for (;;) {
|
|
632
|
+
if (f.eof)
|
|
633
|
+
return false;
|
|
634
|
+
if (!maybeStartPacket(f))
|
|
635
|
+
return false;
|
|
636
|
+
if (getBits(f, 1) !== 0) {
|
|
637
|
+
while (get8Packet(f) !== EOP) { /* flush */ }
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
const i = getBits(f, ilog(f.modeCount - 1));
|
|
641
|
+
if (i === EOP)
|
|
642
|
+
return false;
|
|
643
|
+
if (i >= f.modeCount)
|
|
644
|
+
return false;
|
|
645
|
+
res.mode = i;
|
|
646
|
+
const m = f.modeConfig[i];
|
|
647
|
+
let n, prev, next;
|
|
648
|
+
if (m.blockflag) {
|
|
649
|
+
n = f.blocksize1;
|
|
650
|
+
prev = getBits(f, 1);
|
|
651
|
+
next = getBits(f, 1);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
prev = next = 0;
|
|
655
|
+
n = f.blocksize0;
|
|
656
|
+
}
|
|
657
|
+
const windowCenter = n >> 1;
|
|
658
|
+
if (m.blockflag && !prev) {
|
|
659
|
+
res.leftStart = (n - f.blocksize0) >> 2;
|
|
660
|
+
res.leftEnd = (n + f.blocksize0) >> 2;
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
res.leftStart = 0;
|
|
664
|
+
res.leftEnd = windowCenter;
|
|
665
|
+
}
|
|
666
|
+
if (m.blockflag && !next) {
|
|
667
|
+
res.rightStart = (n * 3 - f.blocksize0) >> 2;
|
|
668
|
+
res.rightEnd = (n * 3 + f.blocksize0) >> 2;
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
res.rightStart = windowCenter;
|
|
672
|
+
res.rightEnd = n;
|
|
673
|
+
}
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function vorbisDecodePacketRest(f, len, m, leftStart0, leftEnd0, rightStart0, rightEnd0, pLeft) {
|
|
678
|
+
void leftEnd0;
|
|
679
|
+
let leftStart = leftStart0;
|
|
680
|
+
const n = f.blocksize[m.blockflag];
|
|
681
|
+
const map = f.mapping[m.mapping];
|
|
682
|
+
const n2 = n >> 1;
|
|
683
|
+
const zeroChannel = new Array(256).fill(0);
|
|
684
|
+
const reallyZeroChannel = new Array(256).fill(0);
|
|
685
|
+
// FLOORS
|
|
686
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
687
|
+
const s = map.chan[i].mux;
|
|
688
|
+
const floor = map.submapFloor[s];
|
|
689
|
+
zeroChannel[i] = 0;
|
|
690
|
+
if (f.floorTypes[floor] === 0) {
|
|
691
|
+
f.error = 11;
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
const g = f.floor1Config[floor];
|
|
695
|
+
if (getBits(f, 1)) {
|
|
696
|
+
const finalY = f.finalY[i];
|
|
697
|
+
const rangeList = [256, 128, 86, 64];
|
|
698
|
+
const range = rangeList[g.floor1Multiplier - 1];
|
|
699
|
+
let offset = 2;
|
|
700
|
+
finalY[0] = getBits(f, ilog(range) - 1);
|
|
701
|
+
finalY[1] = getBits(f, ilog(range) - 1);
|
|
702
|
+
const step2Flag = new Array(256).fill(0);
|
|
703
|
+
for (let j = 0; j < g.partitions; ++j) {
|
|
704
|
+
const pclass = g.partitionClassList[j];
|
|
705
|
+
const cdim = g.classDimensions[pclass];
|
|
706
|
+
const cbits = g.classSubclasses[pclass];
|
|
707
|
+
const csub = (1 << cbits) - 1;
|
|
708
|
+
let cval = 0;
|
|
709
|
+
if (cbits) {
|
|
710
|
+
const c = f.codebooks[g.classMasterbooks[pclass]];
|
|
711
|
+
cval = decodeShared(f, c);
|
|
712
|
+
}
|
|
713
|
+
for (let k = 0; k < cdim; ++k) {
|
|
714
|
+
const book = g.subclassBooks[pclass][cval & csub];
|
|
715
|
+
cval = cval >> cbits;
|
|
716
|
+
if (book >= 0) {
|
|
717
|
+
const c = f.codebooks[book];
|
|
718
|
+
finalY[offset++] = decodeShared(f, c);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
finalY[offset++] = 0;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (f.validBits === INVALID_BITS) {
|
|
726
|
+
f.error = 11;
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
step2Flag[0] = step2Flag[1] = 1;
|
|
730
|
+
for (let j = 2; j < g.values; ++j) {
|
|
731
|
+
const low = g.neighbors[j][0];
|
|
732
|
+
const high = g.neighbors[j][1];
|
|
733
|
+
const pred = predictPoint(g.Xlist[j], g.Xlist[low], g.Xlist[high], finalY[low], finalY[high]);
|
|
734
|
+
const val = finalY[j];
|
|
735
|
+
const highroom = range - pred;
|
|
736
|
+
const lowroom = pred;
|
|
737
|
+
let room;
|
|
738
|
+
if (highroom < lowroom)
|
|
739
|
+
room = highroom * 2;
|
|
740
|
+
else
|
|
741
|
+
room = lowroom * 2;
|
|
742
|
+
if (val) {
|
|
743
|
+
step2Flag[low] = step2Flag[high] = 1;
|
|
744
|
+
step2Flag[j] = 1;
|
|
745
|
+
if (val >= room) {
|
|
746
|
+
if (highroom > lowroom)
|
|
747
|
+
finalY[j] = val - lowroom + pred;
|
|
748
|
+
else
|
|
749
|
+
finalY[j] = pred - val + highroom - 1;
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
if (val & 1)
|
|
753
|
+
finalY[j] = pred - ((val + 1) >> 1);
|
|
754
|
+
else
|
|
755
|
+
finalY[j] = pred + (val >> 1);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
step2Flag[j] = 0;
|
|
760
|
+
finalY[j] = pred;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
// defer floor: mark unused
|
|
764
|
+
for (let j = 0; j < g.values; ++j) {
|
|
765
|
+
if (!step2Flag[j])
|
|
766
|
+
finalY[j] = -1;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
zeroChannel[i] = 1;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// re-enable coupled channels
|
|
774
|
+
for (let i = 0; i < f.channels; ++i)
|
|
775
|
+
reallyZeroChannel[i] = zeroChannel[i] ?? 0;
|
|
776
|
+
for (let i = 0; i < map.couplingSteps; ++i) {
|
|
777
|
+
const mag = map.chan[i]?.magnitude ?? 0;
|
|
778
|
+
const ang = map.chan[i]?.angle ?? 0;
|
|
779
|
+
if (!zeroChannel[mag] || !zeroChannel[ang]) {
|
|
780
|
+
zeroChannel[mag] = 0;
|
|
781
|
+
zeroChannel[ang] = 0;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
// RESIDUE
|
|
785
|
+
for (let i = 0; i < map.submaps; ++i) {
|
|
786
|
+
const residueBuffers = [];
|
|
787
|
+
const doNotDecode = [];
|
|
788
|
+
let ch = 0;
|
|
789
|
+
for (let j = 0; j < f.channels; ++j) {
|
|
790
|
+
if (map.chan[j].mux === i) {
|
|
791
|
+
if (zeroChannel[j]) {
|
|
792
|
+
doNotDecode[ch] = 1;
|
|
793
|
+
residueBuffers.push(null);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
doNotDecode[ch] = 0;
|
|
797
|
+
residueBuffers.push(f.channelBuffers[j]);
|
|
798
|
+
}
|
|
799
|
+
++ch;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const r = map.submapResidue[i];
|
|
803
|
+
decodeResidue(f, residueBuffers, ch, n2, r, doNotDecode);
|
|
804
|
+
}
|
|
805
|
+
// INVERSE COUPLING
|
|
806
|
+
for (let i = map.couplingSteps - 1; i >= 0; --i) {
|
|
807
|
+
const mag = f.channelBuffers[map.chan[i]?.magnitude ?? 0];
|
|
808
|
+
const ang = f.channelBuffers[map.chan[i]?.angle ?? 0];
|
|
809
|
+
for (let j = 0; j < n2; ++j) {
|
|
810
|
+
let a2, m2;
|
|
811
|
+
if (mag[j] > 0) {
|
|
812
|
+
if (ang[j] > 0) {
|
|
813
|
+
m2 = mag[j];
|
|
814
|
+
a2 = mag[j] - ang[j];
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
a2 = mag[j];
|
|
818
|
+
m2 = mag[j] + ang[j];
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
if (ang[j] > 0) {
|
|
823
|
+
m2 = mag[j];
|
|
824
|
+
a2 = mag[j] + ang[j];
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
a2 = mag[j];
|
|
828
|
+
m2 = mag[j] - ang[j];
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
mag[j] = m2;
|
|
832
|
+
ang[j] = a2;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
// floors
|
|
836
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
837
|
+
if (reallyZeroChannel[i]) {
|
|
838
|
+
f.channelBuffers[i].fill(0, 0, n2);
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
doFloor(f, map, i, n, f.channelBuffers[i], f.finalY[i]);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
// inverse MDCT
|
|
845
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
846
|
+
inverseMdct(f.channelBuffers[i], n, f, m.blockflag);
|
|
847
|
+
}
|
|
848
|
+
flushPacket(f);
|
|
849
|
+
if (f.firstDecode) {
|
|
850
|
+
f.currentLoc = (0 - n2) >>> 0;
|
|
851
|
+
f.discardSamplesDeferred = n - rightEnd0;
|
|
852
|
+
f.currentLocValid = true;
|
|
853
|
+
f.firstDecode = false;
|
|
854
|
+
}
|
|
855
|
+
else if (f.discardSamplesDeferred) {
|
|
856
|
+
if (f.discardSamplesDeferred >= rightStart0 - leftStart) {
|
|
857
|
+
f.discardSamplesDeferred -= rightStart0 - leftStart;
|
|
858
|
+
leftStart = rightStart0;
|
|
859
|
+
pLeft.v = leftStart;
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
leftStart += f.discardSamplesDeferred;
|
|
863
|
+
pLeft.v = leftStart;
|
|
864
|
+
f.discardSamplesDeferred = 0;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (f.lastSegWhich === f.endSegWithKnownLoc) {
|
|
868
|
+
if (f.currentLocValid && (f.pageFlag & PAGEFLAG_last_page)) {
|
|
869
|
+
const currentEnd = f.knownLocForPacket;
|
|
870
|
+
if (currentEnd < f.currentLoc + (rightEnd0 - leftStart)) {
|
|
871
|
+
if (currentEnd < f.currentLoc) {
|
|
872
|
+
len.v = 0;
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
len.v = currentEnd - f.currentLoc;
|
|
876
|
+
}
|
|
877
|
+
len.v += leftStart;
|
|
878
|
+
if (len.v > rightEnd0)
|
|
879
|
+
len.v = rightEnd0;
|
|
880
|
+
f.currentLoc += len.v;
|
|
881
|
+
return true;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
f.currentLoc = (f.knownLocForPacket - (n2 - leftStart)) >>> 0;
|
|
885
|
+
f.currentLocValid = true;
|
|
886
|
+
}
|
|
887
|
+
if (f.currentLocValid)
|
|
888
|
+
f.currentLoc = (f.currentLoc + (rightStart0 - leftStart)) >>> 0;
|
|
889
|
+
len.v = rightEnd0;
|
|
890
|
+
return true;
|
|
891
|
+
}
|
|
892
|
+
function decodeShared(f, c) {
|
|
893
|
+
let v = codebookDecodeStartShared(f, c);
|
|
894
|
+
if (c.sparse)
|
|
895
|
+
v = c.sortedValues[v];
|
|
896
|
+
return v;
|
|
897
|
+
}
|
|
898
|
+
function codebookDecodeStartShared(z, c) {
|
|
899
|
+
// C DECODE/DECODE_RAW (stb_vorbis.c:1763-1773): the scalar huffman
|
|
900
|
+
// path has NO lookupType restriction — classmaster codebooks in floor1
|
|
901
|
+
// are lookupType 0 (pure huffman). Only codebook_decode_start (VQ)
|
|
902
|
+
// rejects type 0.
|
|
903
|
+
prepHuffman(z);
|
|
904
|
+
let zz = decodeRawShared(z, c);
|
|
905
|
+
if (zz < 0) {
|
|
906
|
+
if (z.bytesInSeg === 0 && z.lastSeg)
|
|
907
|
+
return zz;
|
|
908
|
+
z.error = 11;
|
|
909
|
+
}
|
|
910
|
+
return zz;
|
|
911
|
+
}
|
|
912
|
+
function vorbisDecodePacket(f, len, pLeft, pRight) {
|
|
913
|
+
const res = { leftStart: 0, leftEnd: 0, rightStart: 0, rightEnd: 0, mode: 0 };
|
|
914
|
+
if (!vorbisDecodeInitial(f, res))
|
|
915
|
+
return false;
|
|
916
|
+
pLeft.v = res.leftStart;
|
|
917
|
+
pRight.v = res.rightStart;
|
|
918
|
+
return vorbisDecodePacketRest(f, len, f.modeConfig[res.mode], res.leftStart, res.leftEnd, res.rightStart, res.rightEnd, pLeft);
|
|
919
|
+
}
|
|
920
|
+
function vorbisFinishFrame(f, len, left, right) {
|
|
921
|
+
const prev0 = f.previousLength;
|
|
922
|
+
if (f.previousLength) {
|
|
923
|
+
const n = f.previousLength;
|
|
924
|
+
const w = getWindow(f, n);
|
|
925
|
+
if (w === null)
|
|
926
|
+
return 0;
|
|
927
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
928
|
+
const cb = f.channelBuffers[i];
|
|
929
|
+
const pw = f.previousWindow[i];
|
|
930
|
+
for (let j = 0; j < n; ++j) {
|
|
931
|
+
cb[left + j] = cb[left + j] * w[j] + pw[j] * w[n - 1 - j];
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
const prev = f.previousLength;
|
|
936
|
+
void prev0;
|
|
937
|
+
f.previousLength = len - right;
|
|
938
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
939
|
+
const cb = f.channelBuffers[i];
|
|
940
|
+
const pw = f.previousWindow[i];
|
|
941
|
+
for (let j = 0; right + j < len; ++j) {
|
|
942
|
+
pw[j] = cb[right + j];
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (!prev)
|
|
946
|
+
return 0;
|
|
947
|
+
if (len < right)
|
|
948
|
+
right = len;
|
|
949
|
+
f.samplesOutput += right - left;
|
|
950
|
+
return right - left;
|
|
951
|
+
}
|
|
952
|
+
function getWindow(f, len0) {
|
|
953
|
+
const len = len0 << 1;
|
|
954
|
+
if (len === f.blocksize0)
|
|
955
|
+
return f.window[0];
|
|
956
|
+
if (len === f.blocksize1)
|
|
957
|
+
return f.window[1];
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
function vorbisPumpFirstFrame(f) {
|
|
961
|
+
const len = { v: 0 };
|
|
962
|
+
const left = { v: 0 };
|
|
963
|
+
const right = { v: 0 };
|
|
964
|
+
const res = vorbisDecodePacket(f, len, left, right);
|
|
965
|
+
if (res)
|
|
966
|
+
vorbisFinishFrame(f, len.v, left.v, right.v);
|
|
967
|
+
return res;
|
|
968
|
+
}
|
|
969
|
+
// ---------------------------------------------------------------------------
|
|
970
|
+
// Public API (memory source)
|
|
971
|
+
// ---------------------------------------------------------------------------
|
|
972
|
+
export function stbVorbisOpenMemory(data, errorOut) {
|
|
973
|
+
const f = {
|
|
974
|
+
stream: data,
|
|
975
|
+
streamStart: 0,
|
|
976
|
+
streamEnd: data.length,
|
|
977
|
+
streamPos: 0,
|
|
978
|
+
streamLen: data.length,
|
|
979
|
+
eof: false,
|
|
980
|
+
error: 0,
|
|
981
|
+
sampleRate: 0,
|
|
982
|
+
channels: 0,
|
|
983
|
+
blocksize: [0, 0],
|
|
984
|
+
blocksize0: 0,
|
|
985
|
+
blocksize1: 0,
|
|
986
|
+
codebookCount: 0,
|
|
987
|
+
codebooks: [],
|
|
988
|
+
floorCount: 0,
|
|
989
|
+
floorTypes: [],
|
|
990
|
+
floor0Config: [],
|
|
991
|
+
floor1Config: [],
|
|
992
|
+
residueCount: 0,
|
|
993
|
+
residueTypes: [],
|
|
994
|
+
residueConfig: [],
|
|
995
|
+
mappingCount: 0,
|
|
996
|
+
mapping: [],
|
|
997
|
+
modeCount: 0,
|
|
998
|
+
modeConfig: [],
|
|
999
|
+
channelBuffers: [],
|
|
1000
|
+
outputs: [],
|
|
1001
|
+
previousWindow: [],
|
|
1002
|
+
previousLength: 0,
|
|
1003
|
+
finalY: [],
|
|
1004
|
+
currentLoc: 0,
|
|
1005
|
+
currentLocValid: false,
|
|
1006
|
+
A: [], B: [], C: [], window: [], bitReverse: [],
|
|
1007
|
+
firstDecode: false,
|
|
1008
|
+
nextSeg: -1,
|
|
1009
|
+
lastSeg: false,
|
|
1010
|
+
lastSegWhich: 0,
|
|
1011
|
+
acc: 0,
|
|
1012
|
+
validBits: 0,
|
|
1013
|
+
packetBytes: 0,
|
|
1014
|
+
endSegWithKnownLoc: -2,
|
|
1015
|
+
knownLocForPacket: 0,
|
|
1016
|
+
discardSamplesDeferred: 0,
|
|
1017
|
+
samplesOutput: 0,
|
|
1018
|
+
lastPage: 0,
|
|
1019
|
+
segmentCount: 0,
|
|
1020
|
+
segments: new Uint8Array(255),
|
|
1021
|
+
pageFlag: 0,
|
|
1022
|
+
bytesInSeg: 0,
|
|
1023
|
+
channelBufferStart: 0,
|
|
1024
|
+
channelBufferEnd: 0,
|
|
1025
|
+
firstAudioPageOffset: 0,
|
|
1026
|
+
};
|
|
1027
|
+
if (!startDecoder(f)) {
|
|
1028
|
+
errorOut.v = f.error;
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
vorbisPumpFirstFrame(f);
|
|
1032
|
+
return f;
|
|
1033
|
+
}
|
|
1034
|
+
export function stbVorbisGetFrameFloat(f, len) {
|
|
1035
|
+
const left = { v: 0 };
|
|
1036
|
+
const right = { v: 0 };
|
|
1037
|
+
if (!vorbisDecodePacket(f, len, left, right)) {
|
|
1038
|
+
f.channelBufferStart = 0;
|
|
1039
|
+
f.channelBufferEnd = 0;
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
len.v = vorbisFinishFrame(f, len.v, left.v, right.v);
|
|
1043
|
+
for (let i = 0; i < f.channels; ++i) {
|
|
1044
|
+
f.outputs[i] = f.channelBuffers[i].subarray(left.v);
|
|
1045
|
+
}
|
|
1046
|
+
f.channelBufferStart = left.v;
|
|
1047
|
+
f.channelBufferEnd = left.v + len.v;
|
|
1048
|
+
if (len.v === 0)
|
|
1049
|
+
return null;
|
|
1050
|
+
return f.outputs;
|
|
1051
|
+
}
|
|
1052
|
+
export { bitReverse, ilog, setFileOffset, getFileOffset, EOP, INVALID_BITS };
|
|
1053
|
+
//# sourceMappingURL=vorbis.js.map
|