@modplayjs/fmt-mo3 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.
@@ -0,0 +1,1068 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: OpenMPT's bundled minimp3 (reference/openmpt/include/
4
+ // minimp3/minimp3.h, public domain / CC0 by Lionel Fabbro et al.) — the
5
+ // Layer-3 decode path only (MO3 samples are always Layer 3), scalar
6
+ // (non-SIMD) variants.
7
+ //
8
+ // FRESH PORT (2026-10): rewritten function-by-function against the C
9
+ // source after the previous port produced wrong PCM on some files.
10
+ import { TABS, TAB32, TAB33, TABINDEX, G_LINBITS, G_SCF_LONG, G_SCF_SHORT, G_SCF_MIXED, G_SCF_PARTITIONS, G_SCFC_DECODE, G_MOD, G_PREAMP, G_POW43, G_AA, G_MDCT_WINDOW, G_WIN, G_SEC, G_TWID9, G_TWID3, G_PAN, G_EXPFRAC, } from './mp3tables.js';
11
+ // ---- constants (minimp3.h:49-82) ----
12
+ const MAX_FREE_FORMAT_FRAME_SIZE = 2304;
13
+ const MAX_FRAME_SYNC_MATCHES = 10;
14
+ const MAX_L3_FRAME_PAYLOAD_BYTES = MAX_FREE_FORMAT_FRAME_SIZE;
15
+ const MAX_BITRESERVOIR_BYTES = 511;
16
+ const SHORT_BLOCK_TYPE = 2;
17
+ const STOP_BLOCK_TYPE = 3;
18
+ const HDR_SIZE = 4;
19
+ const BITS_DEQUANTIZER_OUT = -1;
20
+ const MAX_SCF = 255 + BITS_DEQUANTIZER_OUT * 4 - 210; // 41
21
+ const MAX_SCFI = (MAX_SCF + 3) & ~3; // 44
22
+ const MINIMP3_MIN = (a, b) => (a > b ? b : a);
23
+ const MINIMP3_MAX = (a, b) => (a < b ? b : a);
24
+ // ---- header helpers (minimp3.h:264-314) ----
25
+ function hdrIsValid(h) {
26
+ return h[0] === 0xff &&
27
+ ((h[1] & 0xf0) === 0xf0 || (h[1] & 0xfe) === 0xe2) &&
28
+ (hdrGetLayer(h) !== 0) &&
29
+ (hdrGetBitrate(h) !== 15) &&
30
+ (hdrGetSampleRate(h) !== 3);
31
+ }
32
+ function hdrIsMono(h) {
33
+ return (h[3] & 0xc0) === 0xc0;
34
+ }
35
+ function hdrIsMsStereo(h) {
36
+ return (h[3] & 0xe0) === 0x60;
37
+ }
38
+ function hdrIsFreeFormat(h) {
39
+ return (h[2] & 0xf0) === 0;
40
+ }
41
+ function hdrIsCrc(h) {
42
+ return (h[1] & 1) === 0;
43
+ }
44
+ function hdrTestPadding(h) {
45
+ return (h[2] & 0x2) !== 0;
46
+ }
47
+ function hdrTestMpeg1(h) {
48
+ return (h[1] & 0x8) !== 0;
49
+ }
50
+ function hdrTestNotMpeg25(h) {
51
+ return (h[1] & 0x10) !== 0;
52
+ }
53
+ function hdrTestIStereo(h) {
54
+ return (h[3] & 0x10) !== 0;
55
+ }
56
+ function hdrTestMsStereo(h) {
57
+ return (h[3] & 0x20) !== 0;
58
+ }
59
+ function hdrGetLayer(h) {
60
+ return (h[1] >> 1) & 3;
61
+ }
62
+ function hdrGetBitrate(h) {
63
+ return h[2] >> 4;
64
+ }
65
+ function hdrGetSampleRate(h) {
66
+ return (h[2] >> 2) & 3;
67
+ }
68
+ function hdrGetMySampleRate(h) {
69
+ return hdrGetSampleRate(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1)) * 3;
70
+ }
71
+ function hdrIsFrame576(h) {
72
+ return (h[1] & 14) === 2;
73
+ }
74
+ function hdrIsLayer1(h) {
75
+ return (h[1] & 6) === 6;
76
+ }
77
+ function hdrSampleRateHz(h) {
78
+ const gHz = [44100, 48000, 32000];
79
+ let hz = gHz[hdrGetSampleRate(h)];
80
+ if (!hdrTestMpeg1(h))
81
+ hz = hz >> 1;
82
+ if (!hdrTestNotMpeg25(h))
83
+ hz = hz >> 1;
84
+ return hz;
85
+ }
86
+ function hdrFrameSamples(h) {
87
+ return hdrIsLayer1(h) ? 384 : 1152 >> (hdrIsFrame576(h) ? 1 : 0);
88
+ }
89
+ function hdrBitrateKbps(h) {
90
+ const halfrate = [
91
+ [[0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80],
92
+ [0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80],
93
+ [0, 16, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112, 128]],
94
+ [[0, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160],
95
+ [0, 16, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192],
96
+ [0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224]],
97
+ ];
98
+ return 2 * halfrate[hdrTestMpeg1(h) ? 1 : 0][hdrGetLayer(h) - 1][hdrGetBitrate(h)];
99
+ }
100
+ function hdrFrameBytes(h, freeFormatSize) {
101
+ let frameBytes = Math.trunc(hdrFrameSamples(h) * hdrBitrateKbps(h) * 125 / hdrSampleRateHz(h));
102
+ if (hdrIsLayer1(h))
103
+ frameBytes &= ~3;
104
+ return frameBytes !== 0 ? frameBytes : freeFormatSize;
105
+ }
106
+ function hdrPadding(h) {
107
+ return hdrTestPadding(h) ? (hdrIsLayer1(h) ? 4 : 1) : 0;
108
+ }
109
+ function bsInit(bs, data, bytes) {
110
+ bs.buf = data;
111
+ bs.pos = 0;
112
+ bs.limit = bytes * 8;
113
+ }
114
+ function getBits(bs, n) {
115
+ const s = bs.pos & 7;
116
+ let shl = n + s;
117
+ const p = bs.pos >> 3;
118
+ bs.pos += n;
119
+ if (bs.pos > bs.limit)
120
+ return 0;
121
+ let next = bs.buf[p] & (255 >> s);
122
+ let cache = 0;
123
+ let idx = p + 1;
124
+ while ((shl -= 8) > 0) {
125
+ cache |= next << shl;
126
+ next = bs.buf[idx++];
127
+ }
128
+ return ((cache | (next >> -shl)) >>> 0);
129
+ }
130
+ function newGrInfo() {
131
+ return {
132
+ sfbtab: G_SCF_LONG[0], part23Length: 0, bigValues: 0, scalefacCompress: 0,
133
+ globalGain: 0, blockType: 0, mixedBlockFlag: 0, nLongSfb: 22, nShortSfb: 0,
134
+ tableSelect: [0, 0, 0], regionCount: [0, 0, 0], subblockGain: [0, 0, 0],
135
+ preflag: 0, scalefacScale: 0, count1Table: 0, scfsi: 0,
136
+ };
137
+ }
138
+ export function mp3decInit(dec) {
139
+ dec.mdctOverlap = [new Float32Array(9 * 32), new Float32Array(9 * 32)];
140
+ dec.qmfState = new Float32Array(15 * 2 * 32);
141
+ dec.reserv = 0;
142
+ dec.freeFormatBytes = 0;
143
+ dec.header = new Uint8Array(4);
144
+ dec.reservBuf = new Uint8Array(511);
145
+ }
146
+ // ---- L3_read_side_info (minimp3.h:484-607) ----
147
+ function l3ReadSideInfo(bs, gr, hdr) {
148
+ const srIdx = hdrGetMySampleRate(hdr) - (hdrGetMySampleRate(hdr) !== 0 ? 1 : 0);
149
+ let grCount = hdrIsMono(hdr) ? 1 : 2;
150
+ let mainDataBegin;
151
+ let scfsi = 0;
152
+ let part23Sum = 0;
153
+ if (hdrTestMpeg1(hdr)) {
154
+ grCount *= 2;
155
+ mainDataBegin = getBits(bs, 9);
156
+ scfsi = getBits(bs, 7 + grCount);
157
+ }
158
+ else {
159
+ mainDataBegin = getBits(bs, 8 + grCount) >> grCount;
160
+ }
161
+ let g = 0;
162
+ do {
163
+ if (hdrIsMono(hdr))
164
+ scfsi = (scfsi << 4) >>> 0;
165
+ const gi = gr[g];
166
+ gi.part23Length = getBits(bs, 12);
167
+ part23Sum += gi.part23Length;
168
+ gi.bigValues = getBits(bs, 9);
169
+ if (gi.bigValues > 288)
170
+ return -1;
171
+ gi.globalGain = getBits(bs, 8);
172
+ gi.scalefacCompress = getBits(bs, hdrTestMpeg1(hdr) ? 4 : 9);
173
+ gi.sfbtab = G_SCF_LONG[srIdx];
174
+ gi.nLongSfb = 22;
175
+ gi.nShortSfb = 0;
176
+ let tables;
177
+ if (getBits(bs, 1) !== 0) {
178
+ gi.blockType = getBits(bs, 2);
179
+ if (gi.blockType === 0)
180
+ return -1;
181
+ gi.mixedBlockFlag = getBits(bs, 1);
182
+ gi.regionCount[0] = 7;
183
+ gi.regionCount[1] = 255;
184
+ if (gi.blockType === SHORT_BLOCK_TYPE) {
185
+ scfsi &= 0x0f0f;
186
+ if (gi.mixedBlockFlag === 0) {
187
+ gi.regionCount[0] = 8;
188
+ gi.sfbtab = G_SCF_SHORT[srIdx];
189
+ gi.nLongSfb = 0;
190
+ gi.nShortSfb = 39;
191
+ }
192
+ else {
193
+ gi.sfbtab = G_SCF_MIXED[srIdx];
194
+ gi.nLongSfb = hdrTestMpeg1(hdr) ? 8 : 6;
195
+ gi.nShortSfb = 30;
196
+ }
197
+ }
198
+ tables = getBits(bs, 10) << 5;
199
+ gi.subblockGain[0] = getBits(bs, 3);
200
+ gi.subblockGain[1] = getBits(bs, 3);
201
+ gi.subblockGain[2] = getBits(bs, 3);
202
+ }
203
+ else {
204
+ gi.blockType = 0;
205
+ gi.mixedBlockFlag = 0;
206
+ tables = getBits(bs, 15);
207
+ gi.regionCount[0] = getBits(bs, 4);
208
+ gi.regionCount[1] = getBits(bs, 3);
209
+ gi.regionCount[2] = 255;
210
+ }
211
+ gi.tableSelect[0] = (tables >> 10) & 31;
212
+ gi.tableSelect[1] = (tables >> 5) & 31;
213
+ gi.tableSelect[2] = tables & 31;
214
+ gi.preflag = hdrTestMpeg1(hdr) ? getBits(bs, 1) : (gi.scalefacCompress >= 500 ? 1 : 0);
215
+ gi.scalefacScale = getBits(bs, 1);
216
+ gi.count1Table = getBits(bs, 1);
217
+ gi.scfsi = (scfsi >>> 12) & 15;
218
+ scfsi = (scfsi << 4) >>> 0;
219
+ } while (++g < grCount);
220
+ if (part23Sum + bs.pos > bs.limit + mainDataBegin * 8)
221
+ return -1;
222
+ return mainDataBegin;
223
+ }
224
+ // ---- L3_read_scalefactors (minimp3.h:609-640) ----
225
+ function l3ReadScalefactors(scf, scfOff, istPos, istOff, scfSize, scfCount, bitbuf, scfsi) {
226
+ let sOff = scfOff, iOff = istOff;
227
+ for (let i = 0; i < 4 && scfCount[i] !== 0; i++, scfsi *= 2) {
228
+ const cnt = scfCount[i];
229
+ if ((scfsi & 8) !== 0) {
230
+ for (let k = 0; k < cnt; k++)
231
+ scf[sOff + k] = istPos[iOff + k];
232
+ }
233
+ else {
234
+ const bits = scfSize[i];
235
+ if (bits === 0) {
236
+ for (let k = 0; k < cnt; k++) {
237
+ scf[sOff + k] = 0;
238
+ istPos[iOff + k] = 0;
239
+ }
240
+ }
241
+ else {
242
+ const maxScf = scfsi < 0 ? (1 << bits) - 1 : -1;
243
+ for (let k = 0; k < cnt; k++) {
244
+ const s = getBits(bitbuf, bits);
245
+ istPos[iOff + k] = s === maxScf ? 255 : s; // uint8 -1
246
+ scf[sOff + k] = s;
247
+ }
248
+ }
249
+ }
250
+ sOff += cnt;
251
+ iOff += cnt;
252
+ }
253
+ scf[sOff] = 0;
254
+ scf[sOff + 1] = 0;
255
+ scf[sOff + 2] = 0;
256
+ }
257
+ // ---- L3_ldexp_q2 (minimp3.h:642-652) ----
258
+ function l3LdexpQ2(y, expQ2) {
259
+ let e;
260
+ do {
261
+ e = MINIMP3_MIN(30 * 4, expQ2);
262
+ y = Math.fround(y * Math.fround(G_EXPFRAC[e & 3] * ((1 << 30) >> (e >> 2))));
263
+ } while ((expQ2 -= e) > 0);
264
+ return y;
265
+ }
266
+ // ---- L3_decode_scalefactors (minimp3.h:654-714) ----
267
+ function l3DecodeScalefactors(hdr, istPos, bs, gr, scf, ch) {
268
+ let scfPartition = G_SCF_PARTITIONS[(gr.nShortSfb !== 0 ? 1 : 0) + (gr.nLongSfb === 0 ? 1 : 0)];
269
+ const scfSize = [0, 0, 0, 0];
270
+ const iscf = new Uint8Array(40);
271
+ const scfShift = gr.scalefacScale + 1;
272
+ let scfsi = gr.scfsi;
273
+ if (hdrTestMpeg1(hdr)) {
274
+ const part = G_SCFC_DECODE[gr.scalefacCompress];
275
+ scfSize[1] = scfSize[0] = part >> 2;
276
+ scfSize[3] = scfSize[2] = part & 3;
277
+ }
278
+ else {
279
+ // C: for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) — the k
280
+ // increment runs before the condition re-check, so the final k is
281
+ // one row PAST the last used entry (the partition offset).
282
+ const ist = hdrTestIStereo(hdr) && ch !== 0 ? 1 : 0;
283
+ let sfc = gr.scalefacCompress >> ist;
284
+ let k = ist * 3 * 4;
285
+ let modprod = 1;
286
+ while (sfc >= 0) {
287
+ modprod = 1;
288
+ for (let i = 3; i >= 0; i--) {
289
+ scfSize[i] = Math.trunc(sfc / modprod) % G_MOD[k + i];
290
+ modprod *= G_MOD[k + i];
291
+ }
292
+ sfc -= modprod;
293
+ k += 4;
294
+ }
295
+ scfPartition = scfPartition.slice(k);
296
+ scfsi = -16;
297
+ }
298
+ l3ReadScalefactors(iscf, 0, istPos, 0, scfSize, scfPartition, bs, scfsi);
299
+ if (gr.nShortSfb !== 0) {
300
+ const sh = 3 - scfShift;
301
+ for (let i = 0; i < gr.nShortSfb; i += 3) {
302
+ iscf[gr.nLongSfb + i + 0] = ((iscf[gr.nLongSfb + i + 0] ?? 0) + ((gr.subblockGain[0] ?? 0) << sh)) & 255;
303
+ iscf[gr.nLongSfb + i + 1] = ((iscf[gr.nLongSfb + i + 1] ?? 0) + ((gr.subblockGain[1] ?? 0) << sh)) & 255;
304
+ iscf[gr.nLongSfb + i + 2] = ((iscf[gr.nLongSfb + i + 2] ?? 0) + ((gr.subblockGain[2] ?? 0) << sh)) & 255;
305
+ }
306
+ }
307
+ else if (gr.preflag !== 0) {
308
+ for (let i = 0; i < 10; i++)
309
+ iscf[11 + i] = ((iscf[11 + i] ?? 0) + (G_PREAMP[i] ?? 0)) & 255;
310
+ }
311
+ const gainExp = gr.globalGain + BITS_DEQUANTIZER_OUT * 4 - 210 - (hdrIsMsStereo(hdr) ? 2 : 0);
312
+ const gain = l3LdexpQ2(1 << (MAX_SCFI / 4), MAX_SCFI - gainExp);
313
+ const n = gr.nLongSfb + gr.nShortSfb;
314
+ for (let i = 0; i < n; i++) {
315
+ scf[i] = l3LdexpQ2(gain, (iscf[i] | 0) << scfShift);
316
+ }
317
+ }
318
+ // ---- L3_pow_43 (minimp3.h:721-740) ----
319
+ function l3Pow43(x) {
320
+ let mult = 256;
321
+ if (x < 129)
322
+ return G_POW43[16 + x];
323
+ if (x < 1024) {
324
+ mult = 16;
325
+ x <<= 3;
326
+ }
327
+ const sign = (2 * x) & 64;
328
+ const frac = ((x & 63) - sign) / ((x & ~63) + sign);
329
+ return G_POW43[16 + ((x + sign) >> 6)] * (1 + frac * (4 / 3 + frac * (2 / 9))) * mult;
330
+ }
331
+ // ---- L3_huffman (minimp3.h:742-877) — scalar path ----
332
+ function l3Huffman(dst, dstOffIn, bs, gr, scf, layer3grLimit) {
333
+ let one = 0;
334
+ let ireg = 0;
335
+ let bigValCnt = gr.bigValues;
336
+ let sfbIdx = 0;
337
+ const sfb = gr.sfbtab;
338
+ let dstOff = dstOffIn;
339
+ // Bit cache state — mirrors the C's bs_cache/bs_sh/bs_next_ptr.
340
+ let bsNextPtr = bs.pos >> 3; // byte index into bs.buf
341
+ const load4 = () => {
342
+ const b0 = bs.buf[bsNextPtr] ?? 0;
343
+ const b1 = bs.buf[bsNextPtr + 1] ?? 0;
344
+ const b2 = bs.buf[bsNextPtr + 2] ?? 0;
345
+ const b3 = bs.buf[bsNextPtr + 3] ?? 0;
346
+ return ((((b0 * 256 + b1) * 256 + b2) * 256 + b3) << (bs.pos & 7)) >>> 0;
347
+ };
348
+ let bsCache = load4();
349
+ let bsSh = (bs.pos & 7) - 8;
350
+ bsNextPtr += 4;
351
+ const peekBits = (n) => (n === 0 ? 0 : bsCache >>> (32 - n));
352
+ const flushBits = (n) => {
353
+ bsCache = (bsCache << n) >>> 0;
354
+ bsSh += n;
355
+ };
356
+ const checkBits = () => {
357
+ while (bsSh >= 0) {
358
+ bsCache = (bsCache | ((bs.buf[bsNextPtr++] ?? 0) << bsSh)) >>> 0;
359
+ bsSh -= 8;
360
+ }
361
+ };
362
+ // BSPOS = (bs_next_ptr - bs->buf)*8 - 24 + bs_sh
363
+ const bsPos = () => bsNextPtr * 8 - 24 + bsSh;
364
+ while (bigValCnt > 0) {
365
+ const tabNum = gr.tableSelect[ireg];
366
+ let sfbCnt = gr.regionCount[ireg++];
367
+ const codebookBase = TABINDEX[tabNum];
368
+ const linbits = G_LINBITS[tabNum];
369
+ let np;
370
+ let pairsToDecode;
371
+ if (linbits !== 0) {
372
+ do {
373
+ np = sfb[sfbIdx++] / 2;
374
+ pairsToDecode = MINIMP3_MIN(bigValCnt, np);
375
+ one = scf[0];
376
+ scf = scf.subarray(1);
377
+ do {
378
+ let w = 5;
379
+ let leaf = TABS[codebookBase + peekBits(w)];
380
+ while (leaf < 0) {
381
+ flushBits(w);
382
+ w = leaf & 7;
383
+ leaf = TABS[codebookBase + peekBits(w) - (leaf >> 3)];
384
+ }
385
+ flushBits(leaf >> 8);
386
+ for (let j = 0; j < 2; j++, dstOff++, leaf >>= 4) {
387
+ let lsb = leaf & 0x0f;
388
+ if (lsb === 15) {
389
+ lsb += peekBits(linbits);
390
+ flushBits(linbits);
391
+ checkBits();
392
+ dst[dstOff] = Math.fround(Math.fround(one * l3Pow43(lsb)) * (bsCache >= 0x80000000 ? -1 : 1));
393
+ }
394
+ else {
395
+ dst[dstOff] = Math.fround(G_POW43[16 + lsb - 16 * (bsCache >>> 31)] * one);
396
+ }
397
+ flushBits(lsb !== 0 ? 1 : 0);
398
+ }
399
+ checkBits();
400
+ } while (--pairsToDecode);
401
+ } while ((bigValCnt -= np) > 0 && --sfbCnt >= 0);
402
+ }
403
+ else {
404
+ do {
405
+ np = sfb[sfbIdx++] / 2;
406
+ pairsToDecode = MINIMP3_MIN(bigValCnt, np);
407
+ one = scf[0];
408
+ scf = scf.subarray(1);
409
+ do {
410
+ let w = 5;
411
+ let leaf = TABS[codebookBase + peekBits(w)];
412
+ while (leaf < 0) {
413
+ flushBits(w);
414
+ w = leaf & 7;
415
+ leaf = TABS[codebookBase + peekBits(w) - (leaf >> 3)];
416
+ }
417
+ flushBits(leaf >> 8);
418
+ for (let j = 0; j < 2; j++, dstOff++, leaf >>= 4) {
419
+ const lsb = leaf & 0x0f;
420
+ dst[dstOff] = Math.fround(G_POW43[16 + lsb - 16 * (bsCache >>> 31)] * one);
421
+ flushBits(lsb !== 0 ? 1 : 0);
422
+ }
423
+ checkBits();
424
+ } while (--pairsToDecode);
425
+ } while ((bigValCnt -= np) > 0 && --sfbCnt >= 0);
426
+ }
427
+ }
428
+ // count1 quad loop — RELOAD_SCALEFACTOR / DEQ_COUNT1 verbatim.
429
+ let np = 1 - bigValCnt;
430
+ for (;; dstOff += 4) {
431
+ const codebookCount1 = gr.count1Table !== 0 ? TAB33 : TAB32;
432
+ let leaf = codebookCount1[peekBits(4)];
433
+ if (!(leaf & 8)) {
434
+ leaf = codebookCount1[(leaf >> 3) + ((bsCache << 4) >>> (32 - (leaf & 3)))];
435
+ }
436
+ flushBits(leaf & 7);
437
+ if (bsPos() > layer3grLimit)
438
+ break;
439
+ // RELOAD_SCALEFACTOR
440
+ if (--np === 0) {
441
+ np = sfb[sfbIdx++] / 2;
442
+ if (np === 0)
443
+ break;
444
+ one = scf[0];
445
+ scf = scf.subarray(1);
446
+ }
447
+ // DEQ_COUNT1(0), DEQ_COUNT1(1)
448
+ if (leaf & 128) {
449
+ dst[dstOff] = bsCache >= 0x80000000 ? -one : one;
450
+ flushBits(1);
451
+ }
452
+ if (leaf & 64) {
453
+ dst[dstOff + 1] = bsCache >= 0x80000000 ? -one : one;
454
+ flushBits(1);
455
+ }
456
+ // RELOAD_SCALEFACTOR
457
+ if (--np === 0) {
458
+ np = sfb[sfbIdx++] / 2;
459
+ if (np === 0)
460
+ break;
461
+ one = scf[0];
462
+ scf = scf.subarray(1);
463
+ }
464
+ // DEQ_COUNT1(2), DEQ_COUNT1(3)
465
+ if (leaf & 32) {
466
+ dst[dstOff + 2] = bsCache >= 0x80000000 ? -one : one;
467
+ flushBits(1);
468
+ }
469
+ if (leaf & 16) {
470
+ dst[dstOff + 3] = bsCache >= 0x80000000 ? -one : one;
471
+ flushBits(1);
472
+ }
473
+ checkBits();
474
+ }
475
+ bs.pos = layer3grLimit;
476
+ }
477
+ // ---- L3_midside_stereo / L3_intensity_stereo (minimp3.h:879-994) ----
478
+ function l3MidsideStereo(left, n) {
479
+ const right = left.subarray(576);
480
+ for (let i = 0; i < n; i++) {
481
+ const a = left[i];
482
+ const b = right[i];
483
+ left[i] = Math.fround(a + b);
484
+ right[i] = Math.fround(a - b);
485
+ }
486
+ }
487
+ function l3IntensityStereoBand(left, leftOff, n, kl, kr) {
488
+ for (let i = 0; i < n; i++) {
489
+ left[leftOff + 576 + i] = left[leftOff + i] * kr;
490
+ left[leftOff + i] = left[leftOff + i] * kl;
491
+ }
492
+ }
493
+ function l3StereoTopBand(right, rOff, sfb, nbands, maxBand) {
494
+ maxBand[0] = maxBand[1] = maxBand[2] = -1;
495
+ for (let i = 0; i < nbands; i++) {
496
+ for (let k = 0; k < sfb[i]; k += 2) {
497
+ if (right[rOff + k] !== 0 || right[rOff + k + 1] !== 0) {
498
+ maxBand[i % 3] = i;
499
+ break;
500
+ }
501
+ }
502
+ rOff += sfb[i];
503
+ }
504
+ }
505
+ function l3StereoProcess(left, leftOff, istPos, sfb, hdr, maxBand, mpeg2Sh) {
506
+ const gPan = G_PAN;
507
+ const mpeg1 = hdrTestMpeg1(hdr);
508
+ const maxPos = mpeg1 ? 7 : 64;
509
+ let i = 0;
510
+ for (; sfb[i] !== 0; i++) {
511
+ const ipos = istPos[i];
512
+ if (i > maxBand[i % 3] && ipos < maxPos) {
513
+ const s = hdrTestMsStereo(hdr) ? 1.41421356 : 1;
514
+ let kl, kr;
515
+ if (mpeg1) {
516
+ kl = gPan[2 * ipos];
517
+ kr = gPan[2 * ipos + 1];
518
+ }
519
+ else {
520
+ kl = 1;
521
+ kr = l3LdexpQ2(1, ((ipos + 1) >> 1) << mpeg2Sh);
522
+ if ((ipos & 1) !== 0) {
523
+ kl = kr;
524
+ kr = 1;
525
+ }
526
+ }
527
+ l3IntensityStereoBand(left, leftOff, sfb[i], kl * s, kr * s);
528
+ }
529
+ else if (hdrTestMsStereo(hdr)) {
530
+ l3MidsideStereo(left.subarray(leftOff), sfb[i]);
531
+ }
532
+ leftOff += sfb[i];
533
+ }
534
+ }
535
+ function l3IntensityStereo(left, istPos, gr, hdr) {
536
+ const nSfb = gr[0].nLongSfb + gr[0].nShortSfb;
537
+ const maxBlocks = gr[0].nShortSfb !== 0 ? 3 : 1;
538
+ const maxBand = [0, 0, 0];
539
+ l3StereoTopBand(left.subarray(576), 0, gr[0].sfbtab, nSfb, maxBand);
540
+ if (gr[0].nLongSfb !== 0) {
541
+ maxBand[0] = maxBand[1] = maxBand[2] = MINIMP3_MAX(MINIMP3_MAX(maxBand[0], maxBand[1]), maxBand[2]);
542
+ }
543
+ for (let i = 0; i < maxBlocks; i++) {
544
+ const defaultPos = hdrTestMpeg1(hdr) ? 3 : 0;
545
+ const itop = nSfb - maxBlocks + i;
546
+ const prev = itop - maxBlocks;
547
+ istPos[1][itop] = maxBand[i] >= prev ? defaultPos : istPos[1][prev];
548
+ }
549
+ l3StereoProcess(left, 0, istPos[1], gr[0].sfbtab, hdr, maxBand, gr[1].scalefacCompress & 1);
550
+ }
551
+ // ---- L3_reorder (minimp3.h:996-1011) ----
552
+ function l3Reorder(grbuf, gOff, scratch, sOff, sfb, sfbOff) {
553
+ let src = gOff;
554
+ let dst = sOff;
555
+ let idx = sfbOff;
556
+ let len;
557
+ for (; (len = sfb[idx]) !== 0; idx += 3, src += 2 * len) {
558
+ for (let i = 0; i < len; i++, src++) {
559
+ scratch[dst++] = grbuf[src + 0 * len];
560
+ scratch[dst++] = grbuf[src + 1 * len];
561
+ scratch[dst++] = grbuf[src + 2 * len];
562
+ }
563
+ }
564
+ const count = dst - sOff;
565
+ for (let i = 0; i < count; i++)
566
+ grbuf[gOff + i] = scratch[sOff + i];
567
+ }
568
+ // ---- L3_antialias (minimp3.h:1013-1046) — scalar path ----
569
+ function l3Antialias(grbuf, gOff, nbands) {
570
+ for (; nbands > 0; nbands--, gOff += 18) {
571
+ for (let i = 0; i < 8; i++) {
572
+ const u = grbuf[gOff + 18 + i];
573
+ const d = grbuf[gOff + 17 - i];
574
+ const aa0 = G_AA[0], aa1 = G_AA[1];
575
+ const fr = Math.fround;
576
+ grbuf[gOff + 18 + i] = fr(fr(u * aa0[i]) - fr(d * aa1[i]));
577
+ grbuf[gOff + 17 - i] = fr(fr(u * aa1[i]) + fr(d * aa0[i]));
578
+ }
579
+ }
580
+ }
581
+ // ---- L3_dct3_9 (minimp3.h:1048-1086) ----
582
+ function l3Dct3_9(y) {
583
+ const fr = Math.fround;
584
+ let s0 = y[0], s2 = y[2], s4 = y[4], s6 = y[6], s8 = y[8];
585
+ const t0 = fr(s0 + fr(s6 * 0.5));
586
+ s0 = fr(s0 - s6);
587
+ const t4 = fr(fr(s4 + s2) * 0.93969262);
588
+ const t2 = fr(fr(s8 + s2) * 0.76604444);
589
+ s6 = fr(fr(s4 - s8) * 0.17364818);
590
+ s4 = fr(s4 + fr(s8 - s2));
591
+ const s2n = fr(s0 - fr(s4 * 0.5));
592
+ y[4] = fr(s4 + s0);
593
+ const s8n = fr(fr(t0 - t2) + s6);
594
+ const s0n = fr(fr(t0 - t4) + t2);
595
+ const s4n = fr(fr(t0 + t4) - s6);
596
+ let s1 = y[1];
597
+ let s3 = y[3];
598
+ const s5 = y[5];
599
+ const s7 = y[7];
600
+ s3 = fr(s3 * 0.8660254);
601
+ const tt0 = fr(fr(s5 + s1) * 0.98480775);
602
+ const tt4 = fr(fr(s5 - s7) * 0.34202014);
603
+ const tt2 = fr(fr(s1 + s7) * 0.64278761);
604
+ s1 = fr(fr(s1 - s5 - s7) * 0.8660254);
605
+ const s5n = fr(fr(tt0 - s3) - tt2);
606
+ const s7n = fr(fr(tt4 - s3) - tt0);
607
+ const s3n = fr(fr(tt4 + s3) - tt2);
608
+ y[0] = fr(s4n - s7n);
609
+ y[1] = fr(s2n + s1);
610
+ y[2] = fr(s0n - s3n);
611
+ y[3] = fr(s8n + s5n);
612
+ y[5] = fr(s8n - s5n);
613
+ y[6] = fr(s0n + s3n);
614
+ y[7] = fr(s2n - s1);
615
+ y[8] = fr(s4n + s7n);
616
+ }
617
+ // ---- L3_imdct36 (minimp3.h:1088-1144) — scalar path ----
618
+ function l3Imdct36(grbuf, gOff, overlap, oOff, window, nbands) {
619
+ for (let j = 0; j < nbands; j++, gOff += 18, oOff += 9) {
620
+ const co = new Array(9);
621
+ const si = new Array(9);
622
+ co[0] = -grbuf[gOff];
623
+ si[0] = grbuf[gOff + 17];
624
+ const fr = Math.fround;
625
+ for (let i = 0; i < 4; i++) {
626
+ si[8 - 2 * i] = fr(grbuf[gOff + 4 * i + 1] - grbuf[gOff + 4 * i + 2]);
627
+ co[1 + 2 * i] = fr(grbuf[gOff + 4 * i + 1] + grbuf[gOff + 4 * i + 2]);
628
+ si[7 - 2 * i] = fr(grbuf[gOff + 4 * i + 4] - grbuf[gOff + 4 * i + 3]);
629
+ co[2 + 2 * i] = fr(-(grbuf[gOff + 4 * i + 3] + grbuf[gOff + 4 * i + 4]));
630
+ }
631
+ l3Dct3_9(co);
632
+ l3Dct3_9(si);
633
+ si[1] = -si[1];
634
+ si[3] = -si[3];
635
+ si[5] = -si[5];
636
+ si[7] = -si[7];
637
+ for (let i = 0; i < 9; i++) {
638
+ const ovl = overlap[oOff + i];
639
+ const sum = fr(fr(co[i] * G_TWID9[9 + i]) + fr(si[i] * G_TWID9[0 + i]));
640
+ overlap[oOff + i] = fr(fr(co[i] * G_TWID9[0 + i]) - fr(si[i] * G_TWID9[9 + i]));
641
+ grbuf[gOff + i] = fr(fr(ovl * window[0 + i]) - fr(sum * window[9 + i]));
642
+ grbuf[gOff + 17 - i] = fr(fr(ovl * window[9 + i]) + fr(sum * window[0 + i]));
643
+ }
644
+ }
645
+ }
646
+ // ---- L3_idct3 + L3_imdct12 (minimp3.h:1145-1172) ----
647
+ function l3Idct3(x0, x1, x2, dst) {
648
+ const m1 = x1 * 0.8660254;
649
+ const a1 = x0 - x2 * 0.5;
650
+ dst[1] = x0 + x2;
651
+ dst[0] = a1 + m1;
652
+ dst[2] = a1 - m1;
653
+ }
654
+ function l3Imdct12(x, xOff, dst, dOff, overlap, oOff) {
655
+ const co = [0, 0, 0];
656
+ const si = [0, 0, 0];
657
+ l3Idct3(-x[xOff], x[xOff + 6] + x[xOff + 3], x[xOff + 12] + x[xOff + 9], co);
658
+ l3Idct3(x[xOff + 15], x[xOff + 12] - x[xOff + 9], x[xOff + 6] - x[xOff + 3], si);
659
+ si[1] = -si[1];
660
+ const fr = Math.fround;
661
+ for (let i = 0; i < 3; i++) {
662
+ const ovl = overlap[oOff + i];
663
+ const sum = fr(fr(co[i] * G_TWID3[3 + i]) + fr(si[i] * G_TWID3[0 + i]));
664
+ overlap[oOff + i] = fr(fr(co[i] * G_TWID3[0 + i]) - fr(si[i] * G_TWID3[3 + i]));
665
+ dst[dOff + i] = fr(fr(ovl * G_TWID3[2 - i]) - fr(sum * G_TWID3[5 - i]));
666
+ dst[dOff + 5 - i] = fr(fr(ovl * G_TWID3[5 - i]) + fr(sum * G_TWID3[2 - i]));
667
+ }
668
+ }
669
+ // ---- L3_imdct_short (minimp3.h:1174-1185) ----
670
+ function l3ImdctShort(grbuf, gOff, overlap, oOff, nbands) {
671
+ for (; nbands > 0; nbands--, oOff += 9, gOff += 18) {
672
+ const tmp = new Float32Array(18);
673
+ for (let i = 0; i < 18; i++)
674
+ tmp[i] = grbuf[gOff + i];
675
+ for (let i = 0; i < 6; i++)
676
+ grbuf[gOff + i] = overlap[oOff + i];
677
+ l3Imdct12(tmp, 0, grbuf, gOff + 6, overlap, oOff + 6);
678
+ l3Imdct12(tmp, 1, grbuf, gOff + 12, overlap, oOff + 6);
679
+ l3Imdct12(tmp, 2, overlap, oOff, overlap, oOff + 6);
680
+ }
681
+ }
682
+ // ---- L3_change_sign (minimp3.h:1187-1193) ----
683
+ function l3ChangeSign(grbuf, gOff) {
684
+ for (let b = 0, bOff = gOff + 18; b < 32; b += 2, bOff += 36) {
685
+ for (let i = 1; i < 18; i += 2)
686
+ grbuf[bOff + i] = -grbuf[bOff + i];
687
+ }
688
+ }
689
+ // ---- L3_imdct_gr (minimp3.h:1195-1211) ----
690
+ function l3ImdctGr(grbuf, gOff, overlap, oOff, blockType, nLongBands) {
691
+ if (nLongBands !== 0) {
692
+ l3Imdct36(grbuf, gOff, overlap, oOff, G_MDCT_WINDOW[0], nLongBands);
693
+ gOff += 18 * nLongBands;
694
+ oOff += 9 * nLongBands;
695
+ }
696
+ if (blockType === SHORT_BLOCK_TYPE) {
697
+ l3ImdctShort(grbuf, gOff, overlap, oOff, 32 - nLongBands);
698
+ }
699
+ else {
700
+ l3Imdct36(grbuf, gOff, overlap, oOff, G_MDCT_WINDOW[blockType === STOP_BLOCK_TYPE ? 1 : 0], 32 - nLongBands);
701
+ }
702
+ }
703
+ // ---- L3_save_reservoir (minimp3.h:1213-1227) ----
704
+ function l3SaveReservoir(dec, maindata, bs) {
705
+ let pos = Math.trunc((bs.pos + 7) / 8);
706
+ let remains = Math.trunc(bs.limit / 8) - pos;
707
+ if (remains > MAX_BITRESERVOIR_BYTES) {
708
+ pos += remains - MAX_BITRESERVOIR_BYTES;
709
+ remains = MAX_BITRESERVOIR_BYTES;
710
+ }
711
+ if (remains > 0) {
712
+ for (let i = 0; i < remains; i++)
713
+ dec.reservBuf[i] = maindata[pos + i];
714
+ }
715
+ dec.reserv = remains;
716
+ }
717
+ // ---- L3_restore_reservoir (minimp3.h:1229-1237) ----
718
+ function l3RestoreReservoir(dec, bs, maindata, mainDataBegin) {
719
+ const frameBytes = Math.trunc((bs.limit - bs.pos) / 8);
720
+ const bytesHave = MINIMP3_MIN(dec.reserv, mainDataBegin);
721
+ const src = Math.max(0, dec.reserv - mainDataBegin);
722
+ const count = MINIMP3_MIN(dec.reserv, mainDataBegin);
723
+ for (let i = 0; i < count; i++)
724
+ maindata[i] = dec.reservBuf[src + i];
725
+ for (let i = 0; i < frameBytes; i++)
726
+ maindata[bytesHave + i] = bs.buf[(bs.pos >> 3) + i];
727
+ bsInit(bs, maindata, bytesHave + frameBytes);
728
+ return dec.reserv >= mainDataBegin;
729
+ }
730
+ // ---- L3_decode (minimp3.h:1239-1273) ----
731
+ function l3Decode(dec, bs, grInfo, nch, grbuf, scratch, reorderScratch, istPos) {
732
+ for (let ch = 0; ch < nch; ch++) {
733
+ const layer3grLimit = bs.pos + grInfo[ch].part23Length;
734
+ l3DecodeScalefactors(dec.header, istPos[ch], bs, grInfo[ch], scratch, ch);
735
+ l3Huffman(grbuf[ch], 0, bs, grInfo[ch], scratch, layer3grLimit);
736
+ }
737
+ if (hdrTestIStereo(dec.header)) {
738
+ l3IntensityStereo(grbuf[0], istPos, grInfo, dec.header);
739
+ }
740
+ else if (hdrIsMsStereo(dec.header)) {
741
+ l3MidsideStereo(grbuf[0], 576);
742
+ }
743
+ for (let ch = 0; ch < nch; ch++) {
744
+ const gi = grInfo[ch];
745
+ let aaBands = 31;
746
+ const nLongBands = (gi.mixedBlockFlag !== 0 ? 2 : 0) << (hdrGetMySampleRate(dec.header) === 2 ? 1 : 0);
747
+ if (gi.nShortSfb !== 0) {
748
+ aaBands = nLongBands - 1;
749
+ l3Reorder(grbuf[ch], nLongBands * 18, reorderScratch, 0, gi.sfbtab, gi.nLongSfb);
750
+ }
751
+ l3Antialias(grbuf[ch], 0, aaBands);
752
+ l3ImdctGr(grbuf[ch], 0, dec.mdctOverlap[ch], 0, gi.blockType, nLongBands);
753
+ l3ChangeSign(grbuf[ch], 0);
754
+ }
755
+ }
756
+ // ---- mp3d_DCT_II (minimp3.h:1275-1428) — scalar path ----
757
+ function mp3dDctII(grbuf, gOff, n) {
758
+ for (let k = 0; k < n; k++) {
759
+ const t = [[], [], [], []].map(() => new Array(8).fill(0));
760
+ let y = gOff + k;
761
+ const fr = Math.fround;
762
+ for (let i = 0; i < 8; i++) {
763
+ const x0 = grbuf[y + i * 18];
764
+ const x1 = grbuf[y + (15 - i) * 18];
765
+ const x2 = grbuf[y + (16 + i) * 18];
766
+ const x3 = grbuf[y + (31 - i) * 18];
767
+ const t0 = fr(x0 + x3);
768
+ const t1 = fr(x1 + x2);
769
+ const t2 = fr((x1 - x2) * G_SEC[3 * i + 0]);
770
+ const t3 = fr((x0 - x3) * G_SEC[3 * i + 1]);
771
+ // The C's x pointer walks t[0] flat: x[0] = t[0][i], x[8] = t[1][i],
772
+ // x[16] = t[2][i], x[24] = t[3][i].
773
+ t[0][i] = fr(t0 + t1);
774
+ t[1][i] = fr((t0 - t1) * G_SEC[3 * i + 2]);
775
+ t[2][i] = fr(t3 + t2);
776
+ t[3][i] = fr((t3 - t2) * G_SEC[3 * i + 2]);
777
+ }
778
+ for (let i = 0; i < 4; i++) {
779
+ const x = t[i];
780
+ let x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7];
781
+ let xt = fr(x0 - x7);
782
+ x0 = fr(x0 + x7);
783
+ x7 = fr(x1 - x6);
784
+ x1 = fr(x1 + x6);
785
+ x6 = fr(x2 - x5);
786
+ x2 = fr(x2 + x5);
787
+ x5 = fr(x3 - x4);
788
+ x3 = fr(x3 + x4);
789
+ x4 = fr(x0 - x3);
790
+ x0 = fr(x0 + x3);
791
+ x3 = fr(x1 - x2);
792
+ x1 = fr(x1 + x2);
793
+ x[0] = fr(x0 + x1);
794
+ x[4] = fr((x0 - x1) * 0.70710677);
795
+ x5 = fr(x5 + x6);
796
+ x6 = fr((x6 + x7) * 0.70710677);
797
+ x7 = fr(x7 + xt);
798
+ x3 = fr((x3 + x4) * 0.70710677);
799
+ x5 = fr(x5 - x7 * 0.198912367); // rotate by PI/8
800
+ x7 = fr(x7 + x5 * 0.382683432);
801
+ x5 = fr(x5 - x7 * 0.198912367);
802
+ x0 = fr(xt - x6);
803
+ xt = fr(xt + x6);
804
+ x[1] = fr((xt + x7) * 0.50979561);
805
+ x[2] = fr((x4 + x3) * 0.54119611);
806
+ x[3] = fr((x0 - x5) * 0.60134488);
807
+ x[5] = fr((x0 + x5) * 0.89997619);
808
+ x[6] = fr((x4 - x3) * 1.30656302);
809
+ x[7] = fr((xt - x7) * 2.56291556);
810
+ }
811
+ for (let i = 0; i < 7; i++, y += 4 * 18) {
812
+ grbuf[y + 0 * 18] = t[0][i];
813
+ grbuf[y + 1 * 18] = fr(t[2][i] + t[3][i] + t[3][i + 1]);
814
+ grbuf[y + 2 * 18] = fr(t[1][i] + t[1][i + 1]);
815
+ grbuf[y + 3 * 18] = fr(t[2][i + 1] + t[3][i] + t[3][i + 1]);
816
+ }
817
+ grbuf[y + 0 * 18] = t[0][7];
818
+ grbuf[y + 1 * 18] = fr(t[2][7] + t[3][7]);
819
+ grbuf[y + 2 * 18] = t[1][7];
820
+ grbuf[y + 3 * 18] = t[3][7];
821
+ }
822
+ }
823
+ // ---- mp3d_scale_pcm (int16 path, minimp3.h:1431-1444) ----
824
+ function mp3dScalePcm(sample) {
825
+ const f = Math.fround(sample);
826
+ if (f >= 32766.5)
827
+ return 32767;
828
+ if (f <= -32767.5)
829
+ return -32768;
830
+ // The C: (int16_t)(sample + .5f) — the addition happens in float32.
831
+ let s = Math.trunc(Math.fround(f + 0.5));
832
+ s -= s < 0 ? 1 : 0; // away from zero, to be compliant
833
+ return s;
834
+ }
835
+ // ---- mp3d_synth_pair (minimp3.h:1452-1475) ----
836
+ function mp3dSynthPair(pcm, pOff, z, zOff) {
837
+ const fr = Math.fround;
838
+ let a = 0;
839
+ a = fr(fr(z[zOff + 14 * 64] - z[zOff + 0]) * 29);
840
+ a = fr(a + fr(fr(z[zOff + 1 * 64] + z[zOff + 13 * 64]) * 213));
841
+ a = fr(a + fr(fr(z[zOff + 12 * 64] - z[zOff + 2 * 64]) * 459));
842
+ a = fr(a + fr(fr(z[zOff + 3 * 64] + z[zOff + 11 * 64]) * 2037));
843
+ a = fr(a + fr(fr(z[zOff + 10 * 64] - z[zOff + 4 * 64]) * 5153));
844
+ a = fr(a + fr(fr(z[zOff + 5 * 64] + z[zOff + 9 * 64]) * 6574));
845
+ a = fr(a + fr(fr(z[zOff + 8 * 64] - z[zOff + 6 * 64]) * 37489));
846
+ a = fr(a + fr(z[zOff + 7 * 64] * 75038));
847
+ pcm[pOff] = mp3dScalePcm(a);
848
+ const z2 = zOff + 2;
849
+ a = fr(z[z2 + 14 * 64] * 104);
850
+ a = fr(a + fr(z[z2 + 12 * 64] * 1567));
851
+ a = fr(a + fr(z[z2 + 10 * 64] * 9727));
852
+ a = fr(a + fr(z[z2 + 8 * 64] * 64019));
853
+ a = fr(a + fr(z[z2 + 6 * 64] * -9975));
854
+ a = fr(a + fr(z[z2 + 4 * 64] * -45));
855
+ a = fr(a + fr(z[z2 + 2 * 64] * 146));
856
+ a = fr(a + fr(z[z2 + 0 * 64] * -5));
857
+ pcm[pOff + 16] = mp3dScalePcm(a);
858
+ }
859
+ // ---- mp3d_synth (minimp3.h:1477-1628) — scalar path ----
860
+ function mp3dSynth(xl, xOff, pcm, dstlOff, nch, lins, lOff) {
861
+ // zlin = lins + 15*64 + lOff (the C's lins is already band-offset)
862
+ const Z = (idx) => lins[15 * 64 + lOff + idx];
863
+ const ZW = (idx, v) => { lins[15 * 64 + lOff + idx] = v; };
864
+ // xr = xl + 576*(nch-1)
865
+ const xr = xOff + 576 * (nch - 1);
866
+ const dstr = dstlOff + (nch - 1);
867
+ let wi = 0;
868
+ const a = [0, 0, 0, 0];
869
+ const b = [0, 0, 0, 0];
870
+ ZW(4 * 15, xl[xOff + 18 * 16]);
871
+ ZW(4 * 15 + 1, xl[xr + 18 * 16]);
872
+ ZW(4 * 15 + 2, xl[xOff + 0]);
873
+ ZW(4 * 15 + 3, xl[xr + 0]);
874
+ ZW(4 * 31, xl[xOff + 1 + 18 * 16]);
875
+ ZW(4 * 31 + 1, xl[xr + 1 + 18 * 16]);
876
+ ZW(4 * 31 + 2, xl[xOff + 1]);
877
+ ZW(4 * 31 + 3, xl[xr + 1]);
878
+ mp3dSynthPair(pcm, dstr, lins, lOff + 4 * 15 + 1);
879
+ mp3dSynthPair(pcm, dstr + 32 * nch, lins, lOff + 4 * 15 + 64 + 1);
880
+ mp3dSynthPair(pcm, dstlOff, lins, lOff + 4 * 15);
881
+ mp3dSynthPair(pcm, dstlOff + 32 * nch, lins, lOff + 4 * 15 + 64);
882
+ for (let i = 14; i >= 0; i--) {
883
+ ZW(4 * i, xl[xOff + 18 * (31 - i)]);
884
+ ZW(4 * i + 1, xl[xr + 18 * (31 - i)]);
885
+ ZW(4 * i + 2, xl[xOff + 1 + 18 * (31 - i)]);
886
+ ZW(4 * i + 3, xl[xr + 1 + 18 * (31 - i)]);
887
+ ZW(4 * (i + 16), xl[xOff + 1 + 18 * (1 + i)]);
888
+ ZW(4 * (i + 16) + 1, xl[xr + 1 + 18 * (1 + i)]);
889
+ ZW(4 * (i - 16) + 2, xl[xOff + 18 * (1 + i)]);
890
+ ZW(4 * (i - 16) + 3, xl[xr + 18 * (1 + i)]);
891
+ // S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7)
892
+ for (let k = 0; k < 8; k++) {
893
+ const w0 = G_WIN[wi++], w1 = G_WIN[wi++];
894
+ const vz = 4 * i - k * 64;
895
+ const vy = 4 * i - (15 - k) * 64;
896
+ const fr = Math.fround;
897
+ for (let j = 0; j < 4; j++) {
898
+ if (k === 0) {
899
+ b[j] = fr(fr(Z(vz + j) * w1) + fr(Z(vy + j) * w0));
900
+ a[j] = fr(fr(Z(vz + j) * w0) - fr(Z(vy + j) * w1));
901
+ }
902
+ else if (k % 2 === 1) {
903
+ // S2
904
+ b[j] = fr(b[j] + fr(fr(Z(vz + j) * w1) + fr(Z(vy + j) * w0)));
905
+ a[j] = fr(a[j] + fr(fr(Z(vy + j) * w1) - fr(Z(vz + j) * w0)));
906
+ }
907
+ else {
908
+ // S1
909
+ b[j] = fr(b[j] + fr(fr(Z(vz + j) * w1) + fr(Z(vy + j) * w0)));
910
+ a[j] = fr(a[j] + fr(fr(Z(vz + j) * w0) - fr(Z(vy + j) * w1)));
911
+ }
912
+ }
913
+ }
914
+ pcm[dstr + (15 - i) * nch] = mp3dScalePcm(a[1]);
915
+ pcm[dstr + (17 + i) * nch] = mp3dScalePcm(b[1]);
916
+ pcm[dstlOff + (15 - i) * nch] = mp3dScalePcm(a[0]);
917
+ pcm[dstlOff + (17 + i) * nch] = mp3dScalePcm(b[0]);
918
+ pcm[dstr + (47 - i) * nch] = mp3dScalePcm(a[3]);
919
+ pcm[dstr + (49 + i) * nch] = mp3dScalePcm(b[3]);
920
+ pcm[dstlOff + (47 - i) * nch] = mp3dScalePcm(a[2]);
921
+ pcm[dstlOff + (49 + i) * nch] = mp3dScalePcm(b[2]);
922
+ }
923
+ }
924
+ // ---- mp3d_synth_granule (minimp3.h:1630-1656) ----
925
+ function mp3dSynthGranule(dec, grbuf, nbands, nch, pcm, pOff, lins) {
926
+ for (let i = 0; i < nch; i++) {
927
+ mp3dDctII(grbuf, 576 * i, nbands);
928
+ }
929
+ for (let i = 0; i < 15 * 64; i++)
930
+ lins[i] = dec.qmfState[i];
931
+ for (let i = 0; i < nbands; i += 2) {
932
+ mp3dSynth(grbuf, i, pcm, pOff + 32 * nch * i, nch, lins, i * 64);
933
+ }
934
+ if (nch === 1) {
935
+ for (let i = 0; i < 15 * 64; i += 2) {
936
+ dec.qmfState[i] = lins[nbands * 64 + i];
937
+ }
938
+ }
939
+ else {
940
+ for (let i = 0; i < 15 * 64; i++) {
941
+ dec.qmfState[i] = lins[nbands * 64 + i];
942
+ }
943
+ }
944
+ }
945
+ // ---- frame parsing (minimp3.h:1658-1724) ----
946
+ function hdrIsTag(h) {
947
+ return h[0] === 0x54 && h[1] === 0x41 && h[2] === 0x47 && h[3] === 0;
948
+ }
949
+ function hdrIsNull(h) {
950
+ return h[0] === 0 && h[1] === 0 && h[2] === 0 && h[3] === 0;
951
+ }
952
+ function hdrIsNullOrTag(h) {
953
+ return hdrIsTag(h) || hdrIsNull(h);
954
+ }
955
+ function hdrCompare(h1, h2) {
956
+ return hdrIsValid(h2) &&
957
+ ((h1[1] ^ h2[1]) & 0xfe) === 0 &&
958
+ ((h1[2] ^ h2[2]) & 0x0c) === 0 &&
959
+ (hdrIsFreeFormat(h1) === hdrIsFreeFormat(h2));
960
+ }
961
+ function mp3dMatchFrame(hdr, mp3Bytes, frameBytes) {
962
+ let i = 0;
963
+ for (let nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) {
964
+ i += hdrFrameBytes(hdr.subarray(i), frameBytes) + hdrPadding(hdr.subarray(i));
965
+ if (i + HDR_SIZE > mp3Bytes)
966
+ return nmatch > 0;
967
+ if (hdrIsNullOrTag(hdr.subarray(i)))
968
+ return nmatch > 0;
969
+ if (!hdrCompare(hdr, hdr.subarray(i)))
970
+ return false;
971
+ }
972
+ return true;
973
+ }
974
+ function mp3dFindFrame(mp3, mp3Bytes, freeFormatBytes, ptrFrameBytes) {
975
+ let i = 0;
976
+ for (; i < mp3Bytes - HDR_SIZE; i++) {
977
+ const h = mp3.subarray(i);
978
+ if (hdrIsValid(h)) {
979
+ let frameBytes = hdrFrameBytes(h, freeFormatBytes.v);
980
+ let frameAndPadding = frameBytes + hdrPadding(h);
981
+ for (let k = HDR_SIZE; !frameBytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2 * k < mp3Bytes - HDR_SIZE; k++) {
982
+ if (hdrCompare(h, mp3.subarray(i + k))) {
983
+ const fb = k - hdrPadding(h);
984
+ const nextfb = fb + hdrPadding(mp3.subarray(i + k));
985
+ if (i + k + nextfb + HDR_SIZE > mp3Bytes || !hdrCompare(h, mp3.subarray(i + k + nextfb)))
986
+ continue;
987
+ frameAndPadding = k;
988
+ frameBytes = fb;
989
+ freeFormatBytes.v = fb;
990
+ }
991
+ }
992
+ if ((frameBytes !== 0 && i + frameAndPadding <= mp3Bytes &&
993
+ mp3dMatchFrame(h, mp3Bytes - i, frameBytes)) ||
994
+ (i === 0 && frameAndPadding === mp3Bytes)) {
995
+ ptrFrameBytes.v = frameAndPadding;
996
+ return i;
997
+ }
998
+ freeFormatBytes.v = 0;
999
+ }
1000
+ }
1001
+ ptrFrameBytes.v = 0;
1002
+ return mp3Bytes;
1003
+ }
1004
+ export function mp3decDecodeFrame(dec, mp3, mp3Bytes, pcm, info) {
1005
+ let i = 0;
1006
+ let frameSize = 0;
1007
+ let success = true;
1008
+ const bsFrame = { buf: mp3, pos: 0, limit: 0 };
1009
+ // +16 zero bytes: the C's L3_huffman CHECK_BITS can read past the
1010
+ // reservoir end (uninitialized scratch in C); keep the reads defined.
1011
+ const maindata = new Uint8Array(MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES + 16);
1012
+ const grbuf = [new Float32Array(576), new Float32Array(576)];
1013
+ const scf = new Float32Array(40);
1014
+ const syn = new Float32Array((18 + 15) * 2 * 32); // syn[18+15][2*32]
1015
+ const istPos = [new Uint8Array(39), new Uint8Array(39)];
1016
+ const grInfo = [newGrInfo(), newGrInfo(), newGrInfo(), newGrInfo()];
1017
+ if (mp3Bytes > 4 && dec.header[0] === 0xff && hdrCompare(dec.header, mp3)) {
1018
+ frameSize = hdrFrameBytes(mp3, dec.freeFormatBytes) + hdrPadding(mp3);
1019
+ if (frameSize !== mp3Bytes && (frameSize + HDR_SIZE > mp3Bytes || !hdrCompare(mp3, mp3.subarray(frameSize)))) {
1020
+ frameSize = 0;
1021
+ }
1022
+ }
1023
+ if (frameSize === 0) {
1024
+ mp3decInit(dec);
1025
+ const ffRef = { v: dec.freeFormatBytes };
1026
+ const fbRef = { v: 0 };
1027
+ i = mp3dFindFrame(mp3, mp3Bytes, ffRef, fbRef);
1028
+ dec.freeFormatBytes = ffRef.v;
1029
+ if (fbRef.v === 0 || i + fbRef.v > mp3Bytes) {
1030
+ info.frameBytes = i;
1031
+ return 0;
1032
+ }
1033
+ frameSize = fbRef.v;
1034
+ }
1035
+ const hdr = mp3.subarray(i);
1036
+ dec.header.set(hdr.subarray(0, HDR_SIZE));
1037
+ info.frameBytes = i + frameSize;
1038
+ info.channels = hdrIsMono(hdr) ? 1 : 2;
1039
+ info.hz = hdrSampleRateHz(hdr);
1040
+ info.layer = 4 - hdrGetLayer(hdr);
1041
+ info.bitrateKbps = hdrBitrateKbps(hdr);
1042
+ bsInit(bsFrame, hdr.subarray(HDR_SIZE), frameSize - HDR_SIZE);
1043
+ if (hdrIsCrc(hdr))
1044
+ getBits(bsFrame, 16);
1045
+ if (info.layer === 3) {
1046
+ const mainDataBegin = l3ReadSideInfo(bsFrame, grInfo, hdr);
1047
+ if (mainDataBegin < 0 || bsFrame.pos > bsFrame.limit) {
1048
+ mp3decInit(dec);
1049
+ return 0;
1050
+ }
1051
+ success = l3RestoreReservoir(dec, bsFrame, maindata, mainDataBegin);
1052
+ if (success) {
1053
+ const granules = hdrTestMpeg1(hdr) ? 2 : 1;
1054
+ for (let igr = 0, pcmOff = 0; igr < granules; igr++, pcmOff += 576 * info.channels) {
1055
+ grbuf[0].fill(0);
1056
+ grbuf[1].fill(0);
1057
+ l3Decode(dec, bsFrame, grInfo.slice(igr * info.channels), info.channels, grbuf, scf, syn, istPos);
1058
+ mp3dSynthGranule(dec, grbuf[0], 18, info.channels, pcm, pcmOff, syn);
1059
+ }
1060
+ }
1061
+ l3SaveReservoir(dec, maindata, bsFrame);
1062
+ }
1063
+ else {
1064
+ return 0; // Layer 1/2: not needed for MO3 samples (always Layer 3)
1065
+ }
1066
+ return success ? hdrFrameSamples(dec.header) : 0;
1067
+ }
1068
+ //# sourceMappingURL=minimp3.js.map