@beatbax/engine 0.1.0

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 (174) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/audio/bufferedRenderer.d.ts +32 -0
  3. package/dist/audio/bufferedRenderer.d.ts.map +1 -0
  4. package/dist/audio/bufferedRenderer.js +309 -0
  5. package/dist/audio/bufferedRenderer.js.map +1 -0
  6. package/dist/audio/pcmRenderer.d.ts +25 -0
  7. package/dist/audio/pcmRenderer.d.ts.map +1 -0
  8. package/dist/audio/pcmRenderer.js +1288 -0
  9. package/dist/audio/pcmRenderer.js.map +1 -0
  10. package/dist/audio/playback.d.ts +57 -0
  11. package/dist/audio/playback.d.ts.map +1 -0
  12. package/dist/audio/playback.js +794 -0
  13. package/dist/audio/playback.js.map +1 -0
  14. package/dist/chips/gameboy/apu.d.ts +9 -0
  15. package/dist/chips/gameboy/apu.d.ts.map +1 -0
  16. package/dist/chips/gameboy/apu.js +27 -0
  17. package/dist/chips/gameboy/apu.js.map +1 -0
  18. package/dist/chips/gameboy/noise.d.ts +6 -0
  19. package/dist/chips/gameboy/noise.d.ts.map +1 -0
  20. package/dist/chips/gameboy/noise.js +155 -0
  21. package/dist/chips/gameboy/noise.js.map +1 -0
  22. package/dist/chips/gameboy/packet.d.ts +3 -0
  23. package/dist/chips/gameboy/packet.d.ts.map +1 -0
  24. package/dist/chips/gameboy/packet.js +3 -0
  25. package/dist/chips/gameboy/packet.js.map +1 -0
  26. package/dist/chips/gameboy/periodTables.d.ts +16 -0
  27. package/dist/chips/gameboy/periodTables.d.ts.map +1 -0
  28. package/dist/chips/gameboy/periodTables.js +29 -0
  29. package/dist/chips/gameboy/periodTables.js.map +1 -0
  30. package/dist/chips/gameboy/pulse.d.ts +12 -0
  31. package/dist/chips/gameboy/pulse.d.ts.map +1 -0
  32. package/dist/chips/gameboy/pulse.js +275 -0
  33. package/dist/chips/gameboy/pulse.js.map +1 -0
  34. package/dist/chips/gameboy/wave.d.ts +8 -0
  35. package/dist/chips/gameboy/wave.d.ts.map +1 -0
  36. package/dist/chips/gameboy/wave.js +146 -0
  37. package/dist/chips/gameboy/wave.js.map +1 -0
  38. package/dist/effects/index.d.ts +7 -0
  39. package/dist/effects/index.d.ts.map +1 -0
  40. package/dist/effects/index.js +1028 -0
  41. package/dist/effects/index.js.map +1 -0
  42. package/dist/effects/types.d.ts +8 -0
  43. package/dist/effects/types.d.ts.map +1 -0
  44. package/dist/effects/types.js +2 -0
  45. package/dist/effects/types.js.map +1 -0
  46. package/dist/expand/refExpander.d.ts +14 -0
  47. package/dist/expand/refExpander.d.ts.map +1 -0
  48. package/dist/expand/refExpander.js +130 -0
  49. package/dist/expand/refExpander.js.map +1 -0
  50. package/dist/export/index.d.ts +5 -0
  51. package/dist/export/index.d.ts.map +1 -0
  52. package/dist/export/index.js +5 -0
  53. package/dist/export/index.js.map +1 -0
  54. package/dist/export/jsonExport.d.ts +9 -0
  55. package/dist/export/jsonExport.d.ts.map +1 -0
  56. package/dist/export/jsonExport.js +184 -0
  57. package/dist/export/jsonExport.js.map +1 -0
  58. package/dist/export/midiExport.d.ts +9 -0
  59. package/dist/export/midiExport.d.ts.map +1 -0
  60. package/dist/export/midiExport.js +390 -0
  61. package/dist/export/midiExport.js.map +1 -0
  62. package/dist/export/ugeWriter.d.ts +33 -0
  63. package/dist/export/ugeWriter.d.ts.map +1 -0
  64. package/dist/export/ugeWriter.js +1997 -0
  65. package/dist/export/ugeWriter.js.map +1 -0
  66. package/dist/export/wavWriter.d.ts +24 -0
  67. package/dist/export/wavWriter.d.ts.map +1 -0
  68. package/dist/export/wavWriter.js +126 -0
  69. package/dist/export/wavWriter.js.map +1 -0
  70. package/dist/import/index.d.ts +5 -0
  71. package/dist/import/index.d.ts.map +1 -0
  72. package/dist/import/index.js +8 -0
  73. package/dist/import/index.js.map +1 -0
  74. package/dist/import/remoteCache.d.ts +60 -0
  75. package/dist/import/remoteCache.d.ts.map +1 -0
  76. package/dist/import/remoteCache.js +194 -0
  77. package/dist/import/remoteCache.js.map +1 -0
  78. package/dist/import/uge/uge.reader.d.ts +27 -0
  79. package/dist/import/uge/uge.reader.d.ts.map +1 -0
  80. package/dist/import/uge/uge.reader.js +545 -0
  81. package/dist/import/uge/uge.reader.js.map +1 -0
  82. package/dist/import/urlUtils.d.ts +50 -0
  83. package/dist/import/urlUtils.d.ts.map +1 -0
  84. package/dist/import/urlUtils.js +87 -0
  85. package/dist/import/urlUtils.js.map +1 -0
  86. package/dist/index.d.ts +18 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +318 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/instruments/instrumentState.d.ts +15 -0
  91. package/dist/instruments/instrumentState.d.ts.map +1 -0
  92. package/dist/instruments/instrumentState.js +24 -0
  93. package/dist/instruments/instrumentState.js.map +1 -0
  94. package/dist/parser/ast.d.ts +22 -0
  95. package/dist/parser/ast.d.ts.map +1 -0
  96. package/dist/parser/ast.js +5 -0
  97. package/dist/parser/ast.js.map +1 -0
  98. package/dist/parser/index.d.ts +14 -0
  99. package/dist/parser/index.d.ts.map +1 -0
  100. package/dist/parser/index.js +10 -0
  101. package/dist/parser/index.js.map +1 -0
  102. package/dist/parser/peggy/generated/parser.d.ts +8 -0
  103. package/dist/parser/peggy/generated/parser.d.ts.map +1 -0
  104. package/dist/parser/peggy/generated/parser.js +6269 -0
  105. package/dist/parser/peggy/generated/parser.js.map +1 -0
  106. package/dist/parser/peggy/index.d.ts +3 -0
  107. package/dist/parser/peggy/index.d.ts.map +1 -0
  108. package/dist/parser/peggy/index.js +555 -0
  109. package/dist/parser/peggy/index.js.map +1 -0
  110. package/dist/parser/structured.d.ts +16 -0
  111. package/dist/parser/structured.d.ts.map +1 -0
  112. package/dist/parser/structured.js +232 -0
  113. package/dist/parser/structured.js.map +1 -0
  114. package/dist/parser/tokenizer.d.ts +12 -0
  115. package/dist/parser/tokenizer.d.ts.map +1 -0
  116. package/dist/parser/tokenizer.js +14 -0
  117. package/dist/parser/tokenizer.js.map +1 -0
  118. package/dist/patterns/expand.d.ts +32 -0
  119. package/dist/patterns/expand.d.ts.map +1 -0
  120. package/dist/patterns/expand.js +184 -0
  121. package/dist/patterns/expand.js.map +1 -0
  122. package/dist/patterns/index.d.ts +2 -0
  123. package/dist/patterns/index.d.ts.map +1 -0
  124. package/dist/patterns/index.js +2 -0
  125. package/dist/patterns/index.js.map +1 -0
  126. package/dist/scheduler/index.d.ts +6 -0
  127. package/dist/scheduler/index.d.ts.map +1 -0
  128. package/dist/scheduler/index.js +9 -0
  129. package/dist/scheduler/index.js.map +1 -0
  130. package/dist/scheduler/tickScheduler.d.ts +27 -0
  131. package/dist/scheduler/tickScheduler.d.ts.map +1 -0
  132. package/dist/scheduler/tickScheduler.js +74 -0
  133. package/dist/scheduler/tickScheduler.js.map +1 -0
  134. package/dist/sequences/expand.d.ts +14 -0
  135. package/dist/sequences/expand.d.ts.map +1 -0
  136. package/dist/sequences/expand.js +137 -0
  137. package/dist/sequences/expand.js.map +1 -0
  138. package/dist/song/importResolver.browser.d.ts +29 -0
  139. package/dist/song/importResolver.browser.d.ts.map +1 -0
  140. package/dist/song/importResolver.browser.js +168 -0
  141. package/dist/song/importResolver.browser.js.map +1 -0
  142. package/dist/song/importResolver.d.ts +40 -0
  143. package/dist/song/importResolver.d.ts.map +1 -0
  144. package/dist/song/importResolver.js +445 -0
  145. package/dist/song/importResolver.js.map +1 -0
  146. package/dist/song/index.browser.d.ts +9 -0
  147. package/dist/song/index.browser.d.ts.map +1 -0
  148. package/dist/song/index.browser.js +7 -0
  149. package/dist/song/index.browser.js.map +1 -0
  150. package/dist/song/index.d.ts +8 -0
  151. package/dist/song/index.d.ts.map +1 -0
  152. package/dist/song/index.js +6 -0
  153. package/dist/song/index.js.map +1 -0
  154. package/dist/song/resolver.browser.d.ts +50 -0
  155. package/dist/song/resolver.browser.d.ts.map +1 -0
  156. package/dist/song/resolver.browser.js +536 -0
  157. package/dist/song/resolver.browser.js.map +1 -0
  158. package/dist/song/resolver.d.ts +20 -0
  159. package/dist/song/resolver.d.ts.map +1 -0
  160. package/dist/song/resolver.js +540 -0
  161. package/dist/song/resolver.js.map +1 -0
  162. package/dist/song/songModel.d.ts +34 -0
  163. package/dist/song/songModel.d.ts.map +1 -0
  164. package/dist/song/songModel.js +2 -0
  165. package/dist/song/songModel.js.map +1 -0
  166. package/dist/tests/refExpander.test.d.ts +2 -0
  167. package/dist/tests/refExpander.test.d.ts.map +1 -0
  168. package/dist/tests/refExpander.test.js +37 -0
  169. package/dist/tests/refExpander.test.js.map +1 -0
  170. package/dist/util/diag.d.ts +16 -0
  171. package/dist/util/diag.d.ts.map +1 -0
  172. package/dist/util/diag.js +29 -0
  173. package/dist/util/diag.js.map +1 -0
  174. package/package.json +84 -0
