@modplayjs/fmt-prowizard 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.
Files changed (110) hide show
  1. package/README.md +42 -2
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +7 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/prowiz.d.ts +44 -0
  7. package/dist/prowiz.d.ts.map +1 -0
  8. package/dist/prowiz.js +157 -0
  9. package/dist/prowiz.js.map +1 -0
  10. package/dist/ptktable.d.ts +5 -0
  11. package/dist/ptktable.d.ts.map +1 -0
  12. package/dist/ptktable.js +49 -0
  13. package/dist/ptktable.js.map +1 -0
  14. package/dist/pw-ac1d.d.ts +4 -0
  15. package/dist/pw-ac1d.d.ts.map +1 -0
  16. package/dist/pw-ac1d.js +133 -0
  17. package/dist/pw-ac1d.js.map +1 -0
  18. package/dist/pw-di.d.ts +4 -0
  19. package/dist/pw-di.d.ts.map +1 -0
  20. package/dist/pw-di.js +177 -0
  21. package/dist/pw-di.js.map +1 -0
  22. package/dist/pw-eureka.d.ts +4 -0
  23. package/dist/pw-eureka.d.ts.map +1 -0
  24. package/dist/pw-eureka.js +171 -0
  25. package/dist/pw-eureka.js.map +1 -0
  26. package/dist/pw-fcm.d.ts +4 -0
  27. package/dist/pw-fcm.d.ts.map +1 -0
  28. package/dist/pw-fcm.js +102 -0
  29. package/dist/pw-fcm.js.map +1 -0
  30. package/dist/pw-fuchs.d.ts +4 -0
  31. package/dist/pw-fuchs.d.ts.map +1 -0
  32. package/dist/pw-fuchs.js +139 -0
  33. package/dist/pw-fuchs.js.map +1 -0
  34. package/dist/pw-heatseek.d.ts +4 -0
  35. package/dist/pw-heatseek.d.ts.map +1 -0
  36. package/dist/pw-heatseek.js +197 -0
  37. package/dist/pw-heatseek.js.map +1 -0
  38. package/dist/pw-hrt.d.ts +4 -0
  39. package/dist/pw-hrt.d.ts.map +1 -0
  40. package/dist/pw-hrt.js +104 -0
  41. package/dist/pw-hrt.js.map +1 -0
  42. package/dist/pw-ksm.d.ts +4 -0
  43. package/dist/pw-ksm.d.ts.map +1 -0
  44. package/dist/pw-ksm.js +212 -0
  45. package/dist/pw-ksm.js.map +1 -0
  46. package/dist/pw-mp.d.ts +6 -0
  47. package/dist/pw-mp.d.ts.map +1 -0
  48. package/dist/pw-mp.js +171 -0
  49. package/dist/pw-mp.js.map +1 -0
  50. package/dist/pw-np12.d.ts +6 -0
  51. package/dist/pw-np12.d.ts.map +1 -0
  52. package/dist/pw-np12.js +234 -0
  53. package/dist/pw-np12.js.map +1 -0
  54. package/dist/pw-np3.d.ts +4 -0
  55. package/dist/pw-np3.d.ts.map +1 -0
  56. package/dist/pw-np3.js +218 -0
  57. package/dist/pw-np3.js.map +1 -0
  58. package/dist/pw-p40.d.ts +4 -0
  59. package/dist/pw-p40.d.ts.map +1 -0
  60. package/dist/pw-p40.js +221 -0
  61. package/dist/pw-p40.js.map +1 -0
  62. package/dist/pw-plugin.d.ts +8 -0
  63. package/dist/pw-plugin.d.ts.map +1 -0
  64. package/dist/pw-plugin.js +27 -0
  65. package/dist/pw-plugin.js.map +1 -0
  66. package/dist/pw-pp.d.ts +8 -0
  67. package/dist/pw-pp.d.ts.map +1 -0
  68. package/dist/pw-pp.js +341 -0
  69. package/dist/pw-pp.js.map +1 -0
  70. package/dist/pw-skyt.d.ts +4 -0
  71. package/dist/pw-skyt.d.ts.map +1 -0
  72. package/dist/pw-skyt.js +116 -0
  73. package/dist/pw-skyt.js.map +1 -0
  74. package/dist/pw-starpack.d.ts +4 -0
  75. package/dist/pw-starpack.d.ts.map +1 -0
  76. package/dist/pw-starpack.js +253 -0
  77. package/dist/pw-starpack.js.map +1 -0
  78. package/dist/pw-theplayer.d.ts +6 -0
  79. package/dist/pw-theplayer.d.ts.map +1 -0
  80. package/dist/pw-theplayer.js +367 -0
  81. package/dist/pw-theplayer.js.map +1 -0
  82. package/dist/pw-tp1.d.ts +4 -0
  83. package/dist/pw-tp1.d.ts.map +1 -0
  84. package/dist/pw-tp1.js +162 -0
  85. package/dist/pw-tp1.js.map +1 -0
  86. package/dist/pw-tp3.d.ts +6 -0
  87. package/dist/pw-tp3.d.ts.map +1 -0
  88. package/dist/pw-tp3.js +217 -0
  89. package/dist/pw-tp3.js.map +1 -0
  90. package/dist/pw-unic.d.ts +8 -0
  91. package/dist/pw-unic.d.ts.map +1 -0
  92. package/dist/pw-unic.js +285 -0
  93. package/dist/pw-unic.js.map +1 -0
  94. package/dist/pw-unic2.d.ts +4 -0
  95. package/dist/pw-unic2.d.ts.map +1 -0
  96. package/dist/pw-unic2.js +173 -0
  97. package/dist/pw-unic2.js.map +1 -0
  98. package/dist/pw-wn.d.ts +4 -0
  99. package/dist/pw-wn.d.ts.map +1 -0
  100. package/dist/pw-wn.js +82 -0
  101. package/dist/pw-wn.js.map +1 -0
  102. package/dist/pw-xann.d.ts +4 -0
  103. package/dist/pw-xann.d.ts.map +1 -0
  104. package/dist/pw-xann.js +220 -0
  105. package/dist/pw-xann.js.map +1 -0
  106. package/dist/pw-zen.d.ts +4 -0
  107. package/dist/pw-zen.d.ts.map +1 -0
  108. package/dist/pw-zen.js +162 -0
  109. package/dist/pw-zen.js.map +1 -0
  110. package/package.json +49 -4
