@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,80 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: OpenMPT soundlib/MPEGFrame.cpp (BSD-3-Clause).
4
+ //
5
+ // Basic MPEG frame header parsing — used by the MO3 loader to find LAME
6
+ // info frames and frame boundaries before decoding MP3 sample data.
7
+ /** Samples per frame — for each MPEG version and all three layers. */
8
+ const SAMPLES_PER_FRAME = [
9
+ [384, 1152, 1152], // MPEG 1
10
+ [384, 1152, 576], // MPEG 2 / 2.5
11
+ ];
12
+ const BIT_RATES = [
13
+ // MPEG 1
14
+ [
15
+ [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448], // Layer 1
16
+ [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384], // Layer 2
17
+ [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320], // Layer 3
18
+ ],
19
+ // MPEG 2 / 2.5
20
+ [
21
+ [0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256], // Layer 1
22
+ [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], // Layer 2
23
+ [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], // Layer 3
24
+ ],
25
+ ];
26
+ const SAMPLING_RATES = [
27
+ [11025, 12000, 8000], // MPEG 2.5
28
+ [0, 0, 0], // Invalid
29
+ [22050, 24000, 16000], // MPEG 2
30
+ [44100, 48000, 32000], // MPEG 1
31
+ ];
32
+ /** Samples per frame / 8. */
33
+ /** Side info size = offset in frame where Xing/Info magic starts. */
34
+ const SIDE_INFO_SIZE = [
35
+ [17, 32], // MPEG 1
36
+ [9, 17], // MPEG 2 / 2.5
37
+ ];
38
+ export function isMPEGHeader(header, off = 0) {
39
+ return (header[off] === 0xff &&
40
+ (header[off + 1] & 0xe0) === 0xe0 && // Sync
41
+ (header[off + 1] & 0x18) !== 0x08 && // Invalid MPEG version
42
+ (header[off + 1] & 0x06) !== 0x00 && // Invalid MPEG layer
43
+ (header[off + 2] & 0x0c) !== 0x0c && // Invalid frequency
44
+ (header[off + 2] & 0xf0) !== 0xf0 // Invalid bitrate
45
+ );
46
+ }
47
+ /** Parse the frame header at `off`; null if not an MPEG header. */
48
+ export function parseMPEGFrame(data, off = 0) {
49
+ if (off + 4 > data.length || !isMPEGHeader(data, off))
50
+ return null;
51
+ const b1 = data[off + 1];
52
+ const b2 = data[off + 2];
53
+ const mpegVersion = (b1 & 0x18) >> 3; // 0=2.5, 2=2, 3=1
54
+ const layer = 3 - ((b1 & 0x06) >> 1); // 0..2 (index into tables)
55
+ const bitrateIndex = (b2 & 0xf0) >> 4;
56
+ const samplerateIndex = (b2 & 0x0c) >> 2;
57
+ const padding = (b2 & 0x02) >> 1;
58
+ const mpegId = mpegVersion === 3 ? 0 : 1; // 0 = MPEG 1 table row, 1 = MPEG 2/2.5
59
+ const sampleRate = SAMPLING_RATES[mpegVersion][samplerateIndex];
60
+ if (sampleRate === 0)
61
+ return null;
62
+ const bitRate = (BIT_RATES[mpegId][layer][bitrateIndex] * 1000) / 8;
63
+ const frameSize = Math.floor((bitRate * SAMPLES_PER_FRAME[mpegId][layer]) / sampleRate) + padding;
64
+ const numSamples = SAMPLES_PER_FRAME[mpegId][layer];
65
+ // LAME/Xing info frame detection (MPEGFrame.cpp:120-140)
66
+ let isLAME = false;
67
+ if (layer === 2 /* Layer 3 */) {
68
+ const sideInfo = SIDE_INFO_SIZE[mpegId][mpegId === 0 ? 1 : 0];
69
+ const magicOff = off + 4 + sideInfo;
70
+ if (magicOff + 4 <= data.length) {
71
+ const magic = String.fromCharCode(data[magicOff], data[magicOff + 1], data[magicOff + 2], data[magicOff + 3]);
72
+ if (magic === 'Xing' || magic === 'Info')
73
+ isLAME = true;
74
+ // LAME frames also carry the "LAME3." string further in; OpenMPT
75
+ // checks the Xing/Info magic only for the flag we need.
76
+ }
77
+ }
78
+ return { frameSize, numSamples, sampleRate, isLAME };
79
+ }
80
+ //# sourceMappingURL=mpegFrame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mpegFrame.js","sourceRoot":"","sources":["../src/mpegFrame.ts"],"names":[],"mappings":"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"}
package/dist/ogg.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Merge a shared vorbis header chunk with the sample data chunk:
3
+ * the header pages are rewritten with the DATA chunk's bitstream serial
4
+ * numbers (Load_mo3.cpp:1788-1848 optimized path), then the data bytes
5
+ * follow verbatim. Returns null when the header cannot be validated.
6
+ */
7
+ export declare function mergeSharedOggHeader(headerBytes: Uint8Array, headerSize: number, dataBytes: Uint8Array, dataOff: number, dataSize: number): Uint8Array | null;
8
+ /** Decode a complete Ogg Vorbis stream (header + data in one buffer) to
9
+ * interleaved float samples, mirroring the C stb_vorbis decode loop
10
+ * (Load_mo3.cpp:1943-1988). */
11
+ export declare function decodeOggStream(merged: Uint8Array, wantFrames: number, channels: number): Float32Array | null;
12
+ //# sourceMappingURL=ogg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ogg.d.ts","sourceRoot":"","sources":["../src/ogg.ts"],"names":[],"mappings":"AA8HA;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAC3C,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GACvD,UAAU,GAAG,IAAI,CA6CnB;AAED;;gCAEgC;AAChC,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAsB7G"}
package/dist/ogg.js ADDED
@@ -0,0 +1,206 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // MO3 Ogg-Vorbis sample decode (Load_mo3.cpp:1688-1970, stb_vorbis path).
3
+ //
4
+ // C reference behaviour mirrored here:
5
+ // - Non-shared samples: the chunk is a complete Ogg Vorbis stream.
6
+ // - Shared-header samples (MO3 v5): the sample's header (identification
7
+ // + comment + setup packets) lives in another sample's chunk, in
8
+ // `encoderDelay` bytes at that sample's start, and the audio packets
9
+ // live here. OpenMPT remuxes the header chunk's pages with the DATA
10
+ // chunk's bitstream serial numbers and stitches both into one buffer
11
+ // before feeding a single vorbis decoder (Load_mo3.cpp:1767-1875,
12
+ // "optimized" variant). We port that optimized path 1:1.
13
+ import { stbVorbisOpenMemory, stbVorbisGetFrameFloat } from '@modplayjs/stb-vorbis';
14
+ /** mpt::crc32_ogg = CRC-32 with polynomial 0x04C11DB7, init 0, MSB-first,
15
+ * no final XOR — the Ogg page CRC (crc.hpp:194). */
16
+ const CRC_TABLE = /* computed lazily */ buildCrcTable();
17
+ function buildCrcTable() {
18
+ const table = new Uint32Array(256);
19
+ for (let i = 0; i < 256; i++) {
20
+ let value = (i << 24) >>> 0;
21
+ for (let bit = 0; bit < 8; bit++) {
22
+ value = value & 0x80000000 ? ((value << 1) >>> 0) ^ 0x04c11db7 : (value << 1) >>> 0;
23
+ }
24
+ table[i] = value >>> 0;
25
+ }
26
+ return table;
27
+ }
28
+ function crcOgg(data, from = 0, to = data.length) {
29
+ let value = 0;
30
+ for (let i = from; i < to; i++) {
31
+ value = (((value << 8) >>> 0) ^ (CRC_TABLE[((value >>> 24) & 0xff) ^ data[i]] ?? 0)) >>> 0;
32
+ }
33
+ return value >>> 0;
34
+ }
35
+ function u32le(b, off) {
36
+ return (b[off] | (b[off + 1] << 8) | (b[off + 2] << 16) | (b[off + 3] << 24)) >>> 0;
37
+ }
38
+ /** Ogg::ReadPage — parse one "OggS" page. Returns null on any structural
39
+ * or CRC error (corrupted pages are dropped per the Ogg spec). */
40
+ function readPage(b, pos) {
41
+ if (pos + 27 > b.length)
42
+ return null;
43
+ const flag = b[pos + 5];
44
+ const granule0 = u32le(b, pos + 6);
45
+ const granule1 = u32le(b, pos + 10);
46
+ const serial = u32le(b, pos + 14);
47
+ const sequence = u32le(b, pos + 18);
48
+ const storedCrc = u32le(b, pos + 22);
49
+ const segmentCount = b[pos + 26];
50
+ if (pos + 27 + segmentCount > b.length)
51
+ return null;
52
+ const segmentTable = b.subarray(pos + 27, pos + 27 + segmentCount);
53
+ let dataSize = 0;
54
+ for (let i = 0; i < segmentCount; i++)
55
+ dataSize += segmentTable[i];
56
+ const end = pos + 27 + segmentCount + dataSize;
57
+ if (end > b.length)
58
+ return null;
59
+ // CRC over the header with the checksum field zeroed, the segment table
60
+ // and the payload (OggStream.cpp:116-137). A stored checksum of 0 is
61
+ // treated as valid only for zero-length verification; C always compares.
62
+ const raw = b.subarray(pos, end);
63
+ const scratch = new Uint8Array(raw.length);
64
+ scratch.set(raw);
65
+ scratch[22] = 0;
66
+ scratch[23] = 0;
67
+ scratch[24] = 0;
68
+ scratch[25] = 0;
69
+ if (storedCrc !== crcOgg(scratch))
70
+ return null;
71
+ return {
72
+ page: {
73
+ serial, sequence, flag,
74
+ granule0, granule1,
75
+ segmentTable,
76
+ data: b.subarray(pos + 27 + segmentCount, end),
77
+ },
78
+ end,
79
+ };
80
+ }
81
+ /** Ogg::ReadPageAndSkipJunk — find the next valid page from pos. */
82
+ function readPageAndSkipJunk(b, pos) {
83
+ let p = pos;
84
+ while (p + 4 <= b.length) {
85
+ if (b[p] === 0x4f && b[p + 1] === 0x67 && b[p + 2] === 0x67 && b[p + 3] === 0x53) {
86
+ const r = readPage(b, p);
87
+ if (r)
88
+ return r;
89
+ p += 4;
90
+ }
91
+ else {
92
+ p++;
93
+ }
94
+ }
95
+ return null;
96
+ }
97
+ /** Serialize a page (header + segments + data) with CRC applied. */
98
+ function serializePage(page, newSerial) {
99
+ const headerSize = 27 + page.segmentTable.length;
100
+ const total = headerSize + page.data.length;
101
+ const raw = new Uint8Array(total);
102
+ raw[0] = 0x4f;
103
+ raw[1] = 0x67;
104
+ raw[2] = 0x67;
105
+ raw[3] = 0x53;
106
+ raw[4] = 0; // stream structure version
107
+ raw[5] = page.flag;
108
+ // granule 64-bit LE
109
+ let g0 = page.granule0 >>> 0, g1 = page.granule1 >>> 0;
110
+ for (let i = 0; i < 8; i++)
111
+ raw[6 + i] = i < 4 ? (g0 >>> (i * 8)) & 0xff : (g1 >>> ((i - 4) * 8)) & 0xff;
112
+ raw.set([newSerial & 0xff, (newSerial >>> 8) & 0xff, (newSerial >>> 16) & 0xff, (newSerial >>> 24) & 0xff], 14);
113
+ raw.set([page.sequence & 0xff, (page.sequence >>> 8) & 0xff, (page.sequence >>> 16) & 0xff, (page.sequence >>> 24) & 0xff], 18);
114
+ // page_segments count lives at offset 26.
115
+ raw[26] = page.segmentTable.length;
116
+ raw.set(page.segmentTable, 27);
117
+ raw.set(page.data, headerSize);
118
+ raw[22] = raw[23] = raw[24] = raw[25] = 0;
119
+ const c = crcOgg(raw);
120
+ raw.set([c & 0xff, (c >>> 8) & 0xff, (c >>> 16) & 0xff, (c >>> 24) & 0xff], 22);
121
+ return raw;
122
+ }
123
+ /**
124
+ * Merge a shared vorbis header chunk with the sample data chunk:
125
+ * the header pages are rewritten with the DATA chunk's bitstream serial
126
+ * numbers (Load_mo3.cpp:1788-1848 optimized path), then the data bytes
127
+ * follow verbatim. Returns null when the header cannot be validated.
128
+ */
129
+ export function mergeSharedOggHeader(headerBytes, headerSize, dataBytes, dataOff, dataSize) {
130
+ // 1. Gather data stream serials (C dataStreamSerials).
131
+ const dataSerials = [];
132
+ for (let p = readPageAndSkipJunk(dataBytes, dataOff); p; p = readPageAndSkipJunk(dataBytes, p.end)) {
133
+ if (!dataSerials.includes(p.page.serial))
134
+ dataSerials.push(p.page.serial);
135
+ }
136
+ if (dataSerials.length > 1) {
137
+ // C logs a warning; multiple logical bitstreams may be mishandled.
138
+ }
139
+ // 2. Read the header chunk pages up to headerSize, renumbering serials.
140
+ const view = headerBytes.subarray(0, headerSize);
141
+ const out = [];
142
+ let headIndex = 0;
143
+ for (let p = readPageAndSkipJunk(view, 0); p; p = readPageAndSkipJunk(view, p.end)) {
144
+ const it = headIndex;
145
+ headIndex++;
146
+ const idx = it;
147
+ let newSerial = 0;
148
+ if (idx < dataSerials.length) {
149
+ // Found corresponding stream in the data chunk.
150
+ newSerial = dataSerials[idx];
151
+ }
152
+ else {
153
+ // No corresponding stream in the data chunk: find a free serial
154
+ // (Load_mo3.cpp:1822-1836).
155
+ let extraIndex = idx - dataSerials.length;
156
+ for (newSerial = 1; newSerial < 0xffffffff; ++newSerial) {
157
+ if (!dataSerials.includes(newSerial)) {
158
+ extraIndex -= 1;
159
+ }
160
+ if (extraIndex === 0) {
161
+ break;
162
+ }
163
+ }
164
+ }
165
+ out.push(...serializePage(p.page, newSerial));
166
+ void it;
167
+ }
168
+ if (out.length === 0)
169
+ return null;
170
+ const merged = new Uint8Array(out.length + dataSize);
171
+ let o = 0;
172
+ for (const v of out)
173
+ merged[o++] = v;
174
+ merged.set(dataBytes.subarray(dataOff, dataOff + dataSize), o);
175
+ return merged;
176
+ }
177
+ /** Decode a complete Ogg Vorbis stream (header + data in one buffer) to
178
+ * interleaved float samples, mirroring the C stb_vorbis decode loop
179
+ * (Load_mo3.cpp:1943-1988). */
180
+ export function decodeOggStream(merged, wantFrames, channels) {
181
+ const err = { v: 0 };
182
+ const vor = stbVorbisOpenMemory(merged, err);
183
+ if (!vor)
184
+ return null;
185
+ if (vor.channels !== channels) {
186
+ // C: channels must match the sample's channel count.
187
+ return null;
188
+ }
189
+ const out = new Float32Array(wantFrames * channels);
190
+ let offset = 0;
191
+ const len = { v: 0 };
192
+ while (offset < wantFrames) {
193
+ const outputs = stbVorbisGetFrameFloat(vor, len);
194
+ if (!outputs || len.v === 0)
195
+ break;
196
+ const n = Math.min(len.v, wantFrames - offset);
197
+ for (let ch = 0; ch < channels; ch++) {
198
+ const src = outputs[ch];
199
+ for (let j = 0; j < n; j++)
200
+ out[(offset + j) * channels + ch] = src[j];
201
+ }
202
+ offset += n;
203
+ }
204
+ return offset > 0 ? out.subarray(0, offset * channels) : null;
205
+ }
206
+ //# sourceMappingURL=ogg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ogg.js","sourceRoot":"","sources":["../src/ogg.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@modplayjs/fmt-mo3",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.1",
4
+ "description": "Un4seen MO3 container (XM/IT/S3M/MOD/MTM inner) format plugin for modplayjs (OpenMPT Load_mo3.cpp port).",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./minimp3.js": {
14
+ "types": "./dist/minimp3.d.ts",
15
+ "import": "./dist/minimp3.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.build.json",
23
+ "typecheck": "tsc -p tsconfig.json --noEmit"
24
+ },
25
+ "dependencies": {
26
+ "@modplayjs/core": "^0.2.1",
27
+ "@modplayjs/fmt-mod": "^0.2.1",
28
+ "@modplayjs/stb-vorbis": "^0.2.1"
29
+ },
30
+ "keywords": [
31
+ "mo3",
32
+ "stm",
33
+ "scream tracker",
34
+ "libxmp",
35
+ "chiptune",
36
+ "audio",
37
+ "music"
38
+ ],
39
+ "sideEffects": false,
40
+ "engines": {
41
+ "node": ">=18"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/modplayjs/modplayjs.git",
46
+ "directory": "packages/fmt-mo3"
47
+ },
48
+ "bugs": "https://github.com/modplayjs/modplayjs/issues",
49
+ "homepage": "https://github.com/modplayjs/modplayjs#readme",
50
+ "license": "BSD-3-Clause",
51
+ "publishConfig": {
52
+ "registry": "https://npm.pkg.github.com"
53
+ }
54
+ }