@@ -0,0 +1,390 @@
1
+ /*
2
+ * Minimal but functional MIDI exporter.
3
+ * - Accepts a resolved SongModel (as produced by `resolveSong`) and writes
4
+ * a Type-1 SMF with one MIDI track per channel (up to 16 channels).
5
+ * - If called with a single string path, writes a small empty MIDI file.
6
+ */
7
+ import { writeFileSync } from 'fs';
8
+ import { noteNameToMidi } from '../audio/playback.js';
9
+ function writeVarLen(n) {
10
+ const bytes = [];
11
+ let val = n & 0xffffffff;
12
+ let buffer = val & 0x7f;
13
+ val >>= 7;
14
+ while (val > 0) {
15
+ buffer <<= 8;
16
+ buffer |= ((val & 0x7f) | 0x80);
17
+ val >>= 7;
18
+ }
19
+ // Emit bytes from buffer
20
+ while (true) {
21
+ bytes.push(buffer & 0xff);
22
+ if (buffer & 0x80)
23
+ buffer >>= 8;
24
+ else
25
+ break;
26
+ }
27
+ return bytes;
28
+ }
29
+ function vlq(n) {
30
+ // Simpler VLQ writer that builds bytes MSB-first
31
+ const out = [];
32
+ let value = n & 0xffffffff;
33
+ let buffer = value & 0x7f;
34
+ value >>= 7;
35
+ while (value > 0) {
36
+ buffer |= ((value & 0x7f) << ((out.length + 1) * 8));
37
+ value >>= 7;
38
+ }
39
+ // Fallback: use common algorithm
40
+ const parts = [];
41
+ let v = n;
42
+ parts.push(v & 0x7f);
43
+ v >>= 7;
44
+ while (v > 0) {
45
+ parts.push((v & 0x7f) | 0x80);
46
+ v >>= 7;
47
+ }
48
+ return parts.reverse();
49
+ }
50
+ function writeChunk(id, data) {
51
+ const header = Buffer.from(id, 'ascii');
52
+ const len = Buffer.alloc(4);
53
+ len.writeUInt32BE(data.length, 0);
54
+ const body = Buffer.from(data);
55
+ return Buffer.concat([header, len, body]);
56
+ }
57
+ function pushMetaText(data, delta, text) {
58
+ const dbytes = vlq(delta);
59
+ for (const b of dbytes)
60
+ data.push(b);
61
+ const txt = Buffer.from(text, 'utf8');
62
+ data.push(0xff, 0x01);
63
+ const lenBytes = vlq(txt.length);
64
+ for (const b of lenBytes)
65
+ data.push(b);
66
+ for (const byte of txt)
67
+ data.push(byte);
68
+ }
69
+ /** Export a resolved song model to MIDI. */
70
+ export async function exportMIDI(songOrPath, maybePath, options = {}, opts) {
71
+ let outPath = maybePath;
72
+ const verbose = opts && opts.verbose === true;
73
+ // If caller passed just a path string, write an empty MIDI file
74
+ if (typeof songOrPath === 'string' && !maybePath) {
75
+ outPath = songOrPath.endsWith('.mid') ? songOrPath : `${songOrPath}.mid`;
76
+ // simple empty type-1 MIDI with one empty track
77
+ const header = Buffer.alloc(14);
78
+ header.write('MThd', 0, 4, 'ascii');
79
+ header.writeUInt32BE(6, 4);
80
+ header.writeUInt16BE(1, 8); // format 1
81
+ header.writeUInt16BE(1, 10); // 1 track
82
+ header.writeUInt16BE(480, 12); // ticks per quarter
83
+ const track = writeChunk('MTrk', [0x00, 0xff, 0x2f, 0x00]);
84
+ writeFileSync(outPath, Buffer.concat([header, track]));
85
+ if (opts && opts.debug)
86
+ console.log('Wrote empty MIDI to', outPath);
87
+ return;
88
+ }
89
+ const song = songOrPath;
90
+ if (!outPath)
91
+ outPath = 'song.mid';
92
+ if (verbose) {
93
+ console.log(`Exporting to MIDI (Standard MIDI File): ${outPath}`);
94
+ }
95
+ // Basic SMF parameters
96
+ const ticksPerQuarter = 480; // PPQ
97
+ const ticksPerToken = Math.floor(ticksPerQuarter / 4); // assume token = 16th note
98
+ const bpm = (song && typeof song.bpm === 'number') ? song.bpm : 128;
99
+ // Build header: format 1, N tracks = channels.length (clamped to 16)
100
+ const allChannels = Array.isArray(song.channels) ? song.channels : [];
101
+ const channels = options.channels
102
+ ? allChannels.filter((ch) => options.channels.includes(ch.id))
103
+ : allChannels;
104
+ const ntracks = Math.max(1, Math.min(16, channels.length));
105
+ const header = Buffer.alloc(14);
106
+ header.write('MThd', 0, 4, 'ascii');
107
+ header.writeUInt32BE(6, 4);
108
+ header.writeUInt16BE(1, 8); // format 1
109
+ header.writeUInt16BE(ntracks, 10);
110
+ header.writeUInt16BE(ticksPerQuarter, 12);
111
+ const trackBuffers = [];
112
+ // GB type -> GM program defaults and drum mapping
113
+ const GB_TO_GM_PROGRAM = {
114
+ pulse1: 80, // Lead 1 (square-like)
115
+ pulse2: 34, // Electric Bass (example)
116
+ wave: 81, // Lead 2 (saw-ish)
117
+ noise: 0
118
+ };
119
+ const NOISE_TO_DRUM = {
120
+ hh: 42, // closed hi-hat
121
+ sn: 38, // acoustic snare
122
+ kick: 36, // bass drum
123
+ default: 39
124
+ };
125
+ function resolveProgramForInstrumentName(instName, ch, ev) {
126
+ // priority: ev.instProps?.gm -> song.insts[instName]?.gm -> GB_TO_GM_PROGRAM based on type -> 0
127
+ if (ev && ev.instProps && typeof ev.instProps.gm === 'number')
128
+ return ev.instProps.gm & 0x7f;
129
+ if (ev && ev.instProps && typeof ev.instProps.gm === 'string') {
130
+ const parsed = parseInt(ev.instProps.gm, 10);
131
+ if (!isNaN(parsed))
132
+ return parsed & 0x7f;
133
+ }
134
+ if (instName && song && song.insts && song.insts[instName]) {
135
+ const inst = song.insts[instName];
136
+ if (inst && typeof inst.gm === 'number')
137
+ return inst.gm & 0x7f;
138
+ if (inst && typeof inst.gm === 'string') {
139
+ const parsed = parseInt(inst.gm, 10);
140
+ if (!isNaN(parsed))
141
+ return parsed & 0x7f;
142
+ }
143
+ if (inst && typeof inst.type === 'string') {
144
+ const t = String(inst.type).toLowerCase();
145
+ if (t.includes('pulse1'))
146
+ return GB_TO_GM_PROGRAM.pulse1;
147
+ if (t.includes('pulse2'))
148
+ return GB_TO_GM_PROGRAM.pulse2;
149
+ if (t.includes('wave'))
150
+ return GB_TO_GM_PROGRAM.wave;
151
+ if (t.includes('noise'))
152
+ return GB_TO_GM_PROGRAM.noise;
153
+ }
154
+ }
155
+ // Channel-level default instrument may have type data
156
+ if (ch && ch.defaultInstrument && song && song.insts && song.insts[ch.defaultInstrument]) {
157
+ const inst = song.insts[ch.defaultInstrument];
158
+ if (inst && typeof inst.type === 'string') {
159
+ const t = String(inst.type).toLowerCase();
160
+ if (t.includes('pulse1'))
161
+ return GB_TO_GM_PROGRAM.pulse1;
162
+ if (t.includes('pulse2'))
163
+ return GB_TO_GM_PROGRAM.pulse2;
164
+ if (t.includes('wave'))
165
+ return GB_TO_GM_PROGRAM.wave;
166
+ if (t.includes('noise'))
167
+ return GB_TO_GM_PROGRAM.noise;
168
+ }
169
+ }
170
+ return GB_TO_GM_PROGRAM.pulse1;
171
+ }
172
+ // For each channel produce a track of note on/off events, emitting Program Change when needed
173
+ for (let ci = 0; ci < ntracks; ci++) {
174
+ const ch = channels[ci];
175
+ const events = (ch && Array.isArray(ch.events)) ? ch.events : (ch && Array.isArray(ch.pat) ? ch.pat : []);
176
+ const data = [];
177
+ let lastTick = 0;
178
+ // choose a MIDI channel for this GB channel (prefer mapping noise -> 9)
179
+ let midiChannel = Math.max(0, Math.min(15, (ci % 16)));
180
+ // if channel default instrument is noise, map to GM percussion channel 9
181
+ if (ch && ch.defaultInstrument && song && song.insts && song.insts[ch.defaultInstrument]) {
182
+ const tinst = song.insts[ch.defaultInstrument];
183
+ if (tinst && typeof tinst.type === 'string' && String(tinst.type).toLowerCase().includes('noise'))
184
+ midiChannel = 9;
185
+ }
186
+ // initial program based on channel default
187
+ let currentProgram = resolveProgramForInstrumentName(ch && ch.defaultInstrument, ch);
188
+ if (midiChannel !== 9) {
189
+ const d0 = vlq(0);
190
+ for (const b of d0)
191
+ data.push(b);
192
+ data.push(0xC0 | midiChannel, currentProgram & 0x7f);
193
+ }
194
+ // Optional: set tempo meta event in track 0 only
195
+ if (ci === 0) {
196
+ // delta 0, set tempo (microseconds per quarter)
197
+ const mpq = Math.round(60000000 / bpm);
198
+ data.push(0x00, 0xff, 0x51, 0x03, (mpq >> 16) & 0xff, (mpq >> 8) & 0xff, mpq & 0xff);
199
+ }
200
+ const secondsPerBeat = 60 / bpm;
201
+ const tickSeconds = secondsPerBeat / 4; // 16th note
202
+ const maxEvents = options.duration ? Math.floor(options.duration / tickSeconds) : events.length;
203
+ const truncatedEvents = events.slice(0, maxEvents);
204
+ for (let ti = 0; ti < truncatedEvents.length; ti++) {
205
+ const ev = truncatedEvents[ti];
206
+ const currTick = ti * ticksPerToken;
207
+ let delta = currTick - lastTick;
208
+ if (delta < 0)
209
+ delta = 0;
210
+ if (!ev || ev.type === 'rest') {
211
+ lastTick = currTick;
212
+ continue;
213
+ }
214
+ if (ev.type === 'note' || ev.type === 'named') {
215
+ const token = String(ev.token || '');
216
+ // If this event has effects (vibrato, portamento, volume slide), emit MIDI text meta events or CCs describing them
217
+ if (Array.isArray(ev.effects)) {
218
+ for (const fx of ev.effects) {
219
+ const fxType = String(fx.type).toLowerCase();
220
+ if (fxType === 'vib') {
221
+ const depth = (Array.isArray(fx.params) && fx.params.length > 0) ? fx.params[0] : undefined;
222
+ const rate = (Array.isArray(fx.params) && fx.params.length > 1) ? fx.params[1] : undefined;
223
+ const shape = (Array.isArray(fx.params) && fx.params.length > 2) ? fx.params[2] : undefined;
224
+ pushMetaText(data, delta, `vib:depth=${depth !== undefined ? depth : ''},rate=${rate !== undefined ? rate : ''},shape=${shape !== undefined ? shape : ''}`);
225
+ delta = 0;
226
+ break;
227
+ }
228
+ else if (fxType === 'port') {
229
+ const speed = (Array.isArray(fx.params) && fx.params.length > 0) ? fx.params[0] : undefined;
230
+ const duration = (Array.isArray(fx.params) && fx.params.length > 1) ? fx.params[1] : undefined;
231
+ pushMetaText(data, delta, `port:speed=${speed !== undefined ? speed : ''},duration=${duration !== undefined ? duration : ''}`);
232
+ delta = 0;
233
+ break;
234
+ }
235
+ else if (fxType === 'trem') {
236
+ // Tremolo: document via text meta event
237
+ // Note: MIDI doesn't have native tremolo support
238
+ // Effect parameters are preserved for reference/import
239
+ const depth = (Array.isArray(fx.params) && fx.params.length > 0) ? fx.params[0] : undefined;
240
+ const rate = (Array.isArray(fx.params) && fx.params.length > 1) ? fx.params[1] : undefined;
241
+ const waveform = (Array.isArray(fx.params) && fx.params.length > 2) ? fx.params[2] : undefined;
242
+ pushMetaText(data, delta, `trem:depth=${depth !== undefined ? depth : ''},rate=${rate !== undefined ? rate : ''},waveform=${waveform !== undefined ? waveform : 'sine'}`);
243
+ delta = 0;
244
+ break;
245
+ }
246
+ else if (fxType === 'volslide') {
247
+ // Volume slide: emit MIDI CC #7 (Volume) event
248
+ const deltaVal = (Array.isArray(fx.params) && fx.params.length > 0) ? Number(fx.params[0]) : 0;
249
+ const steps = (Array.isArray(fx.params) && fx.params.length > 1) ? Number(fx.params[1]) : undefined;
250
+ // Map BeatBax delta (±10 typical range) to MIDI volume (0-127)
251
+ // Start at mid-volume (64), apply scaled delta
252
+ const startVol = 64;
253
+ const scaledDelta = Math.round(deltaVal * 6.4); // Scale ±10 to ±64
254
+ const targetVol = Math.max(0, Math.min(127, startVol + scaledDelta));
255
+ // Emit initial CC#7 for volume change
256
+ const dbytes = vlq(delta);
257
+ for (const b of dbytes)
258
+ data.push(b);
259
+ data.push(0xB0 | midiChannel, 0x07, targetVol & 0x7f);
260
+ // Add text meta event for reference
261
+ pushMetaText(data, 0, `volSlide:delta=${deltaVal},steps=${steps !== undefined ? steps : 'smooth'}`);
262
+ delta = 0;
263
+ break;
264
+ }
265
+ else if (fxType === 'bend') {
266
+ // Pitch bend: emit MIDI pitch wheel events
267
+ // MIDI pitch wheel range: 0x0000 to 0x3FFF (0-16383), center = 0x2000 (8192)
268
+ // Standard range: ±2 semitones, but we'll map based on actual semitones requested
269
+ const semitones = (Array.isArray(fx.params) && fx.params.length > 0) ? Number(fx.params[0]) : 0;
270
+ const curve = (Array.isArray(fx.params) && fx.params.length > 1) ? String(fx.params[1]) : 'linear';
271
+ const delay = (Array.isArray(fx.params) && fx.params.length > 2) ? Number(fx.params[2]) : undefined;
272
+ const bendTime = (Array.isArray(fx.params) && fx.params.length > 3) ? Number(fx.params[3]) : undefined;
273
+ // MIDI pitch bend range: ±8192 units = ±2 semitones (standard)
274
+ // Map semitones to pitch bend value: value = 8192 + (semitones / 2) * 8192
275
+ // For semitones outside ±2 range, clamp or use RPN to set bend range
276
+ const bendValue = Math.round(8192 + (semitones / 2) * 8192);
277
+ const clampedValue = Math.max(0, Math.min(16383, bendValue));
278
+ // Split 14-bit value into LSB and MSB
279
+ const lsb = clampedValue & 0x7F;
280
+ const msb = (clampedValue >> 7) & 0x7F;
281
+ // Emit pitch bend event (0xE0 | channel)
282
+ const dbytes = vlq(delta);
283
+ for (const b of dbytes)
284
+ data.push(b);
285
+ data.push(0xE0 | midiChannel, lsb, msb);
286
+ // Add text meta event for curve, delay and time (for re-import/reference)
287
+ pushMetaText(data, 0, `bend:semitones=${semitones},curve=${curve},delay=${delay !== undefined ? delay : 'default'},time=${bendTime !== undefined ? bendTime : 'remaining'}`);
288
+ delta = 0;
289
+ break;
290
+ }
291
+ else if (fxType === 'sweep') {
292
+ // Pitch sweep: emit MIDI text meta event (no native MIDI sweep)
293
+ // Could also emit pitch wheel events with calculated target frequency
294
+ const time = (Array.isArray(fx.params) && fx.params.length > 0) ? Number(fx.params[0]) : 0;
295
+ const direction = (Array.isArray(fx.params) && fx.params.length > 1) ? String(fx.params[1]) : 'down';
296
+ const shift = (Array.isArray(fx.params) && fx.params.length > 2) ? Number(fx.params[2]) : 0;
297
+ // Document the sweep for reference
298
+ pushMetaText(data, delta, `sweep:time=${time},direction=${direction},shift=${shift} (GB NR10)`);
299
+ delta = 0;
300
+ break;
301
+ }
302
+ }
303
+ }
304
+ // determine instrument name for this event (fallback to channel default)
305
+ const instName = ev.instrument || (ch && ch.defaultInstrument) || undefined;
306
+ const evProg = resolveProgramForInstrumentName(instName, ch, ev);
307
+ // if program changed and this is melodic channel, emit Program Change
308
+ if (midiChannel !== 9 && evProg !== currentProgram) {
309
+ const dbytes = vlq(delta);
310
+ for (const b of dbytes)
311
+ data.push(b);
312
+ data.push(0xC0 | midiChannel, evProg & 0x7f);
313
+ currentProgram = evProg;
314
+ // reset delta accounting
315
+ lastTick = currTick;
316
+ delta = 0;
317
+ }
318
+ // If this track is mapped to percussion, map named tokens to drum keys
319
+ if (midiChannel === 9) {
320
+ // map known names or fall back to default
321
+ const key = (token && NOISE_TO_DRUM[token.toLowerCase()]) || NOISE_TO_DRUM.default;
322
+ const dbytes = vlq(delta);
323
+ for (const b of dbytes)
324
+ data.push(b);
325
+ data.push(0x99, key & 0xff, 0x64);
326
+ const offDelta = vlq(ticksPerToken);
327
+ for (const b of offDelta)
328
+ data.push(b);
329
+ data.push(0x89, key & 0xff, 0x40);
330
+ lastTick = currTick + ticksPerToken;
331
+ continue;
332
+ }
333
+ // melodic mapping: parse pitch
334
+ const m = token.match(/^([A-G][#bB]?)(-?\d+)$/i);
335
+ if (m) {
336
+ const name = m[1].toUpperCase();
337
+ const octave = parseInt(m[2], 10);
338
+ const midi = noteNameToMidi(name, octave);
339
+ if (midi !== null && typeof midi === 'number') {
340
+ const dbytes = vlq(delta);
341
+ for (const b of dbytes)
342
+ data.push(b);
343
+ data.push(0x90 | midiChannel, midi & 0xff, 0x64);
344
+ const offDeltaBytes = vlq(ticksPerToken);
345
+ for (const b of offDeltaBytes)
346
+ data.push(b);
347
+ data.push(0x80 | midiChannel, midi & 0xff, 0x40);
348
+ lastTick = currTick + ticksPerToken;
349
+ continue;
350
+ }
351
+ }
352
+ lastTick = currTick;
353
+ continue;
354
+ }
355
+ // other event types ignored for MIDI
356
+ lastTick = currTick;
357
+ }
358
+ // End of track meta event
359
+ const endDelta = vlq(0);
360
+ for (const b of endDelta)
361
+ data.push(b);
362
+ data.push(0xff, 0x2f, 0x00);
363
+ const trackBuf = writeChunk('MTrk', data);
364
+ trackBuffers.push(trackBuf);
365
+ }
366
+ // Write file
367
+ const out = Buffer.concat([header, ...trackBuffers]);
368
+ if (opts && opts.debug) {
369
+ console.log(`[DEBUG] MIDI: ${ntracks} tracks, ${ticksPerQuarter} PPQ`);
370
+ }
371
+ if (verbose) {
372
+ console.log(` MIDI configuration:`);
373
+ console.log(` - Format: Type 1 (multi-track)`);
374
+ console.log(` - Tracks: ${ntracks} (1 per channel)`);
375
+ console.log(` - Tempo: ${bpm} BPM`);
376
+ console.log(` - Resolution: ${ticksPerQuarter} PPQ`);
377
+ if (options.channels) {
378
+ console.log(` - Channels exported: ${options.channels.join(', ')}`);
379
+ }
380
+ if (options.duration) {
381
+ console.log(` - Duration: ${options.duration}s`);
382
+ }
383
+ }
384
+ writeFileSync(outPath, out);
385
+ if (verbose) {
386
+ const sizeKB = (out.length / 1024).toFixed(2);
387
+ console.log(`Export complete: ${out.length.toLocaleString()} bytes (${sizeKB} KB) written`);
388
+ }
389
+ }
390
+ //# sourceMappingURL=midiExport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"midiExport.js","sourceRoot":"","sources":["../../src/export/midiExport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,SAAS,WAAW,CAAC,CAAS;IAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC;IACzB,IAAI,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC;IACxB,GAAG,KAAK,CAAC,CAAC;IACV,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,KAAK,CAAC,CAAC;QACb,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAChC,GAAG,KAAK,CAAC,CAAC;IACX,CAAC;IACD,yBAAyB;IACzB,OAAO,IAAI,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC1B,IAAI,MAAM,GAAG,IAAI;YAAE,MAAM,KAAK,CAAC,CAAC;;YAAM,MAAM;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,GAAG,CAAC,CAAS;IACrB,iDAAiD;IACjD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC;IAC3B,IAAI,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;IAC1B,KAAK,KAAK,CAAC,CAAC;IACZ,OAAO,KAAK,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrD,KAAK,KAAK,CAAC,CAAC;IACb,CAAC;IACD,iCAAiC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACrB,CAAC,KAAK,CAAC,CAAC;IACR,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9B,CAAC,KAAK,CAAC,CAAC;IACT,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,EAAU,EAAE,IAAc;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5B,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,YAAY,CAAC,IAAc,EAAE,KAAa,EAAE,IAAY;IAChE,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,GAAG;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAe,EAAE,SAAkB,EAAE,UAAsD,EAAE,EAAE,IAA6C;IAC5K,IAAI,OAAO,GAAG,SAA+B,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;IAE9C,gEAAgE;IAChE,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QAClD,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,MAAM,CAAC;QACzE,gDAAgD;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW;QACvC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU;QACvC,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB;QACnD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3D,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;QACpE,OAAO;IACR,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC;IACxB,IAAI,CAAC,OAAO;QAAE,OAAO,GAAG,UAAU,CAAC;IAEnC,IAAI,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,uBAAuB;IACvB,MAAM,eAAe,GAAG,GAAG,CAAC,CAAC,MAAM;IACnC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,2BAA2B;IAClF,MAAM,GAAG,GAAG,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAEpE,qEAAqE;IACrE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;QAChC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC,CAAC,WAAW,CAAC;IAEf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW;IACvC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAClC,MAAM,CAAC,aAAa,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAE1C,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,kDAAkD;IAClD,MAAM,gBAAgB,GAA2B;QAChD,MAAM,EAAE,EAAE,EAAE,uBAAuB;QACnC,MAAM,EAAE,EAAE,EAAE,0BAA0B;QACtC,IAAI,EAAE,EAAE,EAAE,mBAAmB;QAC7B,KAAK,EAAE,CAAC;KACR,CAAC;IAEF,MAAM,aAAa,GAA2B;QAC7C,EAAE,EAAE,EAAE,EAAE,gBAAgB;QACxB,EAAE,EAAE,EAAE,EAAE,iBAAiB;QACzB,IAAI,EAAE,EAAE,EAAE,YAAY;QACtB,OAAO,EAAE,EAAE;KACX,CAAC;IAEF,SAAS,+BAA+B,CAAC,QAA4B,EAAE,EAAO,EAAE,EAAQ;QACvF,gGAAgG;QAChG,IAAI,EAAE,IAAI,EAAE,CAAC,SAAS,IAAI,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;QAC7F,IAAI,EAAE,IAAI,EAAE,CAAC,SAAS,IAAI,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC/D,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,EAAS,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAM,GAAG,IAAI,CAAC;QAC1C,CAAC;QACD,IAAI,QAAQ,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;YAC/D,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;gBACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAS,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;oBAAE,OAAO,MAAM,GAAG,IAAI,CAAC;YAC1C,CAAC;YACD,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC1C,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,OAAO,gBAAgB,CAAC,MAAM,CAAC;gBACzD,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,OAAO,gBAAgB,CAAC,MAAM,CAAC;gBACzD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,OAAO,gBAAgB,CAAC,IAAI,CAAC;gBACrD,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC;YACxD,CAAC;QACF,CAAC;QACD,sDAAsD;QACtD,IAAI,EAAE,IAAI,EAAE,CAAC,iBAAiB,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC1F,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;YAC9C,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC1C,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,OAAO,gBAAgB,CAAC,MAAM,CAAC;gBACzD,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAAE,OAAO,gBAAgB,CAAC,MAAM,CAAC;gBACzD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,OAAO,gBAAgB,CAAC,IAAI,CAAC;gBACrD,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC;YACxD,CAAC;QACF,CAAC;QACD,OAAO,gBAAgB,CAAC,MAAM,CAAC;IAChC,CAAC;IAED,8FAA8F;IAC9F,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxB,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1G,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,wEAAwE;QACxE,IAAI,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACvD,yEAAyE;QACzE,IAAI,EAAE,IAAI,EAAE,CAAC,iBAAiB,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC1F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;YAC/C,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,WAAW,GAAG,CAAC,CAAC;QACpH,CAAC;QAED,2CAA2C;QAC3C,IAAI,cAAc,GAAG,+BAA+B,CAAC,EAAE,IAAI,EAAE,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACrF,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAClB,KAAK,MAAM,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,cAAc,GAAG,IAAI,CAAC,CAAC;QACtD,CAAC;QAED,iDAAiD;QACjD,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACd,gDAAgD;YAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,cAAc,GAAG,EAAE,GAAG,GAAG,CAAC;QAChC,MAAM,WAAW,GAAG,cAAc,GAAG,CAAC,CAAC,CAAC,YAAY;QACpD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;QAChG,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAEnD,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,eAAe,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YACpD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;YAC/B,MAAM,QAAQ,GAAG,EAAE,GAAG,aAAa,CAAC;YACpC,IAAI,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;YAChC,IAAI,KAAK,GAAG,CAAC;gBAAE,KAAK,GAAG,CAAC,CAAC;YAEzB,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC/B,QAAQ,GAAG,QAAQ,CAAC;gBACpB,SAAS;YACV,CAAC;YAED,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAErC,mHAAmH;gBACnH,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC/B,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;wBAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;wBAC7C,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;4BACtB,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC5F,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC3F,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC5F,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC5J,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;6BAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;4BAC9B,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC5F,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC/F,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC/H,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;6BAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;4BAC9B,wCAAwC;4BACxC,iDAAiD;4BACjD,uDAAuD;4BACvD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC5F,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC3F,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC/F,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,aAAa,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;4BAC1K,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;6BAAM,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;4BAClC,+CAA+C;4BAC/C,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BAC/F,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BACpG,+DAA+D;4BAC/D,+CAA+C;4BAC/C,MAAM,QAAQ,GAAG,EAAE,CAAC;4BACpB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,mBAAmB;4BACnE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC;4BAErE,sCAAsC;4BACtC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;4BAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;gCAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;4BACrC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC;4BAEtD,oCAAoC;4BACpC,YAAY,CAAC,IAAI,EAAE,CAAC,EAAE,kBAAkB,QAAQ,UAAU,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;4BACpG,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;6BAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;4BAC9B,2CAA2C;4BAC3C,6EAA6E;4BAC7E,kFAAkF;4BAClF,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BAChG,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;4BACnG,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BACpG,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAEvG,+DAA+D;4BAC/D,2EAA2E;4BAC3E,qEAAqE;4BACrE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;4BAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;4BAE7D,sCAAsC;4BACtC,MAAM,GAAG,GAAG,YAAY,GAAG,IAAI,CAAC;4BAChC,MAAM,GAAG,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;4BAEvC,yCAAyC;4BACzC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;4BAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;gCAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;4BACrC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;4BAExC,0EAA0E;4BAC1E,YAAY,CAAC,IAAI,EAAE,CAAC,EAAE,kBAAkB,SAAS,UAAU,KAAK,UAAU,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,SAAS,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;4BAC7K,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;6BAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;4BAC/B,gEAAgE;4BAChE,sEAAsE;4BACtE,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BAC3F,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;4BACrG,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BAE5F,mCAAmC;4BACnC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,IAAI,cAAc,SAAS,UAAU,KAAK,YAAY,CAAC,CAAC;4BAChG,KAAK,GAAG,CAAC,CAAC;4BACV,MAAM;wBACP,CAAC;oBACF,CAAC;gBACF,CAAC;gBAED,yEAAyE;gBACzE,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,iBAAiB,CAAC,IAAI,SAAS,CAAC;gBAC5E,MAAM,MAAM,GAAG,+BAA+B,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;gBAEjE,sEAAsE;gBACtE,IAAI,WAAW,KAAK,CAAC,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;oBACpD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;oBAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;wBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;oBAC7C,cAAc,GAAG,MAAM,CAAC;oBACxB,yBAAyB;oBACzB,QAAQ,GAAG,QAAQ,CAAC;oBACpB,KAAK,GAAG,CAAC,CAAC;gBACX,CAAC;gBAED,uEAAuE;gBACvE,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;oBACvB,0CAA0C;oBAC1C,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,aAAa,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC;oBACnF,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;oBAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;wBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;oBAClC,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC;oBACpC,KAAK,MAAM,CAAC,IAAI,QAAQ;wBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;oBAClC,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;oBACpC,SAAS;gBACV,CAAC;gBAED,+BAA+B;gBAC/B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBACjD,IAAI,CAAC,EAAE,CAAC;oBACP,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;oBAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAClC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;wBAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;wBAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;4BAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;wBACrC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;wBACjD,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC;wBACzC,KAAK,MAAM,CAAC,IAAI,aAAa;4BAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;wBAC5C,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;wBACjD,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;wBACpC,SAAS;oBACV,CAAC;gBACF,CAAC;gBAED,QAAQ,GAAG,QAAQ,CAAC;gBACpB,SAAS;YACV,CAAC;YAED,qCAAqC;YACrC,QAAQ,GAAG,QAAQ,CAAC;QACrB,CAAC;QAED,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE5B,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1C,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAED,aAAa;IACb,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IACrD,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,YAAY,eAAe,MAAM,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,kBAAkB,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,MAAM,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,qBAAqB,eAAe,MAAM,CAAC,CAAC;QACxD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,4BAA4B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrD,CAAC;IACF,CAAC;IAED,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAE5B,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,MAAM,cAAc,CAAC,CAAC;IAC7F,CAAC;AACF,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * UGE v6 binary file writer for hUGETracker.
3
+ *
4
+ * This writer exports a beatbax SongModel to a valid UGE v6 file that can be
5
+ * opened in hUGETracker and processed by uge2source.exe.
6
+ *
7
+ * Format spec: Based on hUGETracker source (song.pas, HugeDatatypes.pas)
8
+ * Reference implementation: generate_minimal_uge.py (validated with uge2source.exe)
9
+ *
10
+ * Key discoveries:
11
+ * - TInstrumentV3 is a packed record with embedded TPattern (64 cells × 17 bytes)
12
+ * - SubpatternEnabled is a semantic flag; bytes are ALWAYS written (1381 bytes per instrument)
13
+ * - Pascal AnsiString format: u32 length + bytes (length does NOT include null terminator)
14
+ * - Pattern cell v6 (TCellV2): 17 bytes = Note(u32) + Instrument(u32) + Volume(u32) + EffectCode(u32) + EffectParams(u8)
15
+ * - Volume field: 0x00005A00 (23040) means "no volume change"
16
+ */
17
+ import { SongModel } from '../song/songModel.js';
18
+ /**
19
+ * Write a minimal wave instrument (TInstrumentV3 with type=1)
20
+ * Total size: 1381 bytes
21
+ */
22
+ export declare function mapWaveVolumeToUGE(vol: any): number;
23
+ export declare function convertPanToEnum(pan: any, strictGb: boolean, context?: 'instrument' | 'inline'): 'L' | 'C' | 'R' | undefined;
24
+ /**
25
+ * Export a beatbax SongModel to UGE v6 binary format.
26
+ */
27
+ export declare function exportUGE(song: SongModel, outputPath: string, opts?: {
28
+ debug?: boolean;
29
+ strictGb?: boolean;
30
+ verbose?: boolean;
31
+ }): Promise<void>;
32
+ export default exportUGE;
33
+ //# sourceMappingURL=ugeWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ugeWriter.d.ts","sourceRoot":"","sources":["../../src/export/ugeWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,SAAS,EAA2B,MAAM,sBAAsB,CAAC;AAqpB1E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAenD;AA4nBD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAE,YAAY,GAAG,QAAmB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,SAAS,CA0BtI;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmyBzJ;AAED,eAAe,SAAS,CAAC"}