package/dist/pw-di.js ADDED
@@ -0,0 +1,177 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: libxmp src/loaders/prowizard/di.c (Digital Illusions) —
4
+ // write_event :34-59, depack_di :61-159, test_di :165-268.
5
+ import { ptkTable, ptkIsValidNote } from './ptktable.js';
6
+ import { readmem16b, readmem32b, moveData, writeZero, pwReadTitle } from './prowiz.js';
7
+ const PW_MOD_MAGIC = 0x4d2e4b2e; // 'M.K.'
8
+ function put8(out, b) { out.push(b & 0xff); }
9
+ function put16b(out, v) { out.push((v >> 8) & 0xff, v & 0xff); }
10
+ function put32b(out, v) {
11
+ out.push((v >>> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff);
12
+ }
13
+ /** write_event (di.c:34-59): 3 input bytes → 4-byte PTK cell. */
14
+ function writeEvent(out, c1, c2, fxp) {
15
+ const note = ((c1 << 4) & 0x30) | ((c2 >> 4) & 0x0f);
16
+ if (!ptkIsValidNote(note)) {
17
+ // di.nightmare has note 49! (di.c:39-44)
18
+ out.push(0, 0, 0, 0);
19
+ return;
20
+ }
21
+ const ins = (c1 >> 2) & 0x1f;
22
+ const fxt = c2 & 0x0f;
23
+ out.push((ptkTable[note][0] | (ins & 0xf0)) & 0xff);
24
+ out.push(ptkTable[note][1]);
25
+ out.push((((ins << 4) & 0xf0) | fxt) & 0xff);
26
+ out.push(fxp & 0xff);
27
+ }
28
+ /** depack_di (di.c:61-159). */
29
+ function depackDi(data, start) {
30
+ let pos = start;
31
+ const out = [];
32
+ const u8 = () => data[pos++] ?? 0;
33
+ const u16 = () => { const v = readmem16b(data, pos); pos += 2; return v; };
34
+ const u32 = () => { const v = readmem32b(data, pos); pos += 4; return v; };
35
+ writeZero(out, 20); // title
36
+ const nins = u16();
37
+ if (nins > 31)
38
+ throw new Error('di: too many samples');
39
+ const seqOfs = u32();
40
+ u32(); // pat_offs
41
+ const smpOfs = u32();
42
+ // Sample headers (di.c:81-89)
43
+ let ssize = 0;
44
+ for (let i = 0; i < nins; i++) {
45
+ writeZero(out, 22); // name
46
+ const size = u16();
47
+ ssize += size * 2;
48
+ put16b(out, size);
49
+ put8(out, u8()); // finetune
50
+ put8(out, u8()); // volume
51
+ put16b(out, u16()); // loop start
52
+ put16b(out, u16()); // loop size
53
+ }
54
+ // Pad to 31 (di.c:92-96)
55
+ {
56
+ const pad = new Array(30).fill(0);
57
+ for (let i = nins; i < 31; i++)
58
+ out.push(...pad);
59
+ }
60
+ const posAfterSamples = pos;
61
+ // Sequence table (di.c:98-104): 0xff-terminated
62
+ pos = start + seqOfs;
63
+ const ptable = new Array(128).fill(0);
64
+ let i = 0;
65
+ let c1 = 0;
66
+ do {
67
+ c1 = u8();
68
+ ptable[i++] = c1;
69
+ } while (c1 !== 0xff);
70
+ ptable[i - 1] = 0;
71
+ const npat = i - 1;
72
+ put8(out, npat);
73
+ put8(out, 0x7f);
74
+ // Highest pattern (di.c:109-115)
75
+ let max = 0;
76
+ for (i = 0; i < 128; i++) {
77
+ put8(out, ptable[i]);
78
+ if (ptable[i] > max)
79
+ max = ptable[i];
80
+ }
81
+ if (max >= 128)
82
+ throw new Error('di: pattern number too high');
83
+ put32b(out, PW_MOD_MAGIC);
84
+ // Pattern data (di.c:118-153): paddr per pattern; cells have 3 forms
85
+ // (bit7 clear = note+2bytes, 0xff = empty u32, else note+3bytes).
86
+ pos = posAfterSamples;
87
+ const paddr = [];
88
+ for (i = 0; i <= max; i++)
89
+ paddr.push(u16());
90
+ for (i = 0; i <= max; i++) {
91
+ pos = start + paddr[i];
92
+ for (let k = 0; k < 256; k++) {
93
+ const c1v = u8();
94
+ if ((c1v & 0x80) === 0) {
95
+ const c2v = u8();
96
+ writeEvent(out, c1v, c2v, 0);
97
+ }
98
+ else if (c1v === 0xff) {
99
+ out.push(0, 0, 0, 0);
100
+ }
101
+ else {
102
+ const c2v = u8();
103
+ const c3v = u8();
104
+ writeEvent(out, c1v, c2v, c3v);
105
+ }
106
+ }
107
+ }
108
+ // Sample data (di.c:156-158)
109
+ moveData(data, start + smpOfs, out, ssize);
110
+ return Uint8Array.from(out);
111
+ }
112
+ /** test_di (di.c:165-268). */
113
+ function testDi(data, start) {
114
+ const s = data.length - start;
115
+ if (s < 14)
116
+ return 14 - s;
117
+ // Number of samples (di.c:174-177)
118
+ const numsmp = readmem16b(data, start);
119
+ if (numsmp > 31)
120
+ return -1;
121
+ if (s < 14 + numsmp * 8)
122
+ return 14 + numsmp * 8 - s;
123
+ // Finetunes and sample sizes (di.c:180-202)
124
+ let ssize = 0;
125
+ for (let i = 0; i < numsmp; i++) {
126
+ const d = start + i * 8 + 14; // note: fields at +14/+18/+20 within the
127
+ // 8-byte stride window per the C pointer arithmetic (d advances i*8 but
128
+ // field offsets +14/+18/+20 exceed 8 — this matches C exactly).
129
+ const len = readmem16b(data, d) << 1;
130
+ const lstart = readmem16b(data, d + 4) << 1;
131
+ const lsize = readmem16b(data, d + 6) << 1;
132
+ if (len > 0xffff || lstart > 0xffff || lsize > 0xffff)
133
+ return -1;
134
+ if (lstart + lsize > len)
135
+ return -1;
136
+ if (data[d + 2] > 0x0f)
137
+ return -1;
138
+ if (data[d + 3] > 0x40)
139
+ return -1;
140
+ ssize += len;
141
+ }
142
+ if (ssize <= 2)
143
+ return -1;
144
+ // Addresses (di.c:206-216)
145
+ const psize = numsmp * 8 + 2;
146
+ const ptabOfs = readmem32b(data, start + 2);
147
+ const patOfs = readmem32b(data, start + 6);
148
+ const smpOfs = readmem32b(data, start + 10);
149
+ if (ptabOfs < psize)
150
+ return -1;
151
+ if (patOfs <= ptabOfs || smpOfs <= ptabOfs || smpOfs <= patOfs)
152
+ return -1;
153
+ if (patOfs - ptabOfs > 128)
154
+ return -1;
155
+ // Pattern table reliability (di.c:250-254)
156
+ if (s < patOfs)
157
+ return patOfs - s;
158
+ for (let i = ptabOfs; i < patOfs - 1; i++) {
159
+ if (data[start + i] > 0x80)
160
+ return -1;
161
+ }
162
+ // 0xff at the end of the pattern list (di.c:257-260)
163
+ if (data[start + patOfs - 1] !== 0xff)
164
+ return -1;
165
+ // Sample data address > $ffff (di.c:263-266)
166
+ if (smpOfs > 65535)
167
+ return -1;
168
+ pwReadTitle(null, 0);
169
+ return 0;
170
+ }
171
+ /** pw_di: "Digital Illusions". */
172
+ export const pwDi = {
173
+ name: 'Digital Illusions',
174
+ test: testDi,
175
+ depack: depackDi,
176
+ };
177
+ //# sourceMappingURL=pw-di.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-di.js","sourceRoot":"","sources":["../src/pw-di.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type PwFormat } from './prowiz.js';
2
+ /** pw_eu: "Eureka Packer". */
3
+ export declare const pwEu: PwFormat;
4
+ //# sourceMappingURL=pw-eureka.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-eureka.d.ts","sourceRoot":"","sources":["../src/pw-eureka.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAiK9E,8BAA8B;AAC9B,eAAO,MAAM,IAAI,EAAE,QAIlB,CAAC"}
@@ -0,0 +1,171 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: libxmp src/loaders/prowizard/eureka.c (Eureka Packer) —
4
+ // depack_eu :35-122, test_eu :125-218.
5
+ import { readmem16b, readmem32b, moveData } from './prowiz.js';
6
+ const PW_MOD_MAGIC = 0x4d2e4b2e; // 'M.K.'
7
+ function put32b(out, v) {
8
+ out.push((v >>> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff);
9
+ }
10
+ /** depack_eu (eureka.c:35-122). Header is PTK-compatible. */
11
+ function depackEu(data, start) {
12
+ let pos = start;
13
+ const out = [];
14
+ // header: 1080 bytes moved verbatim (eureka.c:38-40)
15
+ for (let i = 0; i < 1080; i++)
16
+ out.push(data[pos++] ?? 0);
17
+ // whole sample size (eureka.c:43-45): sizes at 42 + i*30
18
+ let ssize = 0;
19
+ for (let i = 0; i < 31; i++) {
20
+ ssize += 2 * ((data[start + i * 30 + 42] << 8) | data[start + i * 30 + 43]);
21
+ }
22
+ // pattern list max (eureka.c:47-53)
23
+ let npat = 0;
24
+ for (let i = 0; i < 128; i++) {
25
+ if (data[start + 952 + i] > npat)
26
+ npat = data[start + 952 + i];
27
+ }
28
+ npat++;
29
+ put32b(out, PW_MOD_MAGIC);
30
+ const smpAddr = readmem32b(data, pos);
31
+ pos += 4; // sample data address
32
+ // Track addresses (eureka.c:56-61)
33
+ const trkAddr = [];
34
+ for (let i = 0; i < npat; i++) {
35
+ const row = [];
36
+ for (let j = 0; j < 4; j++) {
37
+ row.push((data[pos] << 8) | data[pos + 1]);
38
+ pos += 2;
39
+ }
40
+ trkAddr.push(row);
41
+ }
42
+ // Track data (eureka.c:64-110): 4 cell forms per 2-bit prefix.
43
+ for (let i = 0; i < npat; i++) {
44
+ const tmp = new Uint8Array(1024);
45
+ for (let j = 0; j < 4; j++) {
46
+ pos = start + trkAddr[i][j];
47
+ for (let k = 0; k < 64; k++) {
48
+ const x = k * 16 + j * 4;
49
+ const c1 = data[pos++] ?? 0;
50
+ if ((c1 & 0xc0) === 0x00) {
51
+ // full 4-byte cell (eureka.c:67-72)
52
+ tmp[x] = c1;
53
+ tmp[x + 1] = data[pos++] ?? 0;
54
+ tmp[x + 2] = data[pos++] ?? 0;
55
+ tmp[x + 3] = data[pos++] ?? 0;
56
+ continue;
57
+ }
58
+ if ((c1 & 0xc0) === 0xc0) {
59
+ k += c1 & 0x3f; // blank rows (eureka.c:73-76)
60
+ continue;
61
+ }
62
+ if ((c1 & 0xc0) === 0x40) {
63
+ // effect-only (eureka.c:77-82)
64
+ tmp[x + 2] = c1 & 0x0f;
65
+ tmp[x + 3] = data[pos++] ?? 0;
66
+ continue;
67
+ }
68
+ if ((c1 & 0xc0) === 0x80) {
69
+ // note+ins without effect (eureka.c:83-88)
70
+ tmp[x] = data[pos++] ?? 0;
71
+ tmp[x + 1] = data[pos++] ?? 0;
72
+ tmp[x + 2] = (c1 << 4) & 0xf0;
73
+ continue;
74
+ }
75
+ }
76
+ }
77
+ for (let k = 0; k < 1024; k++)
78
+ out.push(tmp[k]);
79
+ }
80
+ // Sample data (eureka.c:113-116)
81
+ moveData(data, start + smpAddr, out, ssize);
82
+ return Uint8Array.from(out);
83
+ }
84
+ /** test_eu (eureka.c:125-218). */
85
+ function testEu(data, start) {
86
+ const s = data.length - start;
87
+ if (s < 1084)
88
+ return 1084 - s;
89
+ // test 2 (eureka.c:131-135)
90
+ const len = data[start + 950];
91
+ if (len === 0 || len > 127)
92
+ return -1;
93
+ // test #3 (eureka.c:137-156)
94
+ for (let i = 0; i < 31; i++) {
95
+ const d = start + i * 30;
96
+ const size = readmem16b(data, d + 42) << 1;
97
+ const lstart = readmem16b(data, d + 46) << 1;
98
+ const lsize = readmem16b(data, d + 48) << 1;
99
+ if (size > 0xffff || lstart > 0xffff || lsize > 0xffff)
100
+ return -1;
101
+ if (lstart + lsize > size + 2)
102
+ return -1;
103
+ if (data[d + 44] > 0x0f || data[d + 45] > 0x40)
104
+ return -1;
105
+ }
106
+ // test 4 (eureka.c:159-167)
107
+ const smpOfs = readmem32b(data, start + 1080);
108
+ if (smpOfs < 1084)
109
+ return -1;
110
+ // Pattern list (eureka.c:169-183)
111
+ let maxPat = 0;
112
+ let i = 0;
113
+ for (; i < len; i++) {
114
+ const pat = data[start + 952 + i];
115
+ if (pat > 127)
116
+ return -1;
117
+ if (pat > maxPat)
118
+ maxPat = pat;
119
+ }
120
+ for (; i < 128; i++) {
121
+ if (data[start + 952 + i] !== 0)
122
+ return -1;
123
+ }
124
+ maxPat++;
125
+ // Track address bounds (eureka.c:186-199)
126
+ let maxTrk = 0;
127
+ let minTrk = 999999;
128
+ if (s < maxPat * 4 * 2 + 1085)
129
+ return maxPat * 4 * 2 + 1085 - s;
130
+ for (i = 0; i < maxPat * 4; i++) {
131
+ const trk = readmem16b(data, start + i * 2 + 1084);
132
+ if (trk > smpOfs || trk < 1084)
133
+ return -1;
134
+ if (trk > maxTrk)
135
+ maxTrk = trk;
136
+ if (trk < minTrk)
137
+ minTrk = trk;
138
+ }
139
+ if (s < maxTrk)
140
+ return maxTrk - s;
141
+ // Track data sanity (eureka.c:203-215)
142
+ for (i = minTrk; i < maxTrk; i++) {
143
+ const c = data[start + i];
144
+ if ((c & 0xc0) === 0xc0)
145
+ continue;
146
+ if ((c & 0xc0) === 0x80) {
147
+ i += 2;
148
+ continue;
149
+ }
150
+ if ((c & 0xc0) === 0x40) {
151
+ if ((c & 0x3f) === 0 && data[start + i + 1] === 0)
152
+ return -1;
153
+ i++;
154
+ continue;
155
+ }
156
+ if ((c & 0xc0) === 0) {
157
+ if (c > 0x13)
158
+ return -1;
159
+ i += 3;
160
+ continue;
161
+ }
162
+ }
163
+ return 0;
164
+ }
165
+ /** pw_eu: "Eureka Packer". */
166
+ export const pwEu = {
167
+ name: 'Eureka Packer',
168
+ test: testEu,
169
+ depack: depackEu,
170
+ };
171
+ //# sourceMappingURL=pw-eureka.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-eureka.js","sourceRoot":"","sources":["../src/pw-eureka.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type PwFormat } from './prowiz.js';
2
+ /** pw_fcm: "FC-M Packer". */
3
+ export declare const pwFcm: PwFormat;
4
+ //# sourceMappingURL=pw-fcm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-fcm.d.ts","sourceRoot":"","sources":["../src/pw-fcm.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAoGzD,6BAA6B;AAC7B,eAAO,MAAM,KAAK,EAAE,QAInB,CAAC"}
package/dist/pw-fcm.js ADDED
@@ -0,0 +1,102 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: libxmp src/loaders/prowizard/fc-m.c (FC-M Packer 1.0) —
4
+ // depack_fcm :33-93, test_fcm :95-123.
5
+ import { pwReadTitle } from './prowiz.js';
6
+ const PW_MOD_MAGIC = 0x4d2e4b2e; // 'M.K.'
7
+ function put8(out, b) { out.push(b & 0xff); }
8
+ function put16b(out, v) { out.push((v >> 8) & 0xff, v & 0xff); }
9
+ function put32b(out, v) {
10
+ out.push((v >>> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff);
11
+ }
12
+ /** depack_fcm (fc-m.c:33-93) — chunked container, mostly verbatim moves. */
13
+ function depackFcm(data, start) {
14
+ let pos = start;
15
+ const out = [];
16
+ const u8 = () => data[pos++] ?? 0;
17
+ const u16 = () => { const v = (data[pos] << 8) | data[pos + 1]; pos += 2; return v; };
18
+ const u32 = () => { const v = read32(data, pos); pos += 4; return v; };
19
+ const read32 = (d, o) => ((d[o] << 24) | (d[o + 1] << 16) | (d[o + 2] << 8) | d[o + 3]) >>> 0;
20
+ u32(); // bypass "FC-M" ID
21
+ u16(); // version number?
22
+ u32(); // bypass "NAME" chunk
23
+ // title: move 20 bytes (fc-m.c:42)
24
+ for (let i = 0; i < 20; i++)
25
+ out.push(data[pos++] ?? 0);
26
+ u32(); // bypass "INST" chunk
27
+ // Sample descriptions (fc-m.c:46-57)
28
+ let ssize = 0;
29
+ for (let i = 0; i < 31; i++) {
30
+ for (let k = 0; k < 22; k++)
31
+ out.push(0); // sample name
32
+ const size = u16();
33
+ put16b(out, size);
34
+ ssize += size * 2;
35
+ put8(out, u8()); // finetune
36
+ put8(out, u8()); // volume
37
+ put16b(out, u16()); // loop start
38
+ let loopSize = u16();
39
+ if (loopSize === 0)
40
+ loopSize = 1;
41
+ put16b(out, loopSize);
42
+ }
43
+ u32(); // bypass "LONG" chunk
44
+ const patPos = u8();
45
+ put8(out, patPos);
46
+ put8(out, u8()); // NoiseTracker byte
47
+ u32(); // bypass "PATT" chunk
48
+ // Pattern list (fc-m.c:63-68)
49
+ let patMax = 0;
50
+ let i = 0;
51
+ for (; i < patPos; i++) {
52
+ const c1 = u8();
53
+ put8(out, c1);
54
+ if (c1 > patMax)
55
+ patMax = c1;
56
+ }
57
+ for (; i < 128; i++)
58
+ put8(out, 0);
59
+ put32b(out, PW_MOD_MAGIC);
60
+ u32(); // bypass "SONG" chunk
61
+ // Pattern data (fc-m.c:72-74): verbatim 1024-byte blocks
62
+ for (i = 0; i <= patMax; i++) {
63
+ for (let k = 0; k < 1024; k++)
64
+ out.push(data[pos++] ?? 0);
65
+ }
66
+ u32(); // bypass "SAMP" chunk
67
+ // Sample data (fc-m.c:75-76)
68
+ for (let k = 0; k < ssize && pos < data.length; k++)
69
+ out.push(data[pos++] ?? 0);
70
+ return Uint8Array.from(out);
71
+ }
72
+ /** test_fcm (fc-m.c:95-123). */
73
+ function testFcm(data, start) {
74
+ const s = data.length - start;
75
+ if (s < 37 + 8 * 31)
76
+ return 37 + 8 * 31 - s;
77
+ // "FC-M" (fc-m.c:100-104)
78
+ if (data[start] !== 0x46 || data[start + 1] !== 0x43 ||
79
+ data[start + 2] !== 0x2d || data[start + 3] !== 0x4d) {
80
+ return -1;
81
+ }
82
+ // test 1 (fc-m.c:106-109)
83
+ if (data[start + 4] !== 0x01)
84
+ return -1;
85
+ // test 2 (fc-m.c:111-114)
86
+ if (data[start + 5] !== 0x00)
87
+ return -1;
88
+ // test 3 (fc-m.c:116-120)
89
+ for (let j = 0; j < 31; j++) {
90
+ if (data[start + 37 + 8 * j] > 0x40)
91
+ return -1;
92
+ }
93
+ pwReadTitle(data.subarray(start + 10), 20);
94
+ return 0;
95
+ }
96
+ /** pw_fcm: "FC-M Packer". */
97
+ export const pwFcm = {
98
+ name: 'FC-M Packer',
99
+ test: testFcm,
100
+ depack: depackFcm,
101
+ };
102
+ //# sourceMappingURL=pw-fcm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-fcm.js","sourceRoot":"","sources":["../src/pw-fcm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type PwFormat } from './prowiz.js';
2
+ /** pw_fchs: "Fuchs Tracker". */
3
+ export declare const pwFchs: PwFormat;
4
+ //# sourceMappingURL=pw-fuchs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pw-fuchs.d.ts","sourceRoot":"","sources":["../src/pw-fuchs.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AA8IjF,gCAAgC;AAChC,eAAO,MAAM,MAAM,EAAE,QAIpB,CAAC"}
@@ -0,0 +1,139 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause
2
+ // Copyright (c) 2026 Bitti09 — modplayjs contributors
3
+ // Ported from: libxmp src/loaders/prowizard/fuchs.c (Fuchs Tracker) —
4
+ // depack_fuchs :35-143, test_fuchs :145-200.
5
+ import { readmem16b, readmem32b, pwReadTitle } from './prowiz.js';
6
+ const PW_MOD_MAGIC = 0x4d2e4b2e; // 'M.K.'
7
+ function put32b(out, v) {
8
+ out.push((v >>> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff);
9
+ }
10
+ /** depack_fuchs (fuchs.c:35-143). */
11
+ function depackFuchs(data, start) {
12
+ let pos = start;
13
+ const out = [];
14
+ const u16 = () => { const v = readmem16b(data, pos); pos += 2; return v; };
15
+ const u32 = () => { const v = readmem32b(data, pos); pos += 4; return v; };
16
+ // Fuchs builds a full 1080-byte PTK header in `data`.
17
+ const hdr = new Uint8Array(1080);
18
+ // title: 10 bytes moved (fuchs.c:40)
19
+ for (let i = 0; i < 10; i++)
20
+ hdr[i] = data[pos++] ?? 0;
21
+ u32(); // all sample data size
22
+ // sample sizes (fuchs.c:44-49): smp_len → data[42+i*30], [43+i*30]
23
+ const smpLen = [];
24
+ for (let i = 0; i < 16; i++) {
25
+ const l = u16();
26
+ smpLen.push(l);
27
+ hdr[42 + i * 30] = (l >> 9) & 0xff;
28
+ hdr[43 + i * 30] = (l >> 1) & 0xff;
29
+ }
30
+ // volumes (fuchs.c:52-55): data[45+i*30]
31
+ for (let i = 0; i < 16; i++) {
32
+ hdr[45 + i * 30] = u16() & 0xff;
33
+ }
34
+ // loop start (fuchs.c:58-63)
35
+ const loopStart = [];
36
+ for (let i = 0; i < 16; i++) {
37
+ const l = u16();
38
+ loopStart.push(l);
39
+ hdr[46 + i * 30] = (l >> 1) & 0xff;
40
+ }
41
+ // replen (fuchs.c:66-79)
42
+ for (let i = 0; i < 16; i++) {
43
+ const loopSize = smpLen[i] - loopStart[i];
44
+ if (loopSize === 0 || loopStart[i] === 0) {
45
+ hdr[49 + i * 30] = 1;
46
+ }
47
+ else {
48
+ hdr[48 + i * 30] = (loopSize >> 9) & 0xff;
49
+ hdr[49 + i * 30] = (loopSize >> 1) & 0xff;
50
+ }
51
+ }
52
+ // fill replens for samples 16..30 with $0001 (fuchs.c:82-85)
53
+ for (let i = 16; i < 31; i++) {
54
+ hdr[49 + i * 30] = 1;
55
+ }
56
+ // pattern list (fuchs.c:89-99): count @950, ntk @951, 40 u16 entries
57
+ hdr[950] = u16() & 0xff;
58
+ hdr[951] = 0x7f;
59
+ let maxPat = 0;
60
+ for (let i = 0; i < 40; i++) {
61
+ const pat = u16();
62
+ hdr[952 + i] = pat & 0xff;
63
+ if (pat > maxPat)
64
+ maxPat = pat;
65
+ }
66
+ // write the 1080-byte header (fuchs.c:102-106)
67
+ for (let i = 0; i < 1080; i++)
68
+ out.push(hdr[i]);
69
+ put32b(out, PW_MOD_MAGIC);
70
+ // pattern data (fuchs.c:109-127): bypass "SONG" ID, read size, convert
71
+ u32(); // "SONG" ID
72
+ const patSize = u32();
73
+ if (patSize === 0 || patSize > 0x20000 || (patSize & 0x3) !== 0) {
74
+ throw new Error('fuchs: bad pattern size');
75
+ }
76
+ const tmp = new Uint8Array(patSize);
77
+ for (let i = 0; i < patSize; i++)
78
+ tmp[i] = data[pos++] ?? 0;
79
+ // convert fx C arg back to hex value (fuchs.c:130-134)
80
+ for (let i = 0; i < patSize; i += 4) {
81
+ if ((tmp[i + 2] & 0x0f) === 0x0c) {
82
+ const x = tmp[i + 3];
83
+ tmp[i + 3] = 10 * (x >> 4) + (x & 0xf);
84
+ }
85
+ }
86
+ // write pattern data (fuchs.c:137-139)
87
+ for (let i = 0; i < patSize; i++)
88
+ out.push(tmp[i]);
89
+ // sample data (fuchs.c:142-149): bypass "INST" ID, sequential non-empty
90
+ pos += 4; // "INST" Id
91
+ for (let i = 0; i < 16; i++) {
92
+ if (smpLen[i] !== 0) {
93
+ for (let k = 0; k < smpLen[i] && pos < data.length; k++)
94
+ out.push(data[pos++] ?? 0);
95
+ }
96
+ }
97
+ return Uint8Array.from(out);
98
+ }
99
+ /** test_fuchs (fuchs.c:145-200). */
100
+ function testFuchs(data, start) {
101
+ const s = data.length - start;
102
+ if (s < 196)
103
+ return 196 - s;
104
+ // "SONG" at 192 (fuchs.c:149-150)
105
+ if (readmem32b(data, start + 192) !== 0x534f4e47)
106
+ return -1;
107
+ // all sample size (fuchs.c:153-156)
108
+ const hdrSsize = readmem32b(data, start + 10);
109
+ if (hdrSsize <= 2 || hdrSsize >= 65535 * 16)
110
+ return -1;
111
+ // sample descriptions (fuchs.c:159-177): fields at i*2 strides per C
112
+ let ssize = 0;
113
+ for (let i = 0; i < 16; i++) {
114
+ const d = start + i * 2;
115
+ const len = readmem16b(data, d + 14);
116
+ const lstart = readmem16b(data, d + 78);
117
+ if (data[d + 46] > 0x40)
118
+ return -1; // volumes
119
+ if (len < lstart)
120
+ return -1;
121
+ ssize += len;
122
+ }
123
+ if (ssize <= 2 || ssize > hdrSsize)
124
+ return -1;
125
+ // pattern list entries <= 40 (fuchs.c:182-190)
126
+ for (let i = 0; i < 40; i++) {
127
+ if (data[start + i * 2 + 113] > 40)
128
+ return -1;
129
+ }
130
+ pwReadTitle(null, 0);
131
+ return 0;
132
+ }
133
+ /** pw_fchs: "Fuchs Tracker". */
134
+ export const pwFchs = {
135
+ name: 'Fuchs Tracker',
136
+ test: testFuchs,
137
+ depack: depackFuchs,
138
+ };
139
+ //# sourceMappingURL=pw-fuchs.js.map