@songram/songram-daw-engine 3.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.
package/dist/index.js ADDED
@@ -0,0 +1,4157 @@
1
+ import Ht from "eventemitter3";
2
+ import { Volume as W, Panner as st, Gain as ot, getDestination as J, getTransport as I, getContext as F, PolySynth as G, Synth as jt, MembraneSynth as $, NoiseSynth as Wt, MetalSynth as lt, Part as Bt, start as Jt, now as tt, Context as Kt, setContext as Xt } from "tone";
3
+ import { SoundFont2 as ht, GeneratorType as T } from "soundfont2";
4
+ const Je = 1e3;
5
+ function et(a) {
6
+ const {
7
+ audioBuffer: t,
8
+ startSample: e,
9
+ offsetSamples: n = 0,
10
+ gain: i = 1,
11
+ name: r,
12
+ color: s,
13
+ fadeIn: c,
14
+ fadeOut: u,
15
+ waveformData: l,
16
+ midiNotes: o,
17
+ midiChannel: h,
18
+ midiProgram: f
19
+ } = a, d = t?.sampleRate ?? a.sampleRate ?? l?.sample_rate, g = t?.length ?? a.sourceDurationSamples ?? (l && d ? Math.ceil(l.duration * d) : void 0);
20
+ if (d === void 0)
21
+ throw new Error(
22
+ "createClip: sampleRate is required when audioBuffer is not provided (can use waveformData.sample_rate)"
23
+ );
24
+ if (g === void 0)
25
+ throw new Error(
26
+ "createClip: sourceDurationSamples is required when audioBuffer is not provided (can use waveformData.duration)"
27
+ );
28
+ t && l && t.sampleRate !== l.sample_rate && console.warn(
29
+ `Sample rate mismatch: audioBuffer (${t.sampleRate}) vs waveformData (${l.sample_rate}). Using audioBuffer sample rate. Waveform visualization may be slightly off.`
30
+ );
31
+ const b = a.durationSamples ?? g;
32
+ return {
33
+ id: Vt(),
34
+ audioBuffer: t,
35
+ startSample: e,
36
+ durationSamples: b,
37
+ offsetSamples: n,
38
+ sampleRate: d,
39
+ sourceDurationSamples: g,
40
+ gain: i,
41
+ name: r,
42
+ color: s,
43
+ fadeIn: c,
44
+ fadeOut: u,
45
+ waveformData: l,
46
+ midiNotes: o,
47
+ midiChannel: h,
48
+ midiProgram: f
49
+ };
50
+ }
51
+ function Ke(a) {
52
+ const {
53
+ audioBuffer: t,
54
+ startTime: e,
55
+ offset: n = 0,
56
+ gain: i = 1,
57
+ name: r,
58
+ color: s,
59
+ fadeIn: c,
60
+ fadeOut: u,
61
+ waveformData: l,
62
+ midiNotes: o,
63
+ midiChannel: h,
64
+ midiProgram: f
65
+ } = a, d = t?.sampleRate ?? a.sampleRate ?? l?.sample_rate;
66
+ if (d === void 0)
67
+ throw new Error(
68
+ "createClipFromSeconds: sampleRate is required when audioBuffer is not provided (can use waveformData.sample_rate)"
69
+ );
70
+ const g = t?.duration ?? a.sourceDuration ?? l?.duration;
71
+ if (g === void 0)
72
+ throw new Error(
73
+ "createClipFromSeconds: sourceDuration is required when audioBuffer is not provided (can use waveformData.duration)"
74
+ );
75
+ t && l && t.sampleRate !== l.sample_rate && console.warn(
76
+ `Sample rate mismatch: audioBuffer (${t.sampleRate}) vs waveformData (${l.sample_rate}). Using audioBuffer sample rate. Waveform visualization may be slightly off.`
77
+ );
78
+ const b = a.duration ?? g;
79
+ return et({
80
+ audioBuffer: t,
81
+ startSample: Math.round(e * d),
82
+ durationSamples: Math.round(b * d),
83
+ offsetSamples: Math.round(n * d),
84
+ sampleRate: d,
85
+ sourceDurationSamples: Math.ceil(g * d),
86
+ gain: i,
87
+ name: r,
88
+ color: s,
89
+ fadeIn: c,
90
+ fadeOut: u,
91
+ waveformData: l,
92
+ midiNotes: o,
93
+ midiChannel: h,
94
+ midiProgram: f
95
+ });
96
+ }
97
+ function Xe(a) {
98
+ const {
99
+ name: t,
100
+ clips: e = [],
101
+ muted: n = !1,
102
+ soloed: i = !1,
103
+ volume: r = 1,
104
+ pan: s = 0,
105
+ color: c,
106
+ height: u,
107
+ spectrogramConfig: l,
108
+ spectrogramColorMap: o
109
+ } = a;
110
+ return {
111
+ id: Vt(),
112
+ name: t,
113
+ clips: e,
114
+ muted: n,
115
+ soloed: i,
116
+ volume: r,
117
+ pan: s,
118
+ color: c,
119
+ height: u,
120
+ spectrogramConfig: l,
121
+ spectrogramColorMap: o
122
+ };
123
+ }
124
+ function Ze(a, t = 44100, e) {
125
+ const i = a.reduce((r, s) => {
126
+ const c = s.clips.reduce((u, l) => Math.max(u, l.startSample + l.durationSamples), 0);
127
+ return Math.max(r, c);
128
+ }, 0) / t;
129
+ return {
130
+ tracks: a,
131
+ duration: i,
132
+ sampleRate: t,
133
+ name: e?.name,
134
+ tempo: e?.tempo,
135
+ timeSignature: e?.timeSignature
136
+ };
137
+ }
138
+ function Vt() {
139
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
140
+ }
141
+ function Qe(a, t, e) {
142
+ return a.clips.filter((n) => {
143
+ const i = n.startSample + n.durationSamples;
144
+ return n.startSample < e && i > t;
145
+ });
146
+ }
147
+ function Ye(a, t) {
148
+ return a.clips.filter((e) => {
149
+ const n = e.startSample + e.durationSamples;
150
+ return t >= e.startSample && t < n;
151
+ });
152
+ }
153
+ function tr(a, t) {
154
+ const e = a.startSample + a.durationSamples, n = t.startSample + t.durationSamples;
155
+ return a.startSample < n && e > t.startSample;
156
+ }
157
+ function rt(a) {
158
+ return [...a].sort((t, e) => t.startSample - e.startSample);
159
+ }
160
+ function er(a) {
161
+ if (a.clips.length === 0) return [];
162
+ const t = rt(a.clips), e = [];
163
+ for (let n = 0; n < t.length - 1; n++) {
164
+ const i = t[n].startSample + t[n].durationSamples, r = t[n + 1].startSample;
165
+ r > i && e.push({
166
+ startSample: i,
167
+ endSample: r,
168
+ durationSamples: r - i
169
+ });
170
+ }
171
+ return e;
172
+ }
173
+ var Zt = /* @__PURE__ */ ((a) => (a.Cursor = "cursor", a.Select = "select", a.Shift = "shift", a.FadeIn = "fadein", a.FadeOut = "fadeout", a))(Zt || {});
174
+ function rr(a, t) {
175
+ return a / t;
176
+ }
177
+ function nr(a, t) {
178
+ return Math.ceil(a * t);
179
+ }
180
+ function ar(a, t) {
181
+ return Math.floor(a / t);
182
+ }
183
+ function ir(a, t) {
184
+ return Math.floor(a * t);
185
+ }
186
+ function sr(a, t, e) {
187
+ return a * t / e;
188
+ }
189
+ function or(a, t, e) {
190
+ return Math.ceil(a * e / t);
191
+ }
192
+ const R = 192;
193
+ function Lt(a, t = R) {
194
+ const [, e] = a;
195
+ return t * (4 / e);
196
+ }
197
+ function Qt(a, t = R) {
198
+ const [e] = a;
199
+ return e * Lt(a, t);
200
+ }
201
+ function cr(a, t, e, n = R) {
202
+ return Math.round(a * 60 * e / (t * n));
203
+ }
204
+ function ur(a, t, e, n = R) {
205
+ return Math.round(a * n * t / (60 * e));
206
+ }
207
+ function lr(a, t) {
208
+ return Math.round(a / t) * t;
209
+ }
210
+ function hr(a, t, e = R) {
211
+ const n = Qt(t, e), i = Lt(t, e), r = Math.floor(a / n) + 1, s = Math.floor(a % n / i) + 1;
212
+ return s === 1 ? `${r}` : `${r}.${s}`;
213
+ }
214
+ const j = -100;
215
+ function Yt(a, t = j) {
216
+ return Number.isNaN(a) ? (console.warn("[songram-daw] dBToNormalized received NaN"), 0) : t >= 0 ? (console.warn("[songram-daw] dBToNormalized floor must be negative, got:", t), 0) : !isFinite(a) || a <= t ? 0 : (a - t) / -t;
217
+ }
218
+ function dr(a, t = j) {
219
+ return isFinite(a) ? t >= 0 ? (console.warn("[songram-daw] normalizedToDb floor must be negative, got:", t), j) : Math.max(0, a) * -t + t : t;
220
+ }
221
+ function fr(a, t = j) {
222
+ if (a <= 0) return 0;
223
+ const e = 20 * Math.log10(a);
224
+ return Yt(e, t);
225
+ }
226
+ function q(a) {
227
+ return a.startSample / a.sampleRate;
228
+ }
229
+ function dt(a) {
230
+ return (a.startSample + a.durationSamples) / a.sampleRate;
231
+ }
232
+ function ft(a) {
233
+ return a.offsetSamples / a.sampleRate;
234
+ }
235
+ function mt(a) {
236
+ return a.durationSamples / a.sampleRate;
237
+ }
238
+ function mr(a, t, e) {
239
+ return Math.floor((a + t) / e) - Math.floor(a / e);
240
+ }
241
+ function te(a, t, e, n) {
242
+ let i = t;
243
+ const r = -a.startSample;
244
+ if (i = Math.max(i, r), n > 0) {
245
+ const s = e[n - 1], u = s.startSample + s.durationSamples - a.startSample;
246
+ i = Math.max(i, u);
247
+ }
248
+ if (n < e.length - 1) {
249
+ const c = e[n + 1].startSample - (a.startSample + a.durationSamples);
250
+ i = Math.min(i, c);
251
+ }
252
+ return i;
253
+ }
254
+ function ee(a, t, e, n, i, r) {
255
+ let s = t;
256
+ if (e === "left") {
257
+ if (s = Math.max(s, -a.startSample), s = Math.max(s, -a.offsetSamples), i > 0) {
258
+ const c = n[i - 1], u = c.startSample + c.durationSamples;
259
+ s = Math.max(s, u - a.startSample);
260
+ }
261
+ s = Math.min(s, a.durationSamples - r);
262
+ } else if (s = Math.max(s, r - a.durationSamples), s = Math.min(s, a.sourceDurationSamples - a.offsetSamples - a.durationSamples), i < n.length - 1) {
263
+ const c = n[i + 1];
264
+ s = Math.min(s, c.startSample - a.startSample - a.durationSamples);
265
+ }
266
+ return s;
267
+ }
268
+ function pr(a, t) {
269
+ return Math.floor(a / t) * t;
270
+ }
271
+ function re(a, t) {
272
+ const e = t - a.startSample, n = a.durationSamples - e, i = a.name ? `${a.name} (1)` : void 0, r = a.name ? `${a.name} (2)` : void 0, s = et({
273
+ startSample: a.startSample,
274
+ durationSamples: e,
275
+ offsetSamples: a.offsetSamples,
276
+ sampleRate: a.sampleRate,
277
+ sourceDurationSamples: a.sourceDurationSamples,
278
+ gain: a.gain,
279
+ name: i,
280
+ color: a.color,
281
+ fadeIn: a.fadeIn,
282
+ audioBuffer: a.audioBuffer,
283
+ waveformData: a.waveformData
284
+ }), c = et({
285
+ startSample: t,
286
+ durationSamples: n,
287
+ offsetSamples: a.offsetSamples + e,
288
+ sampleRate: a.sampleRate,
289
+ sourceDurationSamples: a.sourceDurationSamples,
290
+ gain: a.gain,
291
+ name: r,
292
+ color: a.color,
293
+ fadeOut: a.fadeOut,
294
+ audioBuffer: a.audioBuffer,
295
+ waveformData: a.waveformData
296
+ });
297
+ return { left: s, right: c };
298
+ }
299
+ function ne(a, t, e) {
300
+ const n = a.startSample + a.durationSamples;
301
+ if (t <= a.startSample || t >= n)
302
+ return !1;
303
+ const i = t - a.startSample, r = n - t;
304
+ return i >= e && r >= e;
305
+ }
306
+ function gr(a, t, e = 1.5) {
307
+ const n = t * e;
308
+ return {
309
+ visibleStart: Math.max(0, a - n),
310
+ visibleEnd: a + t + n
311
+ };
312
+ }
313
+ function yr(a, t, e, n) {
314
+ const i = Math.ceil(a / t), r = [];
315
+ for (let s = 0; s < i; s++) {
316
+ const c = s * t, u = Math.min(a - c, t);
317
+ c + u <= e || c >= n || r.push(s);
318
+ }
319
+ return r;
320
+ }
321
+ function vr(a, t, e = 100) {
322
+ return Math.abs(a - t) >= e;
323
+ }
324
+ function K(a) {
325
+ let t = 0;
326
+ for (const e of a)
327
+ for (const n of e.clips) {
328
+ const r = (n.startSample + n.durationSamples) / n.sampleRate;
329
+ t = Math.max(t, r);
330
+ }
331
+ return t;
332
+ }
333
+ function ae(a, t) {
334
+ if (t.length === 0) return 0;
335
+ let e = 0, n = Math.abs(t[0] - a);
336
+ for (let i = 1; i < t.length; i++) {
337
+ const r = Math.abs(t[i] - a);
338
+ r < n && (n = r, e = i);
339
+ }
340
+ return e;
341
+ }
342
+ function br(a, t, e, n, i, r = 0) {
343
+ const l = (e + n / 2 - r) * a / i * i / t + r - n / 2;
344
+ return Math.max(0, l);
345
+ }
346
+ function pt(a, t) {
347
+ return Math.max(0, Math.min(a, t));
348
+ }
349
+ const ie = 44100, se = 1024, oe = [256, 512, 1024, 2048, 4096, 8192], gt = 0.1;
350
+ class ce {
351
+ constructor(t = {}) {
352
+ if (this._tracks = [], this._currentTime = 0, this._playStartPosition = 0, this._isPlaying = !1, this._selectedTrackId = null, this._selectionStart = 0, this._selectionEnd = 0, this._masterVolume = 1, this._loopStart = 0, this._loopEnd = 0, this._isLoopEnabled = !1, this._tracksVersion = 0, this._animFrameId = null, this._disposed = !1, this._listeners = /* @__PURE__ */ new Map(), this._sampleRate = t.sampleRate ?? ie, this._zoomLevels = [...t.zoomLevels ?? oe], this._adapter = t.adapter ?? null, this._zoomLevels.length === 0)
353
+ throw new Error("PlaylistEngine: zoomLevels must not be empty");
354
+ const e = t.samplesPerPixel ?? se, n = this._zoomLevels.indexOf(e);
355
+ if (n === -1)
356
+ throw new Error(
357
+ `PlaylistEngine: samplesPerPixel ${e} is not in zoomLevels [${this._zoomLevels.join(", ")}]. Either pass a samplesPerPixel value that exists in zoomLevels, or include ${e} in your zoomLevels array.`
358
+ );
359
+ this._zoomIndex = n;
360
+ }
361
+ // ---------------------------------------------------------------------------
362
+ // State snapshot
363
+ // ---------------------------------------------------------------------------
364
+ getState() {
365
+ return {
366
+ tracks: this._tracks.map((t) => ({ ...t, clips: [...t.clips] })),
367
+ tracksVersion: this._tracksVersion,
368
+ duration: K(this._tracks),
369
+ currentTime: this._currentTime,
370
+ isPlaying: this._isPlaying,
371
+ samplesPerPixel: this._zoomLevels[this._zoomIndex],
372
+ sampleRate: this._sampleRate,
373
+ selectedTrackId: this._selectedTrackId,
374
+ zoomIndex: this._zoomIndex,
375
+ canZoomIn: this._zoomIndex > 0,
376
+ canZoomOut: this._zoomIndex < this._zoomLevels.length - 1,
377
+ selectionStart: this._selectionStart,
378
+ selectionEnd: this._selectionEnd,
379
+ masterVolume: this._masterVolume,
380
+ loopStart: this._loopStart,
381
+ loopEnd: this._loopEnd,
382
+ isLoopEnabled: this._isLoopEnabled
383
+ };
384
+ }
385
+ // ---------------------------------------------------------------------------
386
+ // Track Management
387
+ // ---------------------------------------------------------------------------
388
+ setTracks(t) {
389
+ this._tracks = [...t], this._tracksVersion++, this._adapter?.setTracks(this._tracks), this._emitStateChange();
390
+ }
391
+ addTrack(t) {
392
+ this._tracks = [...this._tracks, t], this._tracksVersion++, this._adapter?.addTrack ? this._adapter.addTrack(t) : this._adapter?.setTracks(this._tracks), this._emitStateChange();
393
+ }
394
+ removeTrack(t) {
395
+ this._tracks.some((e) => e.id === t) && (this._tracks = this._tracks.filter((e) => e.id !== t), this._tracksVersion++, this._selectedTrackId === t && (this._selectedTrackId = null), this._adapter?.setTracks(this._tracks), this._emitStateChange());
396
+ }
397
+ selectTrack(t) {
398
+ t !== this._selectedTrackId && (this._selectedTrackId = t, this._emitStateChange());
399
+ }
400
+ // ---------------------------------------------------------------------------
401
+ // Clip Editing (delegates to operations/)
402
+ // ---------------------------------------------------------------------------
403
+ moveClip(t, e, n) {
404
+ const i = this._tracks.find((o) => o.id === t);
405
+ if (!i) {
406
+ console.warn(`[songram-daw/engine] moveClip: track "${t}" not found`);
407
+ return;
408
+ }
409
+ const r = i.clips.findIndex((o) => o.id === e);
410
+ if (r === -1) {
411
+ console.warn(
412
+ `[songram-daw/engine] moveClip: clip "${e}" not found in track "${t}"`
413
+ );
414
+ return;
415
+ }
416
+ const s = i.clips[r], c = rt(i.clips), u = c.findIndex((o) => o.id === e), l = te(s, n, c, u);
417
+ l !== 0 && (this._tracks = this._tracks.map((o) => {
418
+ if (o.id !== t) return o;
419
+ const h = o.clips.map(
420
+ (f, d) => d === r ? {
421
+ ...f,
422
+ startSample: Math.floor(f.startSample + l)
423
+ } : f
424
+ );
425
+ return { ...o, clips: h };
426
+ }), this._tracksVersion++, this._adapter?.setTracks(this._tracks), this._emitStateChange());
427
+ }
428
+ splitClip(t, e, n) {
429
+ const i = this._tracks.find((o) => o.id === t);
430
+ if (!i) {
431
+ console.warn(`[songram-daw/engine] splitClip: track "${t}" not found`);
432
+ return;
433
+ }
434
+ const r = i.clips.findIndex((o) => o.id === e);
435
+ if (r === -1) {
436
+ console.warn(
437
+ `[songram-daw/engine] splitClip: clip "${e}" not found in track "${t}"`
438
+ );
439
+ return;
440
+ }
441
+ const s = i.clips[r], c = Math.floor(gt * this._sampleRate);
442
+ if (!ne(s, n, c)) {
443
+ console.warn(
444
+ `[songram-daw/engine] splitClip: cannot split clip "${e}" at sample ${n} (clip range: ${s.startSample}–${s.startSample + s.durationSamples}, minDuration: ${c})`
445
+ );
446
+ return;
447
+ }
448
+ const { left: u, right: l } = re(s, n);
449
+ this._tracks = this._tracks.map((o) => {
450
+ if (o.id !== t) return o;
451
+ const h = [...o.clips];
452
+ return h.splice(r, 1, u, l), { ...o, clips: h };
453
+ }), this._tracksVersion++, this._adapter?.setTracks(this._tracks), this._emitStateChange();
454
+ }
455
+ trimClip(t, e, n, i) {
456
+ const r = this._tracks.find((f) => f.id === t);
457
+ if (!r) {
458
+ console.warn(`[songram-daw/engine] trimClip: track "${t}" not found`);
459
+ return;
460
+ }
461
+ const s = r.clips.findIndex((f) => f.id === e);
462
+ if (s === -1) {
463
+ console.warn(
464
+ `[songram-daw/engine] trimClip: clip "${e}" not found in track "${t}"`
465
+ );
466
+ return;
467
+ }
468
+ const c = r.clips[s], u = rt(r.clips), l = u.findIndex((f) => f.id === e), o = Math.floor(gt * this._sampleRate), h = ee(
469
+ c,
470
+ i,
471
+ n,
472
+ u,
473
+ l,
474
+ o
475
+ );
476
+ h !== 0 && (this._tracks = this._tracks.map((f) => {
477
+ if (f.id !== t) return f;
478
+ const d = f.clips.map((g, b) => b !== s ? g : n === "left" ? {
479
+ ...g,
480
+ startSample: g.startSample + h,
481
+ offsetSamples: g.offsetSamples + h,
482
+ durationSamples: g.durationSamples - h
483
+ } : { ...g, durationSamples: g.durationSamples + h });
484
+ return { ...f, clips: d };
485
+ }), this._tracksVersion++, this._adapter?.setTracks(this._tracks), this._emitStateChange());
486
+ }
487
+ // ---------------------------------------------------------------------------
488
+ // Playback (delegates to adapter, no-ops without adapter)
489
+ // ---------------------------------------------------------------------------
490
+ async init() {
491
+ this._adapter && await this._adapter.init();
492
+ }
493
+ play(t, e) {
494
+ const n = this._currentTime, i = this._playStartPosition;
495
+ if (t !== void 0) {
496
+ const r = K(this._tracks);
497
+ this._currentTime = pt(t, r);
498
+ }
499
+ if (this._playStartPosition = this._currentTime, this._adapter) {
500
+ if (e !== void 0)
501
+ this._adapter.setLoop(!1, this._loopStart, this._loopEnd);
502
+ else if (this._isLoopEnabled) {
503
+ const r = this._currentTime < this._loopEnd;
504
+ this._adapter.setLoop(r, this._loopStart, this._loopEnd);
505
+ }
506
+ try {
507
+ this._adapter.play(this._currentTime, e);
508
+ } catch (r) {
509
+ throw this._currentTime = n, this._playStartPosition = i, r;
510
+ }
511
+ }
512
+ this._isPlaying = !0, this._startTimeUpdateLoop(), this._emit("play"), this._emitStateChange();
513
+ }
514
+ pause() {
515
+ this._isPlaying = !1, this._stopTimeUpdateLoop(), this._adapter?.pause(), this._adapter && (this._currentTime = this._adapter.getCurrentTime()), this._emit("pause"), this._emitStateChange();
516
+ }
517
+ stop() {
518
+ this._isPlaying = !1, this._currentTime = this._playStartPosition, this._stopTimeUpdateLoop(), this._adapter?.setLoop(!1, this._loopStart, this._loopEnd), this._adapter?.stop(), this._emit("stop"), this._emitStateChange();
519
+ }
520
+ seek(t) {
521
+ const e = K(this._tracks);
522
+ this._currentTime = pt(t, e), this._adapter?.seek(this._currentTime), this._emitStateChange();
523
+ }
524
+ setMasterVolume(t) {
525
+ t !== this._masterVolume && (this._masterVolume = t, this._adapter?.setMasterVolume(t), this._emitStateChange());
526
+ }
527
+ getCurrentTime() {
528
+ return this._isPlaying && this._adapter ? this._adapter.getCurrentTime() : this._currentTime;
529
+ }
530
+ // ---------------------------------------------------------------------------
531
+ // Selection & Loop
532
+ // ---------------------------------------------------------------------------
533
+ setSelection(t, e) {
534
+ const n = Math.min(t, e), i = Math.max(t, e);
535
+ n === this._selectionStart && i === this._selectionEnd || (this._selectionStart = n, this._selectionEnd = i, this._emitStateChange());
536
+ }
537
+ setLoopRegion(t, e) {
538
+ const n = Math.min(t, e), i = Math.max(t, e);
539
+ n === this._loopStart && i === this._loopEnd || (this._loopStart = n, this._loopEnd = i, this._adapter?.setLoop(
540
+ this._isLoopEnabled && this._isBeforeLoopEnd(),
541
+ this._loopStart,
542
+ this._loopEnd
543
+ ), this._emitStateChange());
544
+ }
545
+ setLoopEnabled(t) {
546
+ t !== this._isLoopEnabled && (this._isLoopEnabled = t, this._adapter?.setLoop(t && this._isBeforeLoopEnd(), this._loopStart, this._loopEnd), this._emitStateChange());
547
+ }
548
+ // ---------------------------------------------------------------------------
549
+ // Per-Track Audio (delegates to adapter)
550
+ // ---------------------------------------------------------------------------
551
+ setTrackVolume(t, e) {
552
+ const n = this._tracks.find((i) => i.id === t);
553
+ n && (n.volume = e), this._adapter?.setTrackVolume(t, e);
554
+ }
555
+ setTrackMute(t, e) {
556
+ const n = this._tracks.find((i) => i.id === t);
557
+ n && (n.muted = e), this._adapter?.setTrackMute(t, e);
558
+ }
559
+ setTrackSolo(t, e) {
560
+ const n = this._tracks.find((i) => i.id === t);
561
+ n && (n.soloed = e), this._adapter?.setTrackSolo(t, e);
562
+ }
563
+ setTrackPan(t, e) {
564
+ const n = this._tracks.find((i) => i.id === t);
565
+ n && (n.pan = e), this._adapter?.setTrackPan(t, e);
566
+ }
567
+ // ---------------------------------------------------------------------------
568
+ // Zoom
569
+ // ---------------------------------------------------------------------------
570
+ zoomIn() {
571
+ this._zoomIndex > 0 && (this._zoomIndex--, this._emitStateChange());
572
+ }
573
+ zoomOut() {
574
+ this._zoomIndex < this._zoomLevels.length - 1 && (this._zoomIndex++, this._emitStateChange());
575
+ }
576
+ setZoomLevel(t) {
577
+ const e = ae(t, this._zoomLevels);
578
+ e !== this._zoomIndex && (this._zoomIndex = e, this._emitStateChange());
579
+ }
580
+ // ---------------------------------------------------------------------------
581
+ // Events
582
+ // ---------------------------------------------------------------------------
583
+ on(t, e) {
584
+ this._listeners.has(t) || this._listeners.set(t, /* @__PURE__ */ new Set()), this._listeners.get(t).add(e);
585
+ }
586
+ off(t, e) {
587
+ this._listeners.get(t)?.delete(e);
588
+ }
589
+ // ---------------------------------------------------------------------------
590
+ // Lifecycle
591
+ // ---------------------------------------------------------------------------
592
+ dispose() {
593
+ if (!this._disposed) {
594
+ this._disposed = !0, this._stopTimeUpdateLoop();
595
+ try {
596
+ this._adapter?.dispose();
597
+ } catch (t) {
598
+ console.warn("[songram-daw/engine] Error disposing adapter:", t);
599
+ }
600
+ this._listeners.clear();
601
+ }
602
+ }
603
+ // ---------------------------------------------------------------------------
604
+ // Private helpers
605
+ // ---------------------------------------------------------------------------
606
+ _emit(t, ...e) {
607
+ const n = this._listeners.get(t);
608
+ if (n)
609
+ for (const i of n)
610
+ try {
611
+ i(...e);
612
+ } catch (r) {
613
+ console.warn("[songram-daw/engine] Error in event listener:", r);
614
+ }
615
+ }
616
+ /**
617
+ * Returns whether the current playback position is before loopEnd.
618
+ * Used by setLoopEnabled/setLoopRegion during playback — if past loopEnd,
619
+ * Transport loop stays off so playback continues to the end.
620
+ * Note: play() uses an inline check instead — _isPlaying is still false
621
+ * when play() runs, and this method returns true unconditionally when
622
+ * not playing.
623
+ */
624
+ _isBeforeLoopEnd() {
625
+ return this._isPlaying ? (this._adapter?.getCurrentTime() ?? this._currentTime) < this._loopEnd : !0;
626
+ }
627
+ _emitStateChange() {
628
+ this._emit("statechange", this.getState());
629
+ }
630
+ _startTimeUpdateLoop() {
631
+ if (typeof requestAnimationFrame > "u") return;
632
+ this._stopTimeUpdateLoop();
633
+ const t = () => {
634
+ this._disposed || !this._isPlaying || (this._adapter && (this._currentTime = this._adapter.getCurrentTime(), this._emit("timeupdate", this._currentTime)), this._animFrameId = requestAnimationFrame(t));
635
+ };
636
+ this._animFrameId = requestAnimationFrame(t);
637
+ }
638
+ _stopTimeUpdateLoop() {
639
+ this._animFrameId !== null && typeof cancelAnimationFrame < "u" && (cancelAnimationFrame(this._animFrameId), this._animFrameId = null);
640
+ }
641
+ }
642
+ let yt = !1;
643
+ function ct(a) {
644
+ const t = a._param;
645
+ return !t && !yt && (yt = !0, console.warn(
646
+ "[songram-daw] Unable to access Tone.js internal _param. This likely means the Tone.js version is incompatible. Mute scheduling may not work correctly."
647
+ )), t;
648
+ }
649
+ function vt(a, t) {
650
+ const e = new Float32Array(a), n = a - 1;
651
+ for (let i = 0; i < a; i++) {
652
+ const r = i / n;
653
+ e[i] = t ? r : 1 - r;
654
+ }
655
+ return e;
656
+ }
657
+ function ue(a, t) {
658
+ const e = new Float32Array(a), n = a - 1;
659
+ for (let i = 0; i < a; i++) {
660
+ const r = i / n, s = t ? i : a - 1 - i;
661
+ e[s] = Math.exp(2 * r - 1) / Math.E;
662
+ }
663
+ return e;
664
+ }
665
+ function le(a, t) {
666
+ const e = new Float32Array(a), n = t ? Math.PI / 2 : -Math.PI / 2;
667
+ for (let i = 0; i < a; i++)
668
+ e[i] = Math.sin(Math.PI * i / a - n) / 2 + 0.5;
669
+ return e;
670
+ }
671
+ function he(a, t, e = 10) {
672
+ const n = new Float32Array(a);
673
+ for (let i = 0; i < a; i++) {
674
+ const r = t ? i : a - 1 - i, s = i / a;
675
+ n[r] = Math.log(1 + e * s) / Math.log(1 + e);
676
+ }
677
+ return n;
678
+ }
679
+ function Rt(a, t, e) {
680
+ switch (a) {
681
+ case "linear":
682
+ return vt(t, e);
683
+ case "exponential":
684
+ return ue(t, e);
685
+ case "sCurve":
686
+ return le(t, e);
687
+ case "logarithmic":
688
+ return he(t, e);
689
+ default:
690
+ return vt(t, e);
691
+ }
692
+ }
693
+ function bt(a, t, e, n = "linear", i = 0, r = 1) {
694
+ if (!(e <= 0))
695
+ if (n === "linear")
696
+ a.setValueAtTime(i, t), a.linearRampToValueAtTime(r, t + e);
697
+ else if (n === "exponential")
698
+ a.setValueAtTime(Math.max(i, 1e-3), t), a.exponentialRampToValueAtTime(Math.max(r, 1e-3), t + e);
699
+ else {
700
+ const s = Rt(n, 1e4, !0), c = new Float32Array(s.length), u = r - i;
701
+ for (let l = 0; l < s.length; l++)
702
+ c[l] = i + s[l] * u;
703
+ a.setValueCurveAtTime(c, t, e);
704
+ }
705
+ }
706
+ function kt(a, t, e, n = "linear", i = 1, r = 0) {
707
+ if (!(e <= 0))
708
+ if (n === "linear")
709
+ a.setValueAtTime(i, t), a.linearRampToValueAtTime(r, t + e);
710
+ else if (n === "exponential")
711
+ a.setValueAtTime(Math.max(i, 1e-3), t), a.exponentialRampToValueAtTime(Math.max(r, 1e-3), t + e);
712
+ else {
713
+ const s = Rt(n, 1e4, !1), c = new Float32Array(s.length), u = i - r;
714
+ for (let l = 0; l < s.length; l++)
715
+ c[l] = r + s[l] * u;
716
+ a.setValueCurveAtTime(c, t, e);
717
+ }
718
+ }
719
+ class de {
720
+ constructor(t) {
721
+ this.activeSources = /* @__PURE__ */ new Set(), this._scheduleGuardOffset = 0, this.track = t.track, this.volumeNode = new W(this.gainToDb(t.track.gain)), this.panNode = new st({ pan: t.track.stereoPan, channelCount: 2 }), this.muteGain = new ot(t.track.muted ? 0 : 1), this.volumeNode.chain(this.panNode, this.muteGain);
722
+ const e = t.destination || J();
723
+ if (t.effects) {
724
+ const c = t.effects(this.muteGain, e, !1);
725
+ c && (this.effectsCleanup = c);
726
+ } else
727
+ this.muteGain.connect(e);
728
+ const n = t.clips || (t.buffer ? [
729
+ {
730
+ buffer: t.buffer,
731
+ startTime: 0,
732
+ duration: t.buffer.duration,
733
+ offset: 0,
734
+ fadeIn: t.track.fadeIn,
735
+ fadeOut: t.track.fadeOut,
736
+ gain: 1
737
+ }
738
+ ] : []), i = I(), r = F().rawContext, s = this.volumeNode.input.input;
739
+ this.scheduledClips = n.map((c) => {
740
+ const u = r.createGain();
741
+ u.gain.value = c.gain, u.connect(s);
742
+ const l = this.track.startTime + c.startTime, o = i.schedule((h) => {
743
+ l < this._scheduleGuardOffset || this.startClipSource(c, u, h);
744
+ }, l);
745
+ return { clipInfo: c, fadeGainNode: u, scheduleId: o };
746
+ });
747
+ }
748
+ /**
749
+ * Create and start an AudioBufferSourceNode for a clip.
750
+ * Sources are one-shot: each play or loop iteration creates a fresh one.
751
+ */
752
+ startClipSource(t, e, n, i, r) {
753
+ const c = F().rawContext.createBufferSource();
754
+ c.buffer = t.buffer, c.connect(e);
755
+ const u = i ?? t.offset, l = r ?? t.duration;
756
+ try {
757
+ c.start(n, u, l);
758
+ } catch (o) {
759
+ console.warn(
760
+ `[songram-daw] Failed to start source on track "${this.id}" (time=${n}, offset=${u}, duration=${l}):`,
761
+ o
762
+ ), c.disconnect();
763
+ return;
764
+ }
765
+ this.activeSources.add(c), c.onended = () => {
766
+ this.activeSources.delete(c);
767
+ };
768
+ }
769
+ /**
770
+ * Set the schedule guard offset. Schedule callbacks for clips before this
771
+ * offset are suppressed (already handled by startMidClipSources).
772
+ * Must be called before transport.start() and in the loop handler.
773
+ */
774
+ setScheduleGuardOffset(t) {
775
+ this._scheduleGuardOffset = t;
776
+ }
777
+ /**
778
+ * Start sources for clips that span the given Transport position.
779
+ * Used for mid-playback seeking and loop boundary handling where
780
+ * Transport.schedule() callbacks have already passed.
781
+ *
782
+ * Uses strict < for absClipStart to avoid double-creation with
783
+ * schedule callbacks at exact Transport position (e.g., loopStart).
784
+ */
785
+ startMidClipSources(t, e) {
786
+ for (const { clipInfo: n, fadeGainNode: i } of this.scheduledClips) {
787
+ const r = this.track.startTime + n.startTime, s = r + n.duration;
788
+ if (r < t && s > t) {
789
+ const c = t - r, u = n.offset + c, l = n.duration - c;
790
+ this.startClipSource(
791
+ n,
792
+ i,
793
+ e,
794
+ u,
795
+ l
796
+ );
797
+ }
798
+ }
799
+ }
800
+ /**
801
+ * Stop all active AudioBufferSourceNodes and clear the set.
802
+ * Native AudioBufferSourceNodes ignore Transport state changes —
803
+ * they must be explicitly stopped.
804
+ */
805
+ stopAllSources() {
806
+ this.activeSources.forEach((t) => {
807
+ try {
808
+ t.stop();
809
+ } catch (e) {
810
+ console.warn(`[songram-daw] Error stopping source on track "${this.id}":`, e);
811
+ }
812
+ }), this.activeSources.clear();
813
+ }
814
+ /**
815
+ * Schedule fade envelopes for a clip at the given AudioContext time.
816
+ * Uses native GainNode.gain (AudioParam) directly — no _param workaround needed.
817
+ */
818
+ scheduleFades(t, e, n = 0) {
819
+ const { clipInfo: i, fadeGainNode: r } = t, s = r.gain;
820
+ s.cancelScheduledValues(0);
821
+ const c = n - i.offset;
822
+ if (i.fadeIn && c < i.fadeIn.duration) {
823
+ const u = i.fadeIn.duration;
824
+ if (c <= 0)
825
+ bt(
826
+ s,
827
+ e,
828
+ u,
829
+ i.fadeIn.type || "linear",
830
+ 0,
831
+ i.gain
832
+ );
833
+ else {
834
+ const l = u - c, o = c / u, h = i.gain * o;
835
+ bt(
836
+ s,
837
+ e,
838
+ l,
839
+ i.fadeIn.type || "linear",
840
+ h,
841
+ i.gain
842
+ );
843
+ }
844
+ } else
845
+ s.setValueAtTime(i.gain, e);
846
+ if (i.fadeOut) {
847
+ const l = i.duration - i.fadeOut.duration - c;
848
+ if (l > 0) {
849
+ const o = e + l;
850
+ kt(
851
+ s,
852
+ o,
853
+ i.fadeOut.duration,
854
+ i.fadeOut.type || "linear",
855
+ i.gain,
856
+ 0
857
+ );
858
+ } else if (l > -i.fadeOut.duration) {
859
+ const o = -l, h = i.fadeOut.duration - o, f = o / i.fadeOut.duration, d = i.gain * (1 - f);
860
+ kt(
861
+ s,
862
+ e,
863
+ h,
864
+ i.fadeOut.type || "linear",
865
+ d,
866
+ 0
867
+ );
868
+ }
869
+ }
870
+ }
871
+ /**
872
+ * Prepare fade envelopes for all clips based on Transport offset.
873
+ * Called before Transport.start() to schedule fades at correct AudioContext times.
874
+ */
875
+ prepareFades(t, e) {
876
+ this.scheduledClips.forEach((n) => {
877
+ const i = this.track.startTime + n.clipInfo.startTime, r = i + n.clipInfo.duration;
878
+ if (!(e >= r))
879
+ if (e >= i) {
880
+ const s = e - i + n.clipInfo.offset;
881
+ this.scheduleFades(n, t, s);
882
+ } else {
883
+ const s = i - e;
884
+ this.scheduleFades(n, t + s, n.clipInfo.offset);
885
+ }
886
+ });
887
+ }
888
+ /**
889
+ * Cancel all scheduled fade automation and reset to nominal gain.
890
+ * Called on pause/stop to prevent stale fade envelopes.
891
+ */
892
+ cancelFades() {
893
+ this.scheduledClips.forEach(({ fadeGainNode: t, clipInfo: e }) => {
894
+ const n = t.gain;
895
+ n.cancelScheduledValues(0), n.setValueAtTime(e.gain, 0);
896
+ });
897
+ }
898
+ gainToDb(t) {
899
+ return 20 * Math.log10(t);
900
+ }
901
+ setVolume(t) {
902
+ this.track.gain = t, this.volumeNode.volume.value = this.gainToDb(t);
903
+ }
904
+ setPan(t) {
905
+ this.track.stereoPan = t, this.panNode.pan.value = t;
906
+ }
907
+ setMute(t) {
908
+ this.track.muted = t;
909
+ const e = t ? 0 : 1;
910
+ ct(this.muteGain.gain)?.setValueAtTime(e, 0), this.muteGain.gain.value = e;
911
+ }
912
+ setSolo(t) {
913
+ this.track.soloed = t;
914
+ }
915
+ dispose() {
916
+ const t = I();
917
+ if (this.effectsCleanup)
918
+ try {
919
+ this.effectsCleanup();
920
+ } catch (e) {
921
+ console.warn(`[songram-daw] Error during track "${this.id}" effects cleanup:`, e);
922
+ }
923
+ this.stopAllSources(), this.scheduledClips.forEach((e, n) => {
924
+ try {
925
+ t.clear(e.scheduleId);
926
+ } catch (i) {
927
+ console.warn(
928
+ `[songram-daw] Error clearing schedule ${n} on track "${this.id}":`,
929
+ i
930
+ );
931
+ }
932
+ try {
933
+ e.fadeGainNode.disconnect();
934
+ } catch (i) {
935
+ console.warn(
936
+ `[songram-daw] Error disconnecting fadeGain ${n} on track "${this.id}":`,
937
+ i
938
+ );
939
+ }
940
+ });
941
+ try {
942
+ this.volumeNode.dispose();
943
+ } catch (e) {
944
+ console.warn(`[songram-daw] Error disposing volumeNode on track "${this.id}":`, e);
945
+ }
946
+ try {
947
+ this.panNode.dispose();
948
+ } catch (e) {
949
+ console.warn(`[songram-daw] Error disposing panNode on track "${this.id}":`, e);
950
+ }
951
+ try {
952
+ this.muteGain.dispose();
953
+ } catch (e) {
954
+ console.warn(`[songram-daw] Error disposing muteGain on track "${this.id}":`, e);
955
+ }
956
+ }
957
+ get id() {
958
+ return this.track.id;
959
+ }
960
+ get duration() {
961
+ if (this.scheduledClips.length === 0) return 0;
962
+ const t = this.scheduledClips[this.scheduledClips.length - 1];
963
+ return t.clipInfo.startTime + t.clipInfo.duration;
964
+ }
965
+ get buffer() {
966
+ return this.scheduledClips[0]?.clipInfo.buffer;
967
+ }
968
+ get muted() {
969
+ return this.track.muted;
970
+ }
971
+ get startTime() {
972
+ return this.track.startTime;
973
+ }
974
+ }
975
+ function fe(a) {
976
+ return a === 35 || a === 36 ? "kick" : a >= 37 && a <= 40 ? "snare" : a === 41 || a === 43 || a === 45 || a === 47 || a === 48 || a === 50 ? "tom" : "cymbal";
977
+ }
978
+ class me {
979
+ constructor(t) {
980
+ this.track = t.track, this.volumeNode = new W(this.gainToDb(t.track.gain)), this.panNode = new st(t.track.stereoPan), this.muteGain = new ot(t.track.muted ? 0 : 1), this.volumeNode.chain(this.panNode, this.muteGain), this.synth = new G(jt, t.synthOptions), this.synth.connect(this.volumeNode), this.kickSynth = new G($, {
981
+ voice: $,
982
+ options: {
983
+ pitchDecay: 0.05,
984
+ octaves: 6,
985
+ envelope: { attack: 1e-3, decay: 0.4, sustain: 0, release: 0.1 }
986
+ }
987
+ }), this.snareSynth = new Wt({
988
+ noise: { type: "white" },
989
+ envelope: { attack: 1e-3, decay: 0.15, sustain: 0, release: 0.05 }
990
+ }), this.cymbalSynth = new G(lt, {
991
+ voice: lt,
992
+ options: {
993
+ envelope: { attack: 1e-3, decay: 0.3, release: 0.1 },
994
+ harmonicity: 5.1,
995
+ modulationIndex: 32,
996
+ resonance: 4e3,
997
+ octaves: 1.5
998
+ }
999
+ }), this.tomSynth = new G($, {
1000
+ voice: $,
1001
+ options: {
1002
+ pitchDecay: 0.08,
1003
+ octaves: 4,
1004
+ envelope: { attack: 1e-3, decay: 0.3, sustain: 0, release: 0.1 }
1005
+ }
1006
+ }), this.kickSynth.connect(this.volumeNode), this.snareSynth.connect(this.volumeNode), this.cymbalSynth.connect(this.volumeNode), this.tomSynth.connect(this.volumeNode);
1007
+ const e = t.destination || J();
1008
+ if (t.effects) {
1009
+ const n = t.effects(this.muteGain, e, !1);
1010
+ n && (this.effectsCleanup = n);
1011
+ } else
1012
+ this.muteGain.connect(e);
1013
+ this.scheduledClips = t.clips.map((n) => {
1014
+ const i = n.notes.filter((u) => {
1015
+ const l = u.time + u.duration;
1016
+ return u.time < n.offset + n.duration && l > n.offset;
1017
+ }), r = this.track.startTime + n.startTime, s = i.map((u) => {
1018
+ const l = u.time - n.offset, o = Math.max(0, l), h = Math.min(
1019
+ u.duration - Math.max(0, n.offset - u.time),
1020
+ n.duration - o
1021
+ );
1022
+ return {
1023
+ time: r + o,
1024
+ note: u.name,
1025
+ midi: u.midi,
1026
+ duration: Math.max(0, h),
1027
+ velocity: u.velocity,
1028
+ channel: u.channel
1029
+ };
1030
+ }), c = new Bt((u, l) => {
1031
+ l.duration > 0 && this.triggerNote(
1032
+ l.midi,
1033
+ l.note,
1034
+ l.duration,
1035
+ u,
1036
+ l.velocity,
1037
+ l.channel
1038
+ );
1039
+ }, s);
1040
+ return c.start(0), { clipInfo: n, part: c };
1041
+ });
1042
+ }
1043
+ /**
1044
+ * Trigger a note using the appropriate synth.
1045
+ * Routes per-note: channel 9 → percussion synths, others → melodic PolySynth.
1046
+ */
1047
+ triggerNote(t, e, n, i, r, s) {
1048
+ if (s === 9)
1049
+ switch (fe(t)) {
1050
+ case "kick":
1051
+ this.kickSynth.triggerAttackRelease("C1", n, i, r);
1052
+ break;
1053
+ case "snare":
1054
+ try {
1055
+ this.snareSynth.triggerAttackRelease(n, i, r);
1056
+ } catch (u) {
1057
+ console.warn(
1058
+ "[songram-daw] Snare overlap — previous hit still decaying, skipped:",
1059
+ u
1060
+ );
1061
+ }
1062
+ break;
1063
+ case "tom": {
1064
+ const u = {
1065
+ 41: "G1",
1066
+ 43: "A1",
1067
+ 45: "C2",
1068
+ 47: "D2",
1069
+ 48: "E2",
1070
+ 50: "G2"
1071
+ };
1072
+ this.tomSynth.triggerAttackRelease(
1073
+ u[t] || "C2",
1074
+ n,
1075
+ i,
1076
+ r
1077
+ );
1078
+ break;
1079
+ }
1080
+ case "cymbal":
1081
+ this.cymbalSynth.triggerAttackRelease("C4", n, i, r);
1082
+ break;
1083
+ }
1084
+ else
1085
+ this.synth.triggerAttackRelease(e, n, i, r);
1086
+ }
1087
+ gainToDb(t) {
1088
+ return 20 * Math.log10(t);
1089
+ }
1090
+ /**
1091
+ * No-op for MIDI — schedule guard is for AudioBufferSourceNode ghost tick prevention.
1092
+ * Tone.Part handles its own scheduling relative to Transport.
1093
+ */
1094
+ setScheduleGuardOffset(t) {
1095
+ }
1096
+ /**
1097
+ * For MIDI, mid-clip sources are notes that should already be sounding.
1098
+ * We trigger them with their remaining duration.
1099
+ */
1100
+ startMidClipSources(t, e) {
1101
+ for (const { clipInfo: n } of this.scheduledClips) {
1102
+ const i = this.track.startTime + n.startTime, r = i + n.duration;
1103
+ if (i < t && r > t)
1104
+ for (const s of n.notes) {
1105
+ const c = s.time - n.offset, u = i + Math.max(0, c), l = u + s.duration;
1106
+ if (u < t && l > t) {
1107
+ const o = l - t;
1108
+ try {
1109
+ this.triggerNote(
1110
+ s.midi,
1111
+ s.name,
1112
+ o,
1113
+ e,
1114
+ s.velocity,
1115
+ s.channel
1116
+ );
1117
+ } catch (h) {
1118
+ console.warn(
1119
+ `[songram-daw] Failed to start mid-clip MIDI note "${s.name}" on track "${this.id}":`,
1120
+ h
1121
+ );
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+ }
1127
+ /**
1128
+ * Stop all sounding notes and cancel scheduled Part events.
1129
+ */
1130
+ stopAllSources() {
1131
+ const t = F().rawContext.currentTime;
1132
+ try {
1133
+ this.synth.releaseAll(t), this.kickSynth.releaseAll(t), this.cymbalSynth.releaseAll(t), this.tomSynth.releaseAll(t);
1134
+ } catch (e) {
1135
+ console.warn(`[songram-daw] Error releasing synth on track "${this.id}":`, e);
1136
+ }
1137
+ }
1138
+ /**
1139
+ * No-op for MIDI — MIDI uses note velocity, not gain fades.
1140
+ */
1141
+ prepareFades(t, e) {
1142
+ }
1143
+ /**
1144
+ * No-op for MIDI — no fade automation to cancel.
1145
+ */
1146
+ cancelFades() {
1147
+ }
1148
+ setVolume(t) {
1149
+ this.track.gain = t, this.volumeNode.volume.value = this.gainToDb(t);
1150
+ }
1151
+ setPan(t) {
1152
+ this.track.stereoPan = t, this.panNode.pan.value = t;
1153
+ }
1154
+ setMute(t) {
1155
+ this.track.muted = t;
1156
+ const e = t ? 0 : 1;
1157
+ ct(this.muteGain.gain)?.setValueAtTime(e, 0), this.muteGain.gain.value = e;
1158
+ }
1159
+ setSolo(t) {
1160
+ this.track.soloed = t;
1161
+ }
1162
+ dispose() {
1163
+ if (this.effectsCleanup)
1164
+ try {
1165
+ this.effectsCleanup();
1166
+ } catch (e) {
1167
+ console.warn(
1168
+ `[songram-daw] Error during MIDI track "${this.id}" effects cleanup:`,
1169
+ e
1170
+ );
1171
+ }
1172
+ this.stopAllSources(), this.scheduledClips.forEach(({ part: e }, n) => {
1173
+ try {
1174
+ e.dispose();
1175
+ } catch (i) {
1176
+ console.warn(
1177
+ `[songram-daw] Error disposing Part ${n} on MIDI track "${this.id}":`,
1178
+ i
1179
+ );
1180
+ }
1181
+ });
1182
+ const t = [
1183
+ this.synth,
1184
+ this.kickSynth,
1185
+ this.snareSynth,
1186
+ this.cymbalSynth,
1187
+ this.tomSynth
1188
+ ];
1189
+ for (const e of t)
1190
+ try {
1191
+ e?.dispose();
1192
+ } catch (n) {
1193
+ console.warn(`[songram-daw] Error disposing synth on MIDI track "${this.id}":`, n);
1194
+ }
1195
+ try {
1196
+ this.volumeNode.dispose();
1197
+ } catch (e) {
1198
+ console.warn(
1199
+ `[songram-daw] Error disposing volumeNode on MIDI track "${this.id}":`,
1200
+ e
1201
+ );
1202
+ }
1203
+ try {
1204
+ this.panNode.dispose();
1205
+ } catch (e) {
1206
+ console.warn(`[songram-daw] Error disposing panNode on MIDI track "${this.id}":`, e);
1207
+ }
1208
+ try {
1209
+ this.muteGain.dispose();
1210
+ } catch (e) {
1211
+ console.warn(`[songram-daw] Error disposing muteGain on MIDI track "${this.id}":`, e);
1212
+ }
1213
+ }
1214
+ get id() {
1215
+ return this.track.id;
1216
+ }
1217
+ get duration() {
1218
+ if (this.scheduledClips.length === 0) return 0;
1219
+ const t = this.scheduledClips[this.scheduledClips.length - 1];
1220
+ return t.clipInfo.startTime + t.clipInfo.duration;
1221
+ }
1222
+ get muted() {
1223
+ return this.track.muted;
1224
+ }
1225
+ get startTime() {
1226
+ return this.track.startTime;
1227
+ }
1228
+ }
1229
+ const L = class L {
1230
+ constructor(t) {
1231
+ this.activeSources = /* @__PURE__ */ new Set(), this.track = t.track, this.soundFontCache = t.soundFontCache, this.programNumber = t.programNumber ?? 0, this.bankNumber = t.isPercussion ? 128 : 0, this.volumeNode = new W(this.gainToDb(t.track.gain)), this.panNode = new st(t.track.stereoPan), this.muteGain = new ot(t.track.muted ? 0 : 1), this.volumeNode.chain(this.panNode, this.muteGain);
1232
+ const e = t.destination || J();
1233
+ if (t.effects) {
1234
+ const n = t.effects(this.muteGain, e, !1);
1235
+ n && (this.effectsCleanup = n);
1236
+ } else
1237
+ this.muteGain.connect(e);
1238
+ this.scheduledClips = t.clips.map((n) => {
1239
+ const i = n.notes.filter((u) => {
1240
+ const l = u.time + u.duration;
1241
+ return u.time < n.offset + n.duration && l > n.offset;
1242
+ }), r = this.track.startTime + n.startTime, s = i.map((u) => {
1243
+ const l = u.time - n.offset, o = Math.max(0, l), h = Math.min(
1244
+ u.duration - Math.max(0, n.offset - u.time),
1245
+ n.duration - o
1246
+ );
1247
+ return {
1248
+ time: r + o,
1249
+ note: u.name,
1250
+ midi: u.midi,
1251
+ duration: Math.max(0, h),
1252
+ velocity: u.velocity,
1253
+ channel: u.channel
1254
+ };
1255
+ }), c = new Bt((u, l) => {
1256
+ l.duration > 0 && this.triggerNote(l.midi, l.duration, u, l.velocity, l.channel);
1257
+ }, s);
1258
+ return c.start(0), { clipInfo: n, part: c };
1259
+ });
1260
+ }
1261
+ /**
1262
+ * Trigger a note by creating a native AudioBufferSourceNode from the SoundFont cache.
1263
+ *
1264
+ * Per-note routing: channel 9 → bank 128 (drums), others → bank 0 with programNumber.
1265
+ */
1266
+ triggerNote(t, e, n, i, r) {
1267
+ const s = r === 9 ? 128 : this.bankNumber, c = r === 9 ? 0 : this.programNumber, u = this.soundFontCache.getAudioBuffer(t, s, c);
1268
+ if (!u) {
1269
+ L._missingSampleWarned || (console.warn(
1270
+ `[songram-daw] SoundFont sample not found for MIDI note ${t} (bank ${s}, preset ${c}). Subsequent missing samples will be silent.`
1271
+ ), L._missingSampleWarned = !0);
1272
+ return;
1273
+ }
1274
+ const l = F().rawContext, o = l.createBufferSource();
1275
+ o.buffer = u.buffer, o.playbackRate.value = u.playbackRate, (u.loopMode === 1 || u.loopMode === 3) && (o.loop = !0, o.loopStart = u.loopStart, o.loopEnd = u.loopEnd);
1276
+ const h = u.buffer.duration / u.playbackRate, f = u.loopMode === 0 ? Math.max(e, h) : e, d = i * i, g = l.createGain(), { attackVolEnv: b, holdVolEnv: y, decayVolEnv: m, sustainVolEnv: v, releaseVolEnv: k } = u, p = d * v;
1277
+ g.gain.setValueAtTime(0, n), g.gain.linearRampToValueAtTime(d, n + b), y > 1e-3 && g.gain.setValueAtTime(d, n + b + y);
1278
+ const S = n + b + y;
1279
+ g.gain.linearRampToValueAtTime(p, S + m), g.gain.setValueAtTime(p, n + f), g.gain.linearRampToValueAtTime(0, n + f + k), o.connect(g), g.connect(this.volumeNode.input.input), this.activeSources.add(o), o.onended = () => {
1280
+ this.activeSources.delete(o);
1281
+ try {
1282
+ g.disconnect();
1283
+ } catch (w) {
1284
+ console.warn("[songram-daw] GainNode already disconnected:", w);
1285
+ }
1286
+ }, o.start(n), o.stop(n + f + k);
1287
+ }
1288
+ gainToDb(t) {
1289
+ return 20 * Math.log10(t);
1290
+ }
1291
+ /**
1292
+ * No-op — Tone.Part handles scheduling internally, no ghost tick guard needed.
1293
+ */
1294
+ setScheduleGuardOffset(t) {
1295
+ }
1296
+ /**
1297
+ * Start notes that should already be sounding at the current transport offset.
1298
+ */
1299
+ startMidClipSources(t, e) {
1300
+ for (const { clipInfo: n } of this.scheduledClips) {
1301
+ const i = this.track.startTime + n.startTime, r = i + n.duration;
1302
+ if (i < t && r > t)
1303
+ for (const s of n.notes) {
1304
+ const c = s.time - n.offset, u = i + Math.max(0, c), l = u + s.duration;
1305
+ if (u < t && l > t) {
1306
+ const o = l - t;
1307
+ try {
1308
+ this.triggerNote(
1309
+ s.midi,
1310
+ o,
1311
+ e,
1312
+ s.velocity,
1313
+ s.channel
1314
+ );
1315
+ } catch (h) {
1316
+ console.warn(
1317
+ `[songram-daw] Failed to start mid-clip SoundFont note on track "${this.id}":`,
1318
+ h
1319
+ );
1320
+ }
1321
+ }
1322
+ }
1323
+ }
1324
+ }
1325
+ /**
1326
+ * Stop all active AudioBufferSourceNodes.
1327
+ */
1328
+ stopAllSources() {
1329
+ for (const t of this.activeSources)
1330
+ try {
1331
+ t.stop();
1332
+ } catch (e) {
1333
+ console.warn("[songram-daw] Error stopping AudioBufferSourceNode:", e);
1334
+ }
1335
+ this.activeSources.clear();
1336
+ }
1337
+ /** No-op for MIDI — MIDI uses note velocity, not gain fades. */
1338
+ prepareFades(t, e) {
1339
+ }
1340
+ /** No-op for MIDI — no fade automation to cancel. */
1341
+ cancelFades() {
1342
+ }
1343
+ setVolume(t) {
1344
+ this.track.gain = t, this.volumeNode.volume.value = this.gainToDb(t);
1345
+ }
1346
+ setPan(t) {
1347
+ this.track.stereoPan = t, this.panNode.pan.value = t;
1348
+ }
1349
+ setMute(t) {
1350
+ this.track.muted = t;
1351
+ const e = t ? 0 : 1;
1352
+ ct(this.muteGain.gain)?.setValueAtTime(e, 0), this.muteGain.gain.value = e;
1353
+ }
1354
+ setSolo(t) {
1355
+ this.track.soloed = t;
1356
+ }
1357
+ dispose() {
1358
+ if (this.effectsCleanup)
1359
+ try {
1360
+ this.effectsCleanup();
1361
+ } catch (t) {
1362
+ console.warn(
1363
+ `[songram-daw] Error during SoundFont track "${this.id}" effects cleanup:`,
1364
+ t
1365
+ );
1366
+ }
1367
+ this.stopAllSources(), this.scheduledClips.forEach(({ part: t }, e) => {
1368
+ try {
1369
+ t.dispose();
1370
+ } catch (n) {
1371
+ console.warn(
1372
+ `[songram-daw] Error disposing Part ${e} on SoundFont track "${this.id}":`,
1373
+ n
1374
+ );
1375
+ }
1376
+ });
1377
+ try {
1378
+ this.volumeNode.dispose();
1379
+ } catch (t) {
1380
+ console.warn(
1381
+ `[songram-daw] Error disposing volumeNode on SoundFont track "${this.id}":`,
1382
+ t
1383
+ );
1384
+ }
1385
+ try {
1386
+ this.panNode.dispose();
1387
+ } catch (t) {
1388
+ console.warn(
1389
+ `[songram-daw] Error disposing panNode on SoundFont track "${this.id}":`,
1390
+ t
1391
+ );
1392
+ }
1393
+ try {
1394
+ this.muteGain.dispose();
1395
+ } catch (t) {
1396
+ console.warn(
1397
+ `[songram-daw] Error disposing muteGain on SoundFont track "${this.id}":`,
1398
+ t
1399
+ );
1400
+ }
1401
+ }
1402
+ get id() {
1403
+ return this.track.id;
1404
+ }
1405
+ get duration() {
1406
+ if (this.scheduledClips.length === 0) return 0;
1407
+ const t = this.scheduledClips[this.scheduledClips.length - 1];
1408
+ return t.clipInfo.startTime + t.clipInfo.duration;
1409
+ }
1410
+ get muted() {
1411
+ return this.track.muted;
1412
+ }
1413
+ get startTime() {
1414
+ return this.track.startTime;
1415
+ }
1416
+ };
1417
+ L._missingSampleWarned = !1;
1418
+ let nt = L;
1419
+ class pe {
1420
+ constructor(t = {}) {
1421
+ if (this.tracks = /* @__PURE__ */ new Map(), this.isInitialized = !1, this.soloedTracks = /* @__PURE__ */ new Set(), this.manualMuteState = /* @__PURE__ */ new Map(), this._completionEventId = null, this._loopHandler = null, this._loopEnabled = !1, this._loopStart = 0, this._loopEnd = 0, this.masterVolume = new W(this.gainToDb(t.masterGain ?? 1)), t.effects) {
1422
+ const e = t.effects(this.masterVolume, J(), !1);
1423
+ e && (this.effectsCleanup = e);
1424
+ } else
1425
+ this.masterVolume.toDestination();
1426
+ t.tracks && t.tracks.forEach((e) => {
1427
+ this.tracks.set(e.id, e), this.manualMuteState.set(e.id, e.muted);
1428
+ });
1429
+ }
1430
+ gainToDb(t) {
1431
+ return 20 * Math.log10(t);
1432
+ }
1433
+ clearCompletionEvent() {
1434
+ if (this._completionEventId !== null) {
1435
+ try {
1436
+ I().clear(this._completionEventId);
1437
+ } catch (t) {
1438
+ console.warn("[songram-daw] Error clearing Transport completion event:", t);
1439
+ }
1440
+ this._completionEventId = null;
1441
+ }
1442
+ }
1443
+ async init() {
1444
+ this.isInitialized || (await Jt(), this.isInitialized = !0);
1445
+ }
1446
+ addTrack(t) {
1447
+ const e = {
1448
+ ...t,
1449
+ destination: this.masterVolume
1450
+ }, n = new de(e);
1451
+ return this.tracks.set(n.id, n), this.manualMuteState.set(n.id, t.track.muted ?? !1), t.track.soloed && this.soloedTracks.add(n.id), n;
1452
+ }
1453
+ addMidiTrack(t) {
1454
+ const e = {
1455
+ ...t,
1456
+ destination: this.masterVolume
1457
+ }, n = new me(e);
1458
+ return this.tracks.set(n.id, n), this.manualMuteState.set(n.id, t.track.muted ?? !1), t.track.soloed && this.soloedTracks.add(n.id), n;
1459
+ }
1460
+ addSoundFontTrack(t) {
1461
+ const e = {
1462
+ ...t,
1463
+ destination: this.masterVolume
1464
+ }, n = new nt(e);
1465
+ return this.tracks.set(n.id, n), this.manualMuteState.set(n.id, t.track.muted ?? !1), t.track.soloed && this.soloedTracks.add(n.id), n;
1466
+ }
1467
+ /**
1468
+ * Apply solo muting after all tracks have been added.
1469
+ * Call this after adding all tracks to ensure solo logic is applied correctly.
1470
+ */
1471
+ applyInitialSoloState() {
1472
+ this.updateSoloMuting();
1473
+ }
1474
+ removeTrack(t) {
1475
+ const e = this.tracks.get(t);
1476
+ e && (e.dispose(), this.tracks.delete(t), this.manualMuteState.delete(t), this.soloedTracks.delete(t));
1477
+ }
1478
+ getTrack(t) {
1479
+ return this.tracks.get(t);
1480
+ }
1481
+ play(t, e, n) {
1482
+ if (!this.isInitialized)
1483
+ throw new Error("[songram-daw] TonePlayout not initialized. Call init() first.");
1484
+ const i = t ?? tt(), r = I();
1485
+ this.clearCompletionEvent();
1486
+ const s = e ?? 0;
1487
+ this.tracks.forEach((c) => {
1488
+ c.cancelFades(), c.prepareFades(i, s);
1489
+ }), n !== void 0 && (this._completionEventId = r.scheduleOnce(() => {
1490
+ this._completionEventId = null;
1491
+ try {
1492
+ this.onPlaybackCompleteCallback?.();
1493
+ } catch (c) {
1494
+ console.warn("[songram-daw] Error in playback completion callback:", c);
1495
+ }
1496
+ }, s + n));
1497
+ try {
1498
+ r.state !== "stopped" && r.stop(), this.tracks.forEach((c) => c.stopAllSources()), r.loopStart = this._loopStart, r.loopEnd = this._loopEnd, r.loop = this._loopEnabled, this.tracks.forEach((c) => c.setScheduleGuardOffset(s)), e !== void 0 ? r.start(i, e) : r.start(i), r._clock._lastUpdate = i, this.tracks.forEach((c) => {
1499
+ c.startMidClipSources(s, i);
1500
+ });
1501
+ } catch (c) {
1502
+ throw this.clearCompletionEvent(), this.tracks.forEach((u) => u.cancelFades()), console.warn(
1503
+ "[songram-daw] Transport.start() failed. Audio playback could not begin.",
1504
+ c
1505
+ ), c;
1506
+ }
1507
+ }
1508
+ pause() {
1509
+ const t = I();
1510
+ try {
1511
+ t.pause();
1512
+ } catch (e) {
1513
+ console.warn("[songram-daw] Transport.pause() failed:", e);
1514
+ }
1515
+ this.tracks.forEach((e) => e.stopAllSources()), this.tracks.forEach((e) => e.cancelFades()), this.clearCompletionEvent();
1516
+ }
1517
+ stop() {
1518
+ const t = I();
1519
+ try {
1520
+ t.stop();
1521
+ } catch (e) {
1522
+ console.warn("[songram-daw] Transport.stop() failed:", e);
1523
+ }
1524
+ if (this._loopHandler) {
1525
+ try {
1526
+ t.off("loop", this._loopHandler);
1527
+ } catch (e) {
1528
+ console.warn("[songram-daw] Error removing loop handler:", e);
1529
+ }
1530
+ this._loopHandler = null;
1531
+ }
1532
+ this.tracks.forEach((e) => {
1533
+ try {
1534
+ e.stopAllSources();
1535
+ } catch (n) {
1536
+ console.warn(`[songram-daw] Error stopping sources for track "${e.id}":`, n);
1537
+ }
1538
+ }), this.tracks.forEach((e) => {
1539
+ try {
1540
+ e.cancelFades();
1541
+ } catch (n) {
1542
+ console.warn(`[songram-daw] Error canceling fades for track "${e.id}":`, n);
1543
+ }
1544
+ }), this.clearCompletionEvent();
1545
+ }
1546
+ setMasterGain(t) {
1547
+ this.masterVolume.volume.value = this.gainToDb(t);
1548
+ }
1549
+ setSolo(t, e) {
1550
+ const n = this.tracks.get(t);
1551
+ n && (n.setSolo(e), e ? this.soloedTracks.add(t) : this.soloedTracks.delete(t), this.updateSoloMuting());
1552
+ }
1553
+ updateSoloMuting() {
1554
+ const t = this.soloedTracks.size > 0;
1555
+ this.tracks.forEach((e, n) => {
1556
+ if (t)
1557
+ if (!this.soloedTracks.has(n))
1558
+ e.setMute(!0);
1559
+ else {
1560
+ const i = this.manualMuteState.get(n) ?? !1;
1561
+ e.setMute(i);
1562
+ }
1563
+ else {
1564
+ const i = this.manualMuteState.get(n) ?? !1;
1565
+ e.setMute(i);
1566
+ }
1567
+ });
1568
+ }
1569
+ setMute(t, e) {
1570
+ const n = this.tracks.get(t);
1571
+ n && (this.manualMuteState.set(t, e), n.setMute(e));
1572
+ }
1573
+ setLoop(t, e, n) {
1574
+ this._loopEnabled = t, this._loopStart = e, this._loopEnd = n;
1575
+ const i = I();
1576
+ try {
1577
+ i.loopStart = e, i.loopEnd = n, i.loop = t;
1578
+ } catch (r) {
1579
+ console.warn("[songram-daw] Error configuring Transport loop:", r);
1580
+ return;
1581
+ }
1582
+ t && !this._loopHandler ? (this._loopHandler = () => {
1583
+ const r = tt();
1584
+ this.tracks.forEach((s) => {
1585
+ try {
1586
+ s.stopAllSources(), s.cancelFades(), s.setScheduleGuardOffset(this._loopStart), s.startMidClipSources(this._loopStart, r), s.prepareFades(r, this._loopStart);
1587
+ } catch (c) {
1588
+ console.warn(
1589
+ `[songram-daw] Error re-scheduling track "${s.id}" on loop:`,
1590
+ c
1591
+ );
1592
+ }
1593
+ });
1594
+ }, i.on("loop", this._loopHandler)) : !t && this._loopHandler && (i.off("loop", this._loopHandler), this._loopHandler = null);
1595
+ }
1596
+ getCurrentTime() {
1597
+ return I().seconds;
1598
+ }
1599
+ seekTo(t) {
1600
+ I().seconds = t;
1601
+ }
1602
+ dispose() {
1603
+ try {
1604
+ this.stop();
1605
+ } catch (t) {
1606
+ console.warn("[songram-daw] Error stopping Transport during dispose:", t);
1607
+ }
1608
+ if (this.tracks.forEach((t) => {
1609
+ try {
1610
+ t.dispose();
1611
+ } catch (e) {
1612
+ console.warn(`[songram-daw] Error disposing track "${t.id}":`, e);
1613
+ }
1614
+ }), this.tracks.clear(), this.effectsCleanup)
1615
+ try {
1616
+ this.effectsCleanup();
1617
+ } catch (t) {
1618
+ console.warn("[songram-daw] Error during master effects cleanup:", t);
1619
+ }
1620
+ try {
1621
+ this.masterVolume.dispose();
1622
+ } catch (t) {
1623
+ console.warn("[songram-daw] Error disposing master volume:", t);
1624
+ }
1625
+ }
1626
+ get context() {
1627
+ return F();
1628
+ }
1629
+ get sampleRate() {
1630
+ return F().sampleRate;
1631
+ }
1632
+ setOnPlaybackComplete(t) {
1633
+ this.onPlaybackCompleteCallback = t;
1634
+ }
1635
+ }
1636
+ function z(a) {
1637
+ return Math.pow(2, a / 1200);
1638
+ }
1639
+ const ge = 5;
1640
+ function _(a, t) {
1641
+ return a[t]?.value;
1642
+ }
1643
+ function ye(a) {
1644
+ const t = new Float32Array(a.length);
1645
+ for (let e = 0; e < a.length; e++)
1646
+ t[e] = a[e] / 32768;
1647
+ return t;
1648
+ }
1649
+ function ve(a) {
1650
+ const { midiNote: t, overrideRootKey: e, originalPitch: n, coarseTune: i, fineTune: r, pitchCorrection: s } = a, u = t - (e !== void 0 ? e : n !== 255 ? n : 60) + i + (r + s) / 100;
1651
+ return Math.pow(2, u / 12);
1652
+ }
1653
+ function be(a) {
1654
+ const { generators: t, header: e } = a, n = _(t, T.SampleModes) ?? 0, i = e.startLoop + (_(t, T.StartLoopAddrsOffset) ?? 0) + (_(t, T.StartLoopAddrsCoarseOffset) ?? 0) * 32768, r = e.endLoop + (_(t, T.EndLoopAddrsOffset) ?? 0) + (_(t, T.EndLoopAddrsCoarseOffset) ?? 0) * 32768, s = i / e.sampleRate, c = r / e.sampleRate, u = z(
1655
+ _(t, T.AttackVolEnv) ?? -12e3
1656
+ ), l = z(
1657
+ _(t, T.HoldVolEnv) ?? -12e3
1658
+ ), o = z(
1659
+ _(t, T.DecayVolEnv) ?? -12e3
1660
+ ), h = Math.min(
1661
+ z(_(t, T.ReleaseVolEnv) ?? -12e3),
1662
+ ge
1663
+ ), f = _(t, T.SustainVolEnv) ?? 0, d = Math.pow(10, -f / 200);
1664
+ return {
1665
+ loopMode: n,
1666
+ loopStart: s,
1667
+ loopEnd: c,
1668
+ attackVolEnv: u,
1669
+ holdVolEnv: l,
1670
+ decayVolEnv: o,
1671
+ sustainVolEnv: d,
1672
+ releaseVolEnv: h
1673
+ };
1674
+ }
1675
+ class kr {
1676
+ /**
1677
+ * @param context Optional AudioContext for createBuffer(). If omitted, uses
1678
+ * an OfflineAudioContext which doesn't require user gesture — safe to
1679
+ * construct before user interaction (avoids Firefox autoplay warnings).
1680
+ */
1681
+ constructor(t) {
1682
+ this.sf2 = null, this.audioBufferCache = /* @__PURE__ */ new Map(), this.context = t ?? new OfflineAudioContext(1, 1, 44100);
1683
+ }
1684
+ /**
1685
+ * Load and parse an SF2 file from a URL.
1686
+ */
1687
+ async load(t, e) {
1688
+ const n = await fetch(t, { signal: e });
1689
+ if (!n.ok)
1690
+ throw new Error(`Failed to fetch SoundFont ${t}: ${n.statusText}`);
1691
+ const i = await n.arrayBuffer();
1692
+ try {
1693
+ this.sf2 = new ht(new Uint8Array(i));
1694
+ } catch (r) {
1695
+ throw new Error(
1696
+ `Failed to parse SoundFont ${t}: ${r instanceof Error ? r.message : String(r)}`
1697
+ );
1698
+ }
1699
+ }
1700
+ /**
1701
+ * Load from an already-fetched ArrayBuffer.
1702
+ */
1703
+ loadFromBuffer(t) {
1704
+ try {
1705
+ this.sf2 = new ht(new Uint8Array(t));
1706
+ } catch (e) {
1707
+ throw new Error(
1708
+ `Failed to parse SoundFont from buffer: ${e instanceof Error ? e.message : String(e)}`
1709
+ );
1710
+ }
1711
+ }
1712
+ get isLoaded() {
1713
+ return this.sf2 !== null;
1714
+ }
1715
+ /**
1716
+ * Look up a MIDI note and return the AudioBuffer + playbackRate.
1717
+ *
1718
+ * @param midiNote - MIDI note number (0-127)
1719
+ * @param bankNumber - Bank number (0 for melodic, 128 for percussion/drums)
1720
+ * @param presetNumber - GM program number (0-127)
1721
+ * @returns SoundFontSample or null if no sample found for this note
1722
+ */
1723
+ getAudioBuffer(t, e = 0, n = 0) {
1724
+ if (!this.sf2) return null;
1725
+ const i = this.sf2.getKeyData(t, e, n);
1726
+ if (!i) return null;
1727
+ const r = i.sample, s = this.sf2.samples.indexOf(r);
1728
+ let c = this.audioBufferCache.get(s);
1729
+ c || (c = this.int16ToAudioBuffer(r.data, r.header.sampleRate), this.audioBufferCache.set(s, c));
1730
+ const u = ve({
1731
+ midiNote: t,
1732
+ overrideRootKey: _(i.generators, T.OverridingRootKey),
1733
+ originalPitch: r.header.originalPitch,
1734
+ coarseTune: _(i.generators, T.CoarseTune) ?? 0,
1735
+ fineTune: _(i.generators, T.FineTune) ?? 0,
1736
+ pitchCorrection: r.header.pitchCorrection ?? 0
1737
+ }), l = be({
1738
+ generators: i.generators,
1739
+ header: i.sample.header
1740
+ });
1741
+ return { buffer: c, playbackRate: u, ...l };
1742
+ }
1743
+ /**
1744
+ * Convert Int16Array sample data to an AudioBuffer.
1745
+ * Uses the extracted int16ToFloat32 for the conversion, then copies into an AudioBuffer.
1746
+ */
1747
+ int16ToAudioBuffer(t, e) {
1748
+ const n = ye(t), i = this.context.createBuffer(1, n.length, e);
1749
+ return i.getChannelData(0).set(n), i;
1750
+ }
1751
+ /**
1752
+ * Clear all cached AudioBuffers and release the parsed SF2.
1753
+ */
1754
+ dispose() {
1755
+ this.audioBufferCache.clear(), this.sf2 = null;
1756
+ }
1757
+ }
1758
+ let x = null;
1759
+ function ut() {
1760
+ return x || (x = new Kt(), Xt(x)), x;
1761
+ }
1762
+ function Sr() {
1763
+ return ut().rawContext;
1764
+ }
1765
+ function wr() {
1766
+ return ut();
1767
+ }
1768
+ async function Tr() {
1769
+ const a = ut();
1770
+ a.state !== "running" && await a.resume();
1771
+ }
1772
+ function _r() {
1773
+ return x?.rawContext.state || "suspended";
1774
+ }
1775
+ async function Cr() {
1776
+ x && x.rawContext.state !== "closed" && (await x.close(), x = null);
1777
+ }
1778
+ const V = /* @__PURE__ */ new Map(), at = /* @__PURE__ */ new Map();
1779
+ function Ir(a) {
1780
+ if (V.has(a))
1781
+ return V.get(a);
1782
+ const e = F().createMediaStreamSource(a);
1783
+ V.set(a, e);
1784
+ const n = () => {
1785
+ e.disconnect(), V.delete(a), at.delete(a), a.removeEventListener("ended", n), a.removeEventListener("inactive", n);
1786
+ };
1787
+ return at.set(a, n), a.addEventListener("ended", n), a.addEventListener("inactive", n), e;
1788
+ }
1789
+ function xr(a) {
1790
+ const t = at.get(a);
1791
+ t && t();
1792
+ }
1793
+ function Mr(a) {
1794
+ return V.has(a);
1795
+ }
1796
+ function ke(a) {
1797
+ let t = null, e = !1, n = 0, i = !1, r = 0, s = 0, c = !1;
1798
+ function u(o, h) {
1799
+ const f = h.clips.filter((g) => g.audioBuffer && !g.midiNotes), d = h.clips.filter((g) => g.midiNotes && g.midiNotes.length > 0);
1800
+ if (f.length > 0) {
1801
+ const g = Math.min(...f.map(q)), b = Math.max(...f.map(dt)), y = {
1802
+ id: h.id,
1803
+ name: h.name,
1804
+ gain: h.volume,
1805
+ muted: h.muted,
1806
+ soloed: h.soloed,
1807
+ stereoPan: h.pan,
1808
+ startTime: g,
1809
+ endTime: b
1810
+ }, m = f.map((v) => ({
1811
+ buffer: v.audioBuffer,
1812
+ startTime: q(v) - g,
1813
+ duration: mt(v),
1814
+ offset: ft(v),
1815
+ fadeIn: v.fadeIn,
1816
+ fadeOut: v.fadeOut,
1817
+ gain: v.gain
1818
+ }));
1819
+ o.addTrack({
1820
+ clips: m,
1821
+ track: y,
1822
+ effects: h.effects
1823
+ });
1824
+ }
1825
+ if (d.length > 0) {
1826
+ const g = Math.min(...d.map(q)), b = Math.max(...d.map(dt)), m = {
1827
+ id: f.length > 0 ? `${h.id}:midi` : h.id,
1828
+ name: h.name,
1829
+ gain: h.volume,
1830
+ muted: h.muted,
1831
+ soloed: h.soloed,
1832
+ stereoPan: h.pan,
1833
+ startTime: g,
1834
+ endTime: b
1835
+ }, v = d.map((k) => ({
1836
+ notes: k.midiNotes,
1837
+ startTime: q(k) - g,
1838
+ duration: mt(k),
1839
+ offset: ft(k)
1840
+ }));
1841
+ if (a?.soundFontCache?.isLoaded) {
1842
+ const k = d[0], S = k.midiChannel === 9, w = k.midiProgram ?? 0;
1843
+ o.addSoundFontTrack({
1844
+ clips: v,
1845
+ track: m,
1846
+ soundFontCache: a.soundFontCache,
1847
+ programNumber: w,
1848
+ isPercussion: S,
1849
+ effects: h.effects
1850
+ });
1851
+ } else
1852
+ a?.soundFontCache && console.warn(
1853
+ `[songram-daw] SoundFont not loaded for track "${h.name}" — falling back to PolySynth.`
1854
+ ), o.addMidiTrack({
1855
+ clips: v,
1856
+ track: m,
1857
+ effects: h.effects
1858
+ });
1859
+ }
1860
+ }
1861
+ function l(o) {
1862
+ if (t) {
1863
+ try {
1864
+ t.dispose();
1865
+ } catch (f) {
1866
+ console.warn("[songram-daw] Error disposing previous playout during rebuild:", f);
1867
+ }
1868
+ t = null;
1869
+ }
1870
+ n++;
1871
+ const h = n;
1872
+ t = new pe({
1873
+ effects: a?.effects
1874
+ }), c && t.init().catch((f) => {
1875
+ console.warn(
1876
+ "[songram-daw] Failed to re-initialize playout after rebuild. Audio playback will require another user gesture.",
1877
+ f
1878
+ ), c = !1;
1879
+ });
1880
+ for (const f of o)
1881
+ u(t, f);
1882
+ t.applyInitialSoloState(), t.setLoop(i, r, s), t.setOnPlaybackComplete(() => {
1883
+ h === n && (e = !1);
1884
+ });
1885
+ }
1886
+ return {
1887
+ async init() {
1888
+ t && (await t.init(), c = !0);
1889
+ },
1890
+ setTracks(o) {
1891
+ l(o);
1892
+ },
1893
+ addTrack(o) {
1894
+ if (!t)
1895
+ throw new Error(
1896
+ "[songram-daw] adapter.addTrack() called but no playout exists. Call setTracks() first to initialize the playout."
1897
+ );
1898
+ u(t, o), t.applyInitialSoloState();
1899
+ },
1900
+ play(o, h) {
1901
+ if (!t) {
1902
+ console.warn(
1903
+ "[songram-daw] adapter.play() called but no playout is available. Tracks may not have been set, or the adapter was disposed."
1904
+ );
1905
+ return;
1906
+ }
1907
+ const f = h !== void 0 ? h - o : void 0;
1908
+ t.play(tt(), o, f), e = !0;
1909
+ },
1910
+ pause() {
1911
+ t?.pause(), e = !1;
1912
+ },
1913
+ stop() {
1914
+ t?.stop(), e = !1;
1915
+ },
1916
+ seek(o) {
1917
+ t?.seekTo(o);
1918
+ },
1919
+ getCurrentTime() {
1920
+ return t?.getCurrentTime() ?? 0;
1921
+ },
1922
+ isPlaying() {
1923
+ return e;
1924
+ },
1925
+ setMasterVolume(o) {
1926
+ t?.setMasterGain(o);
1927
+ },
1928
+ setTrackVolume(o, h) {
1929
+ t?.getTrack(o)?.setVolume(h);
1930
+ },
1931
+ setTrackMute(o, h) {
1932
+ t?.setMute(o, h);
1933
+ },
1934
+ setTrackSolo(o, h) {
1935
+ t?.setSolo(o, h);
1936
+ },
1937
+ setTrackPan(o, h) {
1938
+ t?.getTrack(o)?.setPan(h);
1939
+ },
1940
+ setLoop(o, h, f) {
1941
+ i = o, r = h, s = f, t?.setLoop(o, h, f);
1942
+ },
1943
+ dispose() {
1944
+ try {
1945
+ t?.dispose();
1946
+ } catch (o) {
1947
+ console.warn("[songram-daw] Error disposing playout:", o);
1948
+ }
1949
+ t = null, e = !1;
1950
+ }
1951
+ };
1952
+ }
1953
+ function Se(a) {
1954
+ if (Object.prototype.hasOwnProperty.call(a, "__esModule")) return a;
1955
+ var t = a.default;
1956
+ if (typeof t == "function") {
1957
+ var e = function n() {
1958
+ var i = !1;
1959
+ try {
1960
+ i = this instanceof n;
1961
+ } catch {
1962
+ }
1963
+ return i ? Reflect.construct(t, arguments, this.constructor) : t.apply(this, arguments);
1964
+ };
1965
+ e.prototype = t.prototype;
1966
+ } else e = {};
1967
+ return Object.defineProperty(e, "__esModule", { value: !0 }), Object.keys(a).forEach(function(n) {
1968
+ var i = Object.getOwnPropertyDescriptor(a, n);
1969
+ Object.defineProperty(e, n, i.get ? i : {
1970
+ enumerable: !0,
1971
+ get: function() {
1972
+ return a[n];
1973
+ }
1974
+ });
1975
+ }), e;
1976
+ }
1977
+ var M = {}, H = {}, X, St;
1978
+ function we() {
1979
+ if (St) return X;
1980
+ St = 1;
1981
+ function a(i) {
1982
+ var r = new n(i), s = r.readChunk();
1983
+ if (s.id != "MThd")
1984
+ throw "Bad MIDI file. Expected 'MHdr', got: '" + s.id + "'";
1985
+ for (var c = t(s.data), u = [], l = 0; !r.eof() && l < c.numTracks; l++) {
1986
+ var o = r.readChunk();
1987
+ if (o.id != "MTrk")
1988
+ throw "Bad MIDI file. Expected 'MTrk', got: '" + o.id + "'";
1989
+ var h = e(o.data);
1990
+ u.push(h);
1991
+ }
1992
+ return {
1993
+ header: c,
1994
+ tracks: u
1995
+ };
1996
+ }
1997
+ function t(i) {
1998
+ var r = new n(i), s = r.readUInt16(), c = r.readUInt16(), u = {
1999
+ format: s,
2000
+ numTracks: c
2001
+ }, l = r.readUInt16();
2002
+ return l & 32768 ? (u.framesPerSecond = 256 - (l >> 8), u.ticksPerFrame = l & 255) : u.ticksPerBeat = l, u;
2003
+ }
2004
+ function e(i) {
2005
+ for (var r = new n(i), s = []; !r.eof(); ) {
2006
+ var c = l();
2007
+ s.push(c);
2008
+ }
2009
+ return s;
2010
+ var u;
2011
+ function l() {
2012
+ var o = {};
2013
+ o.deltaTime = r.readVarInt();
2014
+ var h = r.readUInt8();
2015
+ if ((h & 240) === 240)
2016
+ if (h === 255) {
2017
+ o.meta = !0;
2018
+ var f = r.readUInt8(), d = r.readVarInt();
2019
+ switch (f) {
2020
+ case 0:
2021
+ if (o.type = "sequenceNumber", d !== 2) throw "Expected length for sequenceNumber event is 2, got " + d;
2022
+ return o.number = r.readUInt16(), o;
2023
+ case 1:
2024
+ return o.type = "text", o.text = r.readString(d), o;
2025
+ case 2:
2026
+ return o.type = "copyrightNotice", o.text = r.readString(d), o;
2027
+ case 3:
2028
+ return o.type = "trackName", o.text = r.readString(d), o;
2029
+ case 4:
2030
+ return o.type = "instrumentName", o.text = r.readString(d), o;
2031
+ case 5:
2032
+ return o.type = "lyrics", o.text = r.readString(d), o;
2033
+ case 6:
2034
+ return o.type = "marker", o.text = r.readString(d), o;
2035
+ case 7:
2036
+ return o.type = "cuePoint", o.text = r.readString(d), o;
2037
+ case 32:
2038
+ if (o.type = "channelPrefix", d != 1) throw "Expected length for channelPrefix event is 1, got " + d;
2039
+ return o.channel = r.readUInt8(), o;
2040
+ case 33:
2041
+ if (o.type = "portPrefix", d != 1) throw "Expected length for portPrefix event is 1, got " + d;
2042
+ return o.port = r.readUInt8(), o;
2043
+ case 47:
2044
+ if (o.type = "endOfTrack", d != 0) throw "Expected length for endOfTrack event is 0, got " + d;
2045
+ return o;
2046
+ case 81:
2047
+ if (o.type = "setTempo", d != 3) throw "Expected length for setTempo event is 3, got " + d;
2048
+ return o.microsecondsPerBeat = r.readUInt24(), o;
2049
+ case 84:
2050
+ if (o.type = "smpteOffset", d != 5) throw "Expected length for smpteOffset event is 5, got " + d;
2051
+ var g = r.readUInt8(), b = { 0: 24, 32: 25, 64: 29, 96: 30 };
2052
+ return o.frameRate = b[g & 96], o.hour = g & 31, o.min = r.readUInt8(), o.sec = r.readUInt8(), o.frame = r.readUInt8(), o.subFrame = r.readUInt8(), o;
2053
+ case 88:
2054
+ if (o.type = "timeSignature", d != 2 && d != 4) throw "Expected length for timeSignature event is 4 or 2, got " + d;
2055
+ return o.numerator = r.readUInt8(), o.denominator = 1 << r.readUInt8(), d === 4 ? (o.metronome = r.readUInt8(), o.thirtyseconds = r.readUInt8()) : (o.metronome = 36, o.thirtyseconds = 8), o;
2056
+ case 89:
2057
+ if (o.type = "keySignature", d != 2) throw "Expected length for keySignature event is 2, got " + d;
2058
+ return o.key = r.readInt8(), o.scale = r.readUInt8(), o;
2059
+ case 127:
2060
+ return o.type = "sequencerSpecific", o.data = r.readBytes(d), o;
2061
+ default:
2062
+ return o.type = "unknownMeta", o.data = r.readBytes(d), o.metatypeByte = f, o;
2063
+ }
2064
+ } else if (h == 240) {
2065
+ o.type = "sysEx";
2066
+ var d = r.readVarInt();
2067
+ return o.data = r.readBytes(d), o;
2068
+ } else if (h == 247) {
2069
+ o.type = "endSysEx";
2070
+ var d = r.readVarInt();
2071
+ return o.data = r.readBytes(d), o;
2072
+ } else
2073
+ throw "Unrecognised MIDI event type byte: " + h;
2074
+ else {
2075
+ var y;
2076
+ if ((h & 128) === 0) {
2077
+ if (u === null)
2078
+ throw "Running status byte encountered before status byte";
2079
+ y = h, h = u, o.running = !0;
2080
+ } else
2081
+ y = r.readUInt8(), u = h;
2082
+ var m = h >> 4;
2083
+ switch (o.channel = h & 15, m) {
2084
+ case 8:
2085
+ return o.type = "noteOff", o.noteNumber = y, o.velocity = r.readUInt8(), o;
2086
+ case 9:
2087
+ var v = r.readUInt8();
2088
+ return o.type = v === 0 ? "noteOff" : "noteOn", o.noteNumber = y, o.velocity = v, v === 0 && (o.byte9 = !0), o;
2089
+ case 10:
2090
+ return o.type = "noteAftertouch", o.noteNumber = y, o.amount = r.readUInt8(), o;
2091
+ case 11:
2092
+ return o.type = "controller", o.controllerType = y, o.value = r.readUInt8(), o;
2093
+ case 12:
2094
+ return o.type = "programChange", o.programNumber = y, o;
2095
+ case 13:
2096
+ return o.type = "channelAftertouch", o.amount = y, o;
2097
+ case 14:
2098
+ return o.type = "pitchBend", o.value = y + (r.readUInt8() << 7) - 8192, o;
2099
+ default:
2100
+ throw "Unrecognised MIDI event type: " + m;
2101
+ }
2102
+ }
2103
+ }
2104
+ }
2105
+ function n(i) {
2106
+ this.buffer = i, this.bufferLen = this.buffer.length, this.pos = 0;
2107
+ }
2108
+ return n.prototype.eof = function() {
2109
+ return this.pos >= this.bufferLen;
2110
+ }, n.prototype.readUInt8 = function() {
2111
+ var i = this.buffer[this.pos];
2112
+ return this.pos += 1, i;
2113
+ }, n.prototype.readInt8 = function() {
2114
+ var i = this.readUInt8();
2115
+ return i & 128 ? i - 256 : i;
2116
+ }, n.prototype.readUInt16 = function() {
2117
+ var i = this.readUInt8(), r = this.readUInt8();
2118
+ return (i << 8) + r;
2119
+ }, n.prototype.readInt16 = function() {
2120
+ var i = this.readUInt16();
2121
+ return i & 32768 ? i - 65536 : i;
2122
+ }, n.prototype.readUInt24 = function() {
2123
+ var i = this.readUInt8(), r = this.readUInt8(), s = this.readUInt8();
2124
+ return (i << 16) + (r << 8) + s;
2125
+ }, n.prototype.readInt24 = function() {
2126
+ var i = this.readUInt24();
2127
+ return i & 8388608 ? i - 16777216 : i;
2128
+ }, n.prototype.readUInt32 = function() {
2129
+ var i = this.readUInt8(), r = this.readUInt8(), s = this.readUInt8(), c = this.readUInt8();
2130
+ return (i << 24) + (r << 16) + (s << 8) + c;
2131
+ }, n.prototype.readBytes = function(i) {
2132
+ var r = this.buffer.slice(this.pos, this.pos + i);
2133
+ return this.pos += i, r;
2134
+ }, n.prototype.readString = function(i) {
2135
+ var r = this.readBytes(i);
2136
+ return String.fromCharCode.apply(null, r);
2137
+ }, n.prototype.readVarInt = function() {
2138
+ for (var i = 0; !this.eof(); ) {
2139
+ var r = this.readUInt8();
2140
+ if (r & 128)
2141
+ i += r & 127, i <<= 7;
2142
+ else
2143
+ return i + r;
2144
+ }
2145
+ return i;
2146
+ }, n.prototype.readChunk = function() {
2147
+ var i = this.readString(4), r = this.readUInt32(), s = this.readBytes(r);
2148
+ return {
2149
+ id: i,
2150
+ length: r,
2151
+ data: s
2152
+ };
2153
+ }, X = a, X;
2154
+ }
2155
+ var Z, wt;
2156
+ function Te() {
2157
+ if (wt) return Z;
2158
+ wt = 1;
2159
+ function a(r, s) {
2160
+ if (typeof r != "object")
2161
+ throw "Invalid MIDI data";
2162
+ s = s || {};
2163
+ var c = r.header || {}, u = r.tracks || [], l, o = u.length, h = new i();
2164
+ for (t(h, c, o), l = 0; l < o; l++)
2165
+ e(h, u[l], s);
2166
+ return h.buffer;
2167
+ }
2168
+ function t(r, s, c) {
2169
+ var u = s.format == null ? 1 : s.format, l = 128;
2170
+ s.timeDivision ? l = s.timeDivision : s.ticksPerFrame && s.framesPerSecond ? l = -(s.framesPerSecond & 255) << 8 | s.ticksPerFrame & 255 : s.ticksPerBeat && (l = s.ticksPerBeat & 32767);
2171
+ var o = new i();
2172
+ o.writeUInt16(u), o.writeUInt16(c), o.writeUInt16(l), r.writeChunk("MThd", o.buffer);
2173
+ }
2174
+ function e(r, s, c) {
2175
+ var u = new i(), l, o = s.length, h = null;
2176
+ for (l = 0; l < o; l++)
2177
+ (c.running === !1 || !c.running && !s[l].running) && (h = null), h = n(u, s[l], h, c.useByte9ForNoteOff);
2178
+ r.writeChunk("MTrk", u.buffer);
2179
+ }
2180
+ function n(r, s, c, u) {
2181
+ var l = s.type, o = s.deltaTime, h = s.text || "", f = s.data || [], d = null;
2182
+ switch (r.writeVarInt(o), l) {
2183
+ // meta events
2184
+ case "sequenceNumber":
2185
+ r.writeUInt8(255), r.writeUInt8(0), r.writeVarInt(2), r.writeUInt16(s.number);
2186
+ break;
2187
+ case "text":
2188
+ r.writeUInt8(255), r.writeUInt8(1), r.writeVarInt(h.length), r.writeString(h);
2189
+ break;
2190
+ case "copyrightNotice":
2191
+ r.writeUInt8(255), r.writeUInt8(2), r.writeVarInt(h.length), r.writeString(h);
2192
+ break;
2193
+ case "trackName":
2194
+ r.writeUInt8(255), r.writeUInt8(3), r.writeVarInt(h.length), r.writeString(h);
2195
+ break;
2196
+ case "instrumentName":
2197
+ r.writeUInt8(255), r.writeUInt8(4), r.writeVarInt(h.length), r.writeString(h);
2198
+ break;
2199
+ case "lyrics":
2200
+ r.writeUInt8(255), r.writeUInt8(5), r.writeVarInt(h.length), r.writeString(h);
2201
+ break;
2202
+ case "marker":
2203
+ r.writeUInt8(255), r.writeUInt8(6), r.writeVarInt(h.length), r.writeString(h);
2204
+ break;
2205
+ case "cuePoint":
2206
+ r.writeUInt8(255), r.writeUInt8(7), r.writeVarInt(h.length), r.writeString(h);
2207
+ break;
2208
+ case "channelPrefix":
2209
+ r.writeUInt8(255), r.writeUInt8(32), r.writeVarInt(1), r.writeUInt8(s.channel);
2210
+ break;
2211
+ case "portPrefix":
2212
+ r.writeUInt8(255), r.writeUInt8(33), r.writeVarInt(1), r.writeUInt8(s.port);
2213
+ break;
2214
+ case "endOfTrack":
2215
+ r.writeUInt8(255), r.writeUInt8(47), r.writeVarInt(0);
2216
+ break;
2217
+ case "setTempo":
2218
+ r.writeUInt8(255), r.writeUInt8(81), r.writeVarInt(3), r.writeUInt24(s.microsecondsPerBeat);
2219
+ break;
2220
+ case "smpteOffset":
2221
+ r.writeUInt8(255), r.writeUInt8(84), r.writeVarInt(5);
2222
+ var g = { 24: 0, 25: 32, 29: 64, 30: 96 }, b = s.hour & 31 | g[s.frameRate];
2223
+ r.writeUInt8(b), r.writeUInt8(s.min), r.writeUInt8(s.sec), r.writeUInt8(s.frame), r.writeUInt8(s.subFrame);
2224
+ break;
2225
+ case "timeSignature":
2226
+ r.writeUInt8(255), r.writeUInt8(88), r.writeVarInt(4), r.writeUInt8(s.numerator);
2227
+ var y = Math.floor(Math.log(s.denominator) / Math.LN2) & 255;
2228
+ r.writeUInt8(y), r.writeUInt8(s.metronome), r.writeUInt8(s.thirtyseconds || 8);
2229
+ break;
2230
+ case "keySignature":
2231
+ r.writeUInt8(255), r.writeUInt8(89), r.writeVarInt(2), r.writeInt8(s.key), r.writeUInt8(s.scale);
2232
+ break;
2233
+ case "sequencerSpecific":
2234
+ r.writeUInt8(255), r.writeUInt8(127), r.writeVarInt(f.length), r.writeBytes(f);
2235
+ break;
2236
+ case "unknownMeta":
2237
+ s.metatypeByte != null && (r.writeUInt8(255), r.writeUInt8(s.metatypeByte), r.writeVarInt(f.length), r.writeBytes(f));
2238
+ break;
2239
+ // system-exclusive
2240
+ case "sysEx":
2241
+ r.writeUInt8(240), r.writeVarInt(f.length), r.writeBytes(f);
2242
+ break;
2243
+ case "endSysEx":
2244
+ r.writeUInt8(247), r.writeVarInt(f.length), r.writeBytes(f);
2245
+ break;
2246
+ // channel events
2247
+ case "noteOff":
2248
+ var m = u !== !1 && s.byte9 || u && s.velocity == 0 ? 144 : 128;
2249
+ d = m | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.noteNumber), r.writeUInt8(s.velocity);
2250
+ break;
2251
+ case "noteOn":
2252
+ d = 144 | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.noteNumber), r.writeUInt8(s.velocity);
2253
+ break;
2254
+ case "noteAftertouch":
2255
+ d = 160 | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.noteNumber), r.writeUInt8(s.amount);
2256
+ break;
2257
+ case "controller":
2258
+ d = 176 | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.controllerType), r.writeUInt8(s.value);
2259
+ break;
2260
+ case "programChange":
2261
+ d = 192 | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.programNumber);
2262
+ break;
2263
+ case "channelAftertouch":
2264
+ d = 208 | s.channel, d !== c && r.writeUInt8(d), r.writeUInt8(s.amount);
2265
+ break;
2266
+ case "pitchBend":
2267
+ d = 224 | s.channel, d !== c && r.writeUInt8(d);
2268
+ var v = 8192 + s.value, k = v & 127, p = v >> 7 & 127;
2269
+ r.writeUInt8(k), r.writeUInt8(p);
2270
+ break;
2271
+ default:
2272
+ throw "Unrecognized event type: " + l;
2273
+ }
2274
+ return d;
2275
+ }
2276
+ function i() {
2277
+ this.buffer = [];
2278
+ }
2279
+ return i.prototype.writeUInt8 = function(r) {
2280
+ this.buffer.push(r & 255);
2281
+ }, i.prototype.writeInt8 = i.prototype.writeUInt8, i.prototype.writeUInt16 = function(r) {
2282
+ var s = r >> 8 & 255, c = r & 255;
2283
+ this.writeUInt8(s), this.writeUInt8(c);
2284
+ }, i.prototype.writeInt16 = i.prototype.writeUInt16, i.prototype.writeUInt24 = function(r) {
2285
+ var s = r >> 16 & 255, c = r >> 8 & 255, u = r & 255;
2286
+ this.writeUInt8(s), this.writeUInt8(c), this.writeUInt8(u);
2287
+ }, i.prototype.writeInt24 = i.prototype.writeUInt24, i.prototype.writeUInt32 = function(r) {
2288
+ var s = r >> 24 & 255, c = r >> 16 & 255, u = r >> 8 & 255, l = r & 255;
2289
+ this.writeUInt8(s), this.writeUInt8(c), this.writeUInt8(u), this.writeUInt8(l);
2290
+ }, i.prototype.writeInt32 = i.prototype.writeUInt32, i.prototype.writeBytes = function(r) {
2291
+ this.buffer = this.buffer.concat(Array.prototype.slice.call(r, 0));
2292
+ }, i.prototype.writeString = function(r) {
2293
+ var s, c = r.length, u = [];
2294
+ for (s = 0; s < c; s++)
2295
+ u.push(r.codePointAt(s));
2296
+ this.writeBytes(u);
2297
+ }, i.prototype.writeVarInt = function(r) {
2298
+ if (r < 0) throw "Cannot write negative variable-length integer";
2299
+ if (r <= 127)
2300
+ this.writeUInt8(r);
2301
+ else {
2302
+ var s = r, c = [];
2303
+ for (c.push(s & 127), s >>= 7; s; ) {
2304
+ var u = s & 127 | 128;
2305
+ c.push(u), s >>= 7;
2306
+ }
2307
+ this.writeBytes(c.reverse());
2308
+ }
2309
+ }, i.prototype.writeChunk = function(r, s) {
2310
+ this.writeString(r), this.writeUInt32(s.length), this.writeBytes(s);
2311
+ }, Z = a, Z;
2312
+ }
2313
+ var Tt;
2314
+ function Gt() {
2315
+ return Tt || (Tt = 1, H.parseMidi = we(), H.writeMidi = Te()), H;
2316
+ }
2317
+ var Q = {}, E = {}, _t;
2318
+ function $t() {
2319
+ if (_t) return E;
2320
+ _t = 1, Object.defineProperty(E, "__esModule", { value: !0 }), E.insert = E.search = void 0;
2321
+ function a(e, n, i) {
2322
+ i === void 0 && (i = "ticks");
2323
+ var r = 0, s = e.length, c = s;
2324
+ if (s > 0 && e[s - 1][i] <= n)
2325
+ return s - 1;
2326
+ for (; r < c; ) {
2327
+ var u = Math.floor(r + (c - r) / 2), l = e[u], o = e[u + 1];
2328
+ if (l[i] === n) {
2329
+ for (var h = u; h < e.length; h++) {
2330
+ var f = e[h];
2331
+ f[i] === n && (u = h);
2332
+ }
2333
+ return u;
2334
+ } else {
2335
+ if (l[i] < n && o[i] > n)
2336
+ return u;
2337
+ l[i] > n ? c = u : l[i] < n && (r = u + 1);
2338
+ }
2339
+ }
2340
+ return -1;
2341
+ }
2342
+ E.search = a;
2343
+ function t(e, n, i) {
2344
+ if (i === void 0 && (i = "ticks"), e.length) {
2345
+ var r = a(e, n[i], i);
2346
+ e.splice(r + 1, 0, n);
2347
+ } else
2348
+ e.push(n);
2349
+ }
2350
+ return E.insert = t, E;
2351
+ }
2352
+ var Ct;
2353
+ function it() {
2354
+ return Ct || (Ct = 1, (function(a) {
2355
+ Object.defineProperty(a, "__esModule", { value: !0 }), a.Header = a.keySignatureKeys = void 0;
2356
+ var t = $t(), e = /* @__PURE__ */ new WeakMap();
2357
+ a.keySignatureKeys = [
2358
+ "Cb",
2359
+ "Gb",
2360
+ "Db",
2361
+ "Ab",
2362
+ "Eb",
2363
+ "Bb",
2364
+ "F",
2365
+ "C",
2366
+ "G",
2367
+ "D",
2368
+ "A",
2369
+ "E",
2370
+ "B",
2371
+ "F#",
2372
+ "C#"
2373
+ ];
2374
+ var n = (
2375
+ /** @class */
2376
+ (function() {
2377
+ function i(r) {
2378
+ var s = this;
2379
+ if (this.tempos = [], this.timeSignatures = [], this.keySignatures = [], this.meta = [], this.name = "", e.set(this, 480), r) {
2380
+ e.set(this, r.header.ticksPerBeat), r.tracks.forEach(function(u) {
2381
+ u.forEach(function(l) {
2382
+ l.meta && (l.type === "timeSignature" ? s.timeSignatures.push({
2383
+ ticks: l.absoluteTime,
2384
+ timeSignature: [
2385
+ l.numerator,
2386
+ l.denominator
2387
+ ]
2388
+ }) : l.type === "setTempo" ? s.tempos.push({
2389
+ bpm: 6e7 / l.microsecondsPerBeat,
2390
+ ticks: l.absoluteTime
2391
+ }) : l.type === "keySignature" && s.keySignatures.push({
2392
+ key: a.keySignatureKeys[l.key + 7],
2393
+ scale: l.scale === 0 ? "major" : "minor",
2394
+ ticks: l.absoluteTime
2395
+ }));
2396
+ });
2397
+ });
2398
+ var c = 0;
2399
+ r.tracks[0].forEach(function(u) {
2400
+ c += u.deltaTime, u.meta && (u.type === "trackName" ? s.name = u.text : (u.type === "text" || u.type === "cuePoint" || u.type === "marker" || u.type === "lyrics") && s.meta.push({
2401
+ text: u.text,
2402
+ ticks: c,
2403
+ type: u.type
2404
+ }));
2405
+ }), this.update();
2406
+ }
2407
+ }
2408
+ return i.prototype.update = function() {
2409
+ var r = this, s = 0, c = 0;
2410
+ this.tempos.sort(function(u, l) {
2411
+ return u.ticks - l.ticks;
2412
+ }), this.tempos.forEach(function(u, l) {
2413
+ var o = l > 0 ? r.tempos[l - 1].bpm : r.tempos[0].bpm, h = u.ticks / r.ppq - c, f = 60 / o * h;
2414
+ u.time = f + s, s = u.time, c += h;
2415
+ }), this.timeSignatures.sort(function(u, l) {
2416
+ return u.ticks - l.ticks;
2417
+ }), this.timeSignatures.forEach(function(u, l) {
2418
+ var o = l > 0 ? r.timeSignatures[l - 1] : r.timeSignatures[0], h = (u.ticks - o.ticks) / r.ppq, f = h / o.timeSignature[0] / (o.timeSignature[1] / 4);
2419
+ o.measures = o.measures || 0, u.measures = f + o.measures;
2420
+ });
2421
+ }, i.prototype.ticksToSeconds = function(r) {
2422
+ var s = (0, t.search)(this.tempos, r);
2423
+ if (s !== -1) {
2424
+ var c = this.tempos[s], u = c.time, l = (r - c.ticks) / this.ppq;
2425
+ return u + 60 / c.bpm * l;
2426
+ } else {
2427
+ var o = r / this.ppq;
2428
+ return 60 / 120 * o;
2429
+ }
2430
+ }, i.prototype.ticksToMeasures = function(r) {
2431
+ var s = (0, t.search)(this.timeSignatures, r);
2432
+ if (s !== -1) {
2433
+ var c = this.timeSignatures[s], u = (r - c.ticks) / this.ppq;
2434
+ return c.measures + u / (c.timeSignature[0] / c.timeSignature[1]) / 4;
2435
+ } else
2436
+ return r / this.ppq / 4;
2437
+ }, Object.defineProperty(i.prototype, "ppq", {
2438
+ /**
2439
+ * The number of ticks per quarter note.
2440
+ */
2441
+ get: function() {
2442
+ return e.get(this);
2443
+ },
2444
+ enumerable: !1,
2445
+ configurable: !0
2446
+ }), i.prototype.secondsToTicks = function(r) {
2447
+ var s = (0, t.search)(this.tempos, r, "time");
2448
+ if (s !== -1) {
2449
+ var c = this.tempos[s], u = c.time, l = r - u, o = l / (60 / c.bpm);
2450
+ return Math.round(c.ticks + o * this.ppq);
2451
+ } else {
2452
+ var h = r / 0.5;
2453
+ return Math.round(h * this.ppq);
2454
+ }
2455
+ }, i.prototype.toJSON = function() {
2456
+ return {
2457
+ keySignatures: this.keySignatures,
2458
+ meta: this.meta,
2459
+ name: this.name,
2460
+ ppq: this.ppq,
2461
+ tempos: this.tempos.map(function(r) {
2462
+ return {
2463
+ bpm: r.bpm,
2464
+ ticks: r.ticks
2465
+ };
2466
+ }),
2467
+ timeSignatures: this.timeSignatures
2468
+ };
2469
+ }, i.prototype.fromJSON = function(r) {
2470
+ this.name = r.name, this.tempos = r.tempos.map(function(s) {
2471
+ return Object.assign({}, s);
2472
+ }), this.timeSignatures = r.timeSignatures.map(function(s) {
2473
+ return Object.assign({}, s);
2474
+ }), this.keySignatures = r.keySignatures.map(function(s) {
2475
+ return Object.assign({}, s);
2476
+ }), this.meta = r.meta.map(function(s) {
2477
+ return Object.assign({}, s);
2478
+ }), e.set(this, r.ppq), this.update();
2479
+ }, i.prototype.setTempo = function(r) {
2480
+ this.tempos = [
2481
+ {
2482
+ bpm: r,
2483
+ ticks: 0
2484
+ }
2485
+ ], this.update();
2486
+ }, i;
2487
+ })()
2488
+ );
2489
+ a.Header = n;
2490
+ })(Q)), Q;
2491
+ }
2492
+ var U = {}, Y = {}, It;
2493
+ function qt() {
2494
+ return It || (It = 1, (function(a) {
2495
+ Object.defineProperty(a, "__esModule", { value: !0 }), a.ControlChange = a.controlChangeIds = a.controlChangeNames = void 0, a.controlChangeNames = {
2496
+ 1: "modulationWheel",
2497
+ 2: "breath",
2498
+ 4: "footController",
2499
+ 5: "portamentoTime",
2500
+ 7: "volume",
2501
+ 8: "balance",
2502
+ 10: "pan",
2503
+ 64: "sustain",
2504
+ 65: "portamentoTime",
2505
+ 66: "sostenuto",
2506
+ 67: "softPedal",
2507
+ 68: "legatoFootswitch",
2508
+ 84: "portamentoControl"
2509
+ }, a.controlChangeIds = Object.keys(a.controlChangeNames).reduce(function(i, r) {
2510
+ return i[a.controlChangeNames[r]] = r, i;
2511
+ }, {});
2512
+ var t = /* @__PURE__ */ new WeakMap(), e = /* @__PURE__ */ new WeakMap(), n = (
2513
+ /** @class */
2514
+ (function() {
2515
+ function i(r, s) {
2516
+ t.set(this, s), e.set(this, r.controllerType), this.ticks = r.absoluteTime, this.value = r.value;
2517
+ }
2518
+ return Object.defineProperty(i.prototype, "number", {
2519
+ /**
2520
+ * The controller number
2521
+ */
2522
+ get: function() {
2523
+ return e.get(this);
2524
+ },
2525
+ enumerable: !1,
2526
+ configurable: !0
2527
+ }), Object.defineProperty(i.prototype, "name", {
2528
+ /**
2529
+ * return the common name of the control number if it exists
2530
+ */
2531
+ get: function() {
2532
+ return a.controlChangeNames[this.number] ? a.controlChangeNames[this.number] : null;
2533
+ },
2534
+ enumerable: !1,
2535
+ configurable: !0
2536
+ }), Object.defineProperty(i.prototype, "time", {
2537
+ /**
2538
+ * The time of the event in seconds
2539
+ */
2540
+ get: function() {
2541
+ var r = t.get(this);
2542
+ return r.ticksToSeconds(this.ticks);
2543
+ },
2544
+ set: function(r) {
2545
+ var s = t.get(this);
2546
+ this.ticks = s.secondsToTicks(r);
2547
+ },
2548
+ enumerable: !1,
2549
+ configurable: !0
2550
+ }), i.prototype.toJSON = function() {
2551
+ return {
2552
+ number: this.number,
2553
+ ticks: this.ticks,
2554
+ time: this.time,
2555
+ value: this.value
2556
+ };
2557
+ }, i;
2558
+ })()
2559
+ );
2560
+ a.ControlChange = n;
2561
+ })(Y)), Y;
2562
+ }
2563
+ var O = {}, xt;
2564
+ function _e() {
2565
+ if (xt) return O;
2566
+ xt = 1, Object.defineProperty(O, "__esModule", { value: !0 }), O.createControlChanges = void 0;
2567
+ var a = qt();
2568
+ function t() {
2569
+ return new Proxy({}, {
2570
+ // tslint:disable-next-line: typedef
2571
+ get: function(e, n) {
2572
+ if (e[n])
2573
+ return e[n];
2574
+ if (a.controlChangeIds.hasOwnProperty(n))
2575
+ return e[a.controlChangeIds[n]];
2576
+ },
2577
+ // tslint:disable-next-line: typedef
2578
+ set: function(e, n, i) {
2579
+ return a.controlChangeIds.hasOwnProperty(n) ? e[a.controlChangeIds[n]] = i : e[n] = i, !0;
2580
+ }
2581
+ });
2582
+ }
2583
+ return O.createControlChanges = t, O;
2584
+ }
2585
+ var A = {}, Mt;
2586
+ function Ce() {
2587
+ if (Mt) return A;
2588
+ Mt = 1, Object.defineProperty(A, "__esModule", { value: !0 }), A.PitchBend = void 0;
2589
+ var a = /* @__PURE__ */ new WeakMap(), t = (
2590
+ /** @class */
2591
+ (function() {
2592
+ function e(n, i) {
2593
+ a.set(this, i), this.ticks = n.absoluteTime, this.value = n.value;
2594
+ }
2595
+ return Object.defineProperty(e.prototype, "time", {
2596
+ /**
2597
+ * The time of the event in seconds
2598
+ */
2599
+ get: function() {
2600
+ var n = a.get(this);
2601
+ return n.ticksToSeconds(this.ticks);
2602
+ },
2603
+ set: function(n) {
2604
+ var i = a.get(this);
2605
+ this.ticks = i.secondsToTicks(n);
2606
+ },
2607
+ enumerable: !1,
2608
+ configurable: !0
2609
+ }), e.prototype.toJSON = function() {
2610
+ return {
2611
+ ticks: this.ticks,
2612
+ time: this.time,
2613
+ value: this.value
2614
+ };
2615
+ }, e;
2616
+ })()
2617
+ );
2618
+ return A.PitchBend = t, A;
2619
+ }
2620
+ var D = {}, C = {}, Et;
2621
+ function Ie() {
2622
+ return Et || (Et = 1, Object.defineProperty(C, "__esModule", { value: !0 }), C.DrumKitByPatchID = C.InstrumentFamilyByID = C.instrumentByPatchID = void 0, C.instrumentByPatchID = [
2623
+ "acoustic grand piano",
2624
+ "bright acoustic piano",
2625
+ "electric grand piano",
2626
+ "honky-tonk piano",
2627
+ "electric piano 1",
2628
+ "electric piano 2",
2629
+ "harpsichord",
2630
+ "clavi",
2631
+ "celesta",
2632
+ "glockenspiel",
2633
+ "music box",
2634
+ "vibraphone",
2635
+ "marimba",
2636
+ "xylophone",
2637
+ "tubular bells",
2638
+ "dulcimer",
2639
+ "drawbar organ",
2640
+ "percussive organ",
2641
+ "rock organ",
2642
+ "church organ",
2643
+ "reed organ",
2644
+ "accordion",
2645
+ "harmonica",
2646
+ "tango accordion",
2647
+ "acoustic guitar (nylon)",
2648
+ "acoustic guitar (steel)",
2649
+ "electric guitar (jazz)",
2650
+ "electric guitar (clean)",
2651
+ "electric guitar (muted)",
2652
+ "overdriven guitar",
2653
+ "distortion guitar",
2654
+ "guitar harmonics",
2655
+ "acoustic bass",
2656
+ "electric bass (finger)",
2657
+ "electric bass (pick)",
2658
+ "fretless bass",
2659
+ "slap bass 1",
2660
+ "slap bass 2",
2661
+ "synth bass 1",
2662
+ "synth bass 2",
2663
+ "violin",
2664
+ "viola",
2665
+ "cello",
2666
+ "contrabass",
2667
+ "tremolo strings",
2668
+ "pizzicato strings",
2669
+ "orchestral harp",
2670
+ "timpani",
2671
+ "string ensemble 1",
2672
+ "string ensemble 2",
2673
+ "synthstrings 1",
2674
+ "synthstrings 2",
2675
+ "choir aahs",
2676
+ "voice oohs",
2677
+ "synth voice",
2678
+ "orchestra hit",
2679
+ "trumpet",
2680
+ "trombone",
2681
+ "tuba",
2682
+ "muted trumpet",
2683
+ "french horn",
2684
+ "brass section",
2685
+ "synthbrass 1",
2686
+ "synthbrass 2",
2687
+ "soprano sax",
2688
+ "alto sax",
2689
+ "tenor sax",
2690
+ "baritone sax",
2691
+ "oboe",
2692
+ "english horn",
2693
+ "bassoon",
2694
+ "clarinet",
2695
+ "piccolo",
2696
+ "flute",
2697
+ "recorder",
2698
+ "pan flute",
2699
+ "blown bottle",
2700
+ "shakuhachi",
2701
+ "whistle",
2702
+ "ocarina",
2703
+ "lead 1 (square)",
2704
+ "lead 2 (sawtooth)",
2705
+ "lead 3 (calliope)",
2706
+ "lead 4 (chiff)",
2707
+ "lead 5 (charang)",
2708
+ "lead 6 (voice)",
2709
+ "lead 7 (fifths)",
2710
+ "lead 8 (bass + lead)",
2711
+ "pad 1 (new age)",
2712
+ "pad 2 (warm)",
2713
+ "pad 3 (polysynth)",
2714
+ "pad 4 (choir)",
2715
+ "pad 5 (bowed)",
2716
+ "pad 6 (metallic)",
2717
+ "pad 7 (halo)",
2718
+ "pad 8 (sweep)",
2719
+ "fx 1 (rain)",
2720
+ "fx 2 (soundtrack)",
2721
+ "fx 3 (crystal)",
2722
+ "fx 4 (atmosphere)",
2723
+ "fx 5 (brightness)",
2724
+ "fx 6 (goblins)",
2725
+ "fx 7 (echoes)",
2726
+ "fx 8 (sci-fi)",
2727
+ "sitar",
2728
+ "banjo",
2729
+ "shamisen",
2730
+ "koto",
2731
+ "kalimba",
2732
+ "bag pipe",
2733
+ "fiddle",
2734
+ "shanai",
2735
+ "tinkle bell",
2736
+ "agogo",
2737
+ "steel drums",
2738
+ "woodblock",
2739
+ "taiko drum",
2740
+ "melodic tom",
2741
+ "synth drum",
2742
+ "reverse cymbal",
2743
+ "guitar fret noise",
2744
+ "breath noise",
2745
+ "seashore",
2746
+ "bird tweet",
2747
+ "telephone ring",
2748
+ "helicopter",
2749
+ "applause",
2750
+ "gunshot"
2751
+ ], C.InstrumentFamilyByID = [
2752
+ "piano",
2753
+ "chromatic percussion",
2754
+ "organ",
2755
+ "guitar",
2756
+ "bass",
2757
+ "strings",
2758
+ "ensemble",
2759
+ "brass",
2760
+ "reed",
2761
+ "pipe",
2762
+ "synth lead",
2763
+ "synth pad",
2764
+ "synth effects",
2765
+ "world",
2766
+ "percussive",
2767
+ "sound effects"
2768
+ ], C.DrumKitByPatchID = {
2769
+ 0: "standard kit",
2770
+ 8: "room kit",
2771
+ 16: "power kit",
2772
+ 24: "electronic kit",
2773
+ 25: "tr-808 kit",
2774
+ 32: "jazz kit",
2775
+ 40: "brush kit",
2776
+ 48: "orchestra kit",
2777
+ 56: "sound fx kit"
2778
+ }), C;
2779
+ }
2780
+ var Pt;
2781
+ function xe() {
2782
+ if (Pt) return D;
2783
+ Pt = 1, Object.defineProperty(D, "__esModule", { value: !0 }), D.Instrument = void 0;
2784
+ var a = Ie(), t = /* @__PURE__ */ new WeakMap(), e = (
2785
+ /** @class */
2786
+ (function() {
2787
+ function n(i, r) {
2788
+ if (this.number = 0, t.set(this, r), this.number = 0, i) {
2789
+ var s = i.find(function(c) {
2790
+ return c.type === "programChange";
2791
+ });
2792
+ s && (this.number = s.programNumber);
2793
+ }
2794
+ }
2795
+ return Object.defineProperty(n.prototype, "name", {
2796
+ /**
2797
+ * The common name of the instrument.
2798
+ */
2799
+ get: function() {
2800
+ return this.percussion ? a.DrumKitByPatchID[this.number] : a.instrumentByPatchID[this.number];
2801
+ },
2802
+ set: function(i) {
2803
+ var r = a.instrumentByPatchID.indexOf(i);
2804
+ r !== -1 && (this.number = r);
2805
+ },
2806
+ enumerable: !1,
2807
+ configurable: !0
2808
+ }), Object.defineProperty(n.prototype, "family", {
2809
+ /**
2810
+ * The instrument family, e.g. "piano".
2811
+ */
2812
+ get: function() {
2813
+ return this.percussion ? "drums" : a.InstrumentFamilyByID[Math.floor(this.number / 8)];
2814
+ },
2815
+ enumerable: !1,
2816
+ configurable: !0
2817
+ }), Object.defineProperty(n.prototype, "percussion", {
2818
+ /**
2819
+ * If the instrument is a percussion instrument.
2820
+ */
2821
+ get: function() {
2822
+ var i = t.get(this);
2823
+ return i.channel === 9;
2824
+ },
2825
+ enumerable: !1,
2826
+ configurable: !0
2827
+ }), n.prototype.toJSON = function() {
2828
+ return {
2829
+ family: this.family,
2830
+ number: this.number,
2831
+ name: this.name
2832
+ };
2833
+ }, n.prototype.fromJSON = function(i) {
2834
+ this.number = i.number;
2835
+ }, n;
2836
+ })()
2837
+ );
2838
+ return D.Instrument = e, D;
2839
+ }
2840
+ var B = {}, Ft;
2841
+ function Me() {
2842
+ if (Ft) return B;
2843
+ Ft = 1, Object.defineProperty(B, "__esModule", { value: !0 }), B.Note = void 0;
2844
+ function a(s) {
2845
+ var c = Math.floor(s / 12) - 1;
2846
+ return t(s) + c.toString();
2847
+ }
2848
+ function t(s) {
2849
+ var c = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"], u = s % 12;
2850
+ return c[u];
2851
+ }
2852
+ function e(s) {
2853
+ var c = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
2854
+ return c.indexOf(s);
2855
+ }
2856
+ var n = /* @__PURE__ */ (function() {
2857
+ var s = /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i, c = {
2858
+ // tslint:disable-next-line: object-literal-sort-keys
2859
+ cbb: -2,
2860
+ cb: -1,
2861
+ c: 0,
2862
+ "c#": 1,
2863
+ cx: 2,
2864
+ dbb: 0,
2865
+ db: 1,
2866
+ d: 2,
2867
+ "d#": 3,
2868
+ dx: 4,
2869
+ ebb: 2,
2870
+ eb: 3,
2871
+ e: 4,
2872
+ "e#": 5,
2873
+ ex: 6,
2874
+ fbb: 3,
2875
+ fb: 4,
2876
+ f: 5,
2877
+ "f#": 6,
2878
+ fx: 7,
2879
+ gbb: 5,
2880
+ gb: 6,
2881
+ g: 7,
2882
+ "g#": 8,
2883
+ gx: 9,
2884
+ abb: 7,
2885
+ ab: 8,
2886
+ a: 9,
2887
+ "a#": 10,
2888
+ ax: 11,
2889
+ bbb: 9,
2890
+ bb: 10,
2891
+ b: 11,
2892
+ "b#": 12,
2893
+ bx: 13
2894
+ };
2895
+ return function(u) {
2896
+ var l = s.exec(u), o = l[1], h = l[2], f = c[o.toLowerCase()];
2897
+ return f + (parseInt(h, 10) + 1) * 12;
2898
+ };
2899
+ })(), i = /* @__PURE__ */ new WeakMap(), r = (
2900
+ /** @class */
2901
+ (function() {
2902
+ function s(c, u, l) {
2903
+ i.set(this, l), this.midi = c.midi, this.velocity = c.velocity, this.noteOffVelocity = u.velocity, this.ticks = c.ticks, this.durationTicks = u.ticks - c.ticks;
2904
+ }
2905
+ return Object.defineProperty(s.prototype, "name", {
2906
+ /**
2907
+ * The note name and octave in scientific pitch notation, e.g. "C4".
2908
+ */
2909
+ get: function() {
2910
+ return a(this.midi);
2911
+ },
2912
+ set: function(c) {
2913
+ this.midi = n(c);
2914
+ },
2915
+ enumerable: !1,
2916
+ configurable: !0
2917
+ }), Object.defineProperty(s.prototype, "octave", {
2918
+ /**
2919
+ * The notes octave number.
2920
+ */
2921
+ get: function() {
2922
+ return Math.floor(this.midi / 12) - 1;
2923
+ },
2924
+ set: function(c) {
2925
+ var u = c - this.octave;
2926
+ this.midi += u * 12;
2927
+ },
2928
+ enumerable: !1,
2929
+ configurable: !0
2930
+ }), Object.defineProperty(s.prototype, "pitch", {
2931
+ /**
2932
+ * The pitch class name. e.g. "A".
2933
+ */
2934
+ get: function() {
2935
+ return t(this.midi);
2936
+ },
2937
+ set: function(c) {
2938
+ this.midi = 12 * (this.octave + 1) + e(c);
2939
+ },
2940
+ enumerable: !1,
2941
+ configurable: !0
2942
+ }), Object.defineProperty(s.prototype, "duration", {
2943
+ /**
2944
+ * The duration of the segment in seconds.
2945
+ */
2946
+ get: function() {
2947
+ var c = i.get(this);
2948
+ return c.ticksToSeconds(this.ticks + this.durationTicks) - c.ticksToSeconds(this.ticks);
2949
+ },
2950
+ set: function(c) {
2951
+ var u = i.get(this), l = u.secondsToTicks(this.time + c);
2952
+ this.durationTicks = l - this.ticks;
2953
+ },
2954
+ enumerable: !1,
2955
+ configurable: !0
2956
+ }), Object.defineProperty(s.prototype, "time", {
2957
+ /**
2958
+ * The time of the event in seconds.
2959
+ */
2960
+ get: function() {
2961
+ var c = i.get(this);
2962
+ return c.ticksToSeconds(this.ticks);
2963
+ },
2964
+ set: function(c) {
2965
+ var u = i.get(this);
2966
+ this.ticks = u.secondsToTicks(c);
2967
+ },
2968
+ enumerable: !1,
2969
+ configurable: !0
2970
+ }), Object.defineProperty(s.prototype, "bars", {
2971
+ /**
2972
+ * The number of measures (and partial measures) to this beat.
2973
+ * Takes into account time signature changes.
2974
+ * @readonly
2975
+ */
2976
+ get: function() {
2977
+ var c = i.get(this);
2978
+ return c.ticksToMeasures(this.ticks);
2979
+ },
2980
+ enumerable: !1,
2981
+ configurable: !0
2982
+ }), s.prototype.toJSON = function() {
2983
+ return {
2984
+ duration: this.duration,
2985
+ durationTicks: this.durationTicks,
2986
+ midi: this.midi,
2987
+ name: this.name,
2988
+ ticks: this.ticks,
2989
+ time: this.time,
2990
+ velocity: this.velocity
2991
+ };
2992
+ }, s;
2993
+ })()
2994
+ );
2995
+ return B.Note = r, B;
2996
+ }
2997
+ var Nt;
2998
+ function Ut() {
2999
+ if (Nt) return U;
3000
+ Nt = 1, Object.defineProperty(U, "__esModule", { value: !0 }), U.Track = void 0;
3001
+ var a = $t(), t = qt(), e = _e(), n = Ce(), i = xe(), r = Me(), s = /* @__PURE__ */ new WeakMap(), c = (
3002
+ /** @class */
3003
+ (function() {
3004
+ function u(l, o) {
3005
+ var h = this;
3006
+ if (this.name = "", this.notes = [], this.controlChanges = (0, e.createControlChanges)(), this.pitchBends = [], s.set(this, o), l) {
3007
+ var f = l.find(function(p) {
3008
+ return p.type === "trackName";
3009
+ });
3010
+ this.name = f ? f.text : "";
3011
+ }
3012
+ if (this.instrument = new i.Instrument(l, this), this.channel = 0, l) {
3013
+ for (var d = l.filter(function(p) {
3014
+ return p.type === "noteOn";
3015
+ }), g = l.filter(function(p) {
3016
+ return p.type === "noteOff";
3017
+ }), b = function() {
3018
+ var p = d.shift();
3019
+ y.channel = p.channel;
3020
+ var S = g.findIndex(function(N) {
3021
+ return N.noteNumber === p.noteNumber && N.absoluteTime >= p.absoluteTime;
3022
+ });
3023
+ if (S !== -1) {
3024
+ var w = g.splice(S, 1)[0];
3025
+ y.addNote({
3026
+ durationTicks: w.absoluteTime - p.absoluteTime,
3027
+ midi: p.noteNumber,
3028
+ noteOffVelocity: w.velocity / 127,
3029
+ ticks: p.absoluteTime,
3030
+ velocity: p.velocity / 127
3031
+ });
3032
+ }
3033
+ }, y = this; d.length; )
3034
+ b();
3035
+ var m = l.filter(function(p) {
3036
+ return p.type === "controller";
3037
+ });
3038
+ m.forEach(function(p) {
3039
+ h.addCC({
3040
+ number: p.controllerType,
3041
+ ticks: p.absoluteTime,
3042
+ value: p.value / 127
3043
+ });
3044
+ });
3045
+ var v = l.filter(function(p) {
3046
+ return p.type === "pitchBend";
3047
+ });
3048
+ v.forEach(function(p) {
3049
+ h.addPitchBend({
3050
+ ticks: p.absoluteTime,
3051
+ // Scale the value between -2^13 to 2^13 to -2 to 2.
3052
+ value: p.value / Math.pow(2, 13)
3053
+ });
3054
+ });
3055
+ var k = l.find(function(p) {
3056
+ return p.type === "endOfTrack";
3057
+ });
3058
+ this.endOfTrackTicks = k !== void 0 ? k.absoluteTime : void 0;
3059
+ }
3060
+ }
3061
+ return u.prototype.addNote = function(l) {
3062
+ var o = s.get(this), h = new r.Note({
3063
+ midi: 0,
3064
+ ticks: 0,
3065
+ velocity: 1
3066
+ }, {
3067
+ ticks: 0,
3068
+ velocity: 0
3069
+ }, o);
3070
+ return Object.assign(h, l), (0, a.insert)(this.notes, h, "ticks"), this;
3071
+ }, u.prototype.addCC = function(l) {
3072
+ var o = s.get(this), h = new t.ControlChange({
3073
+ controllerType: l.number
3074
+ }, o);
3075
+ return delete l.number, Object.assign(h, l), Array.isArray(this.controlChanges[h.number]) || (this.controlChanges[h.number] = []), (0, a.insert)(this.controlChanges[h.number], h, "ticks"), this;
3076
+ }, u.prototype.addPitchBend = function(l) {
3077
+ var o = s.get(this), h = new n.PitchBend({}, o);
3078
+ return Object.assign(h, l), (0, a.insert)(this.pitchBends, h, "ticks"), this;
3079
+ }, Object.defineProperty(u.prototype, "duration", {
3080
+ /**
3081
+ * The end time of the last event in the track.
3082
+ */
3083
+ get: function() {
3084
+ if (!this.notes.length)
3085
+ return 0;
3086
+ for (var l = this.notes[this.notes.length - 1].time + this.notes[this.notes.length - 1].duration, o = 0; o < this.notes.length - 1; o++) {
3087
+ var h = this.notes[o].time + this.notes[o].duration;
3088
+ l < h && (l = h);
3089
+ }
3090
+ return l;
3091
+ },
3092
+ enumerable: !1,
3093
+ configurable: !0
3094
+ }), Object.defineProperty(u.prototype, "durationTicks", {
3095
+ /**
3096
+ * The end time of the last event in the track in ticks.
3097
+ */
3098
+ get: function() {
3099
+ if (!this.notes.length)
3100
+ return 0;
3101
+ for (var l = this.notes[this.notes.length - 1].ticks + this.notes[this.notes.length - 1].durationTicks, o = 0; o < this.notes.length - 1; o++) {
3102
+ var h = this.notes[o].ticks + this.notes[o].durationTicks;
3103
+ l < h && (l = h);
3104
+ }
3105
+ return l;
3106
+ },
3107
+ enumerable: !1,
3108
+ configurable: !0
3109
+ }), u.prototype.fromJSON = function(l) {
3110
+ var o = this;
3111
+ this.name = l.name, this.channel = l.channel, this.instrument = new i.Instrument(void 0, this), this.instrument.fromJSON(l.instrument), l.endOfTrackTicks !== void 0 && (this.endOfTrackTicks = l.endOfTrackTicks);
3112
+ for (var h in l.controlChanges)
3113
+ l.controlChanges[h] && l.controlChanges[h].forEach(function(f) {
3114
+ o.addCC({
3115
+ number: f.number,
3116
+ ticks: f.ticks,
3117
+ value: f.value
3118
+ });
3119
+ });
3120
+ l.notes.forEach(function(f) {
3121
+ o.addNote({
3122
+ durationTicks: f.durationTicks,
3123
+ midi: f.midi,
3124
+ ticks: f.ticks,
3125
+ velocity: f.velocity
3126
+ });
3127
+ });
3128
+ }, u.prototype.toJSON = function() {
3129
+ for (var l = {}, o = 0; o < 127; o++)
3130
+ this.controlChanges.hasOwnProperty(o) && (l[o] = this.controlChanges[o].map(function(f) {
3131
+ return f.toJSON();
3132
+ }));
3133
+ var h = {
3134
+ channel: this.channel,
3135
+ controlChanges: l,
3136
+ pitchBends: this.pitchBends.map(function(f) {
3137
+ return f.toJSON();
3138
+ }),
3139
+ instrument: this.instrument.toJSON(),
3140
+ name: this.name,
3141
+ notes: this.notes.map(function(f) {
3142
+ return f.toJSON();
3143
+ })
3144
+ };
3145
+ return this.endOfTrackTicks !== void 0 && (h.endOfTrackTicks = this.endOfTrackTicks), h;
3146
+ }, u;
3147
+ })()
3148
+ );
3149
+ return U.Track = c, U;
3150
+ }
3151
+ var P = {};
3152
+ function Ee(a) {
3153
+ var t = [];
3154
+ return zt(a, t), t;
3155
+ }
3156
+ function zt(a, t) {
3157
+ for (var e = 0; e < a.length; e++) {
3158
+ var n = a[e];
3159
+ Array.isArray(n) ? zt(n, t) : t.push(n);
3160
+ }
3161
+ }
3162
+ const Pe = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3163
+ __proto__: null,
3164
+ flatten: Ee
3165
+ }, Symbol.toStringTag, { value: "Module" })), Fe = /* @__PURE__ */ Se(Pe);
3166
+ var Ot;
3167
+ function Ne() {
3168
+ if (Ot) return P;
3169
+ Ot = 1;
3170
+ var a = P && P.__spreadArray || function(m, v, k) {
3171
+ if (k || arguments.length === 2) for (var p = 0, S = v.length, w; p < S; p++)
3172
+ (w || !(p in v)) && (w || (w = Array.prototype.slice.call(v, 0, p)), w[p] = v[p]);
3173
+ return m.concat(w || Array.prototype.slice.call(v));
3174
+ };
3175
+ Object.defineProperty(P, "__esModule", { value: !0 }), P.encode = void 0;
3176
+ var t = Gt(), e = it(), n = Fe;
3177
+ function i(m, v) {
3178
+ return [
3179
+ {
3180
+ absoluteTime: m.ticks,
3181
+ channel: v,
3182
+ deltaTime: 0,
3183
+ noteNumber: m.midi,
3184
+ type: "noteOn",
3185
+ velocity: Math.floor(m.velocity * 127)
3186
+ },
3187
+ {
3188
+ absoluteTime: m.ticks + m.durationTicks,
3189
+ channel: v,
3190
+ deltaTime: 0,
3191
+ noteNumber: m.midi,
3192
+ type: "noteOff",
3193
+ velocity: Math.floor(m.noteOffVelocity * 127)
3194
+ }
3195
+ ];
3196
+ }
3197
+ function r(m) {
3198
+ return (0, n.flatten)(m.notes.map(function(v) {
3199
+ return i(v, m.channel);
3200
+ }));
3201
+ }
3202
+ function s(m, v) {
3203
+ return {
3204
+ absoluteTime: m.ticks,
3205
+ channel: v,
3206
+ controllerType: m.number,
3207
+ deltaTime: 0,
3208
+ type: "controller",
3209
+ value: Math.floor(m.value * 127)
3210
+ };
3211
+ }
3212
+ function c(m) {
3213
+ for (var v = [], k = 0; k < 127; k++)
3214
+ m.controlChanges.hasOwnProperty(k) && m.controlChanges[k].forEach(function(p) {
3215
+ v.push(s(p, m.channel));
3216
+ });
3217
+ return v;
3218
+ }
3219
+ function u(m, v) {
3220
+ return {
3221
+ absoluteTime: m.ticks,
3222
+ channel: v,
3223
+ deltaTime: 0,
3224
+ type: "pitchBend",
3225
+ value: m.value
3226
+ };
3227
+ }
3228
+ function l(m) {
3229
+ var v = [];
3230
+ return m.pitchBends.forEach(function(k) {
3231
+ v.push(u(k, m.channel));
3232
+ }), v;
3233
+ }
3234
+ function o(m) {
3235
+ return {
3236
+ absoluteTime: 0,
3237
+ channel: m.channel,
3238
+ deltaTime: 0,
3239
+ programNumber: m.instrument.number,
3240
+ type: "programChange"
3241
+ };
3242
+ }
3243
+ function h(m) {
3244
+ return {
3245
+ absoluteTime: 0,
3246
+ deltaTime: 0,
3247
+ meta: !0,
3248
+ text: m,
3249
+ type: "trackName"
3250
+ };
3251
+ }
3252
+ function f(m) {
3253
+ return {
3254
+ absoluteTime: m.ticks,
3255
+ deltaTime: 0,
3256
+ meta: !0,
3257
+ microsecondsPerBeat: Math.floor(6e7 / m.bpm),
3258
+ type: "setTempo"
3259
+ };
3260
+ }
3261
+ function d(m) {
3262
+ return {
3263
+ absoluteTime: m.ticks,
3264
+ deltaTime: 0,
3265
+ denominator: m.timeSignature[1],
3266
+ meta: !0,
3267
+ metronome: 24,
3268
+ numerator: m.timeSignature[0],
3269
+ thirtyseconds: 8,
3270
+ type: "timeSignature"
3271
+ };
3272
+ }
3273
+ function g(m) {
3274
+ var v = e.keySignatureKeys.indexOf(m.key);
3275
+ return {
3276
+ absoluteTime: m.ticks,
3277
+ deltaTime: 0,
3278
+ key: v + 7,
3279
+ meta: !0,
3280
+ scale: m.scale === "major" ? 0 : 1,
3281
+ type: "keySignature"
3282
+ };
3283
+ }
3284
+ function b(m) {
3285
+ return {
3286
+ absoluteTime: m.ticks,
3287
+ deltaTime: 0,
3288
+ meta: !0,
3289
+ text: m.text,
3290
+ type: m.type
3291
+ };
3292
+ }
3293
+ function y(m) {
3294
+ var v = {
3295
+ header: {
3296
+ format: 1,
3297
+ numTracks: m.tracks.length + 1,
3298
+ ticksPerBeat: m.header.ppq
3299
+ },
3300
+ tracks: a([
3301
+ a(a(a(a([
3302
+ // The name data.
3303
+ {
3304
+ absoluteTime: 0,
3305
+ deltaTime: 0,
3306
+ meta: !0,
3307
+ text: m.header.name,
3308
+ type: "trackName"
3309
+ }
3310
+ ], m.header.keySignatures.map(function(k) {
3311
+ return g(k);
3312
+ }), !0), m.header.meta.map(function(k) {
3313
+ return b(k);
3314
+ }), !0), m.header.tempos.map(function(k) {
3315
+ return f(k);
3316
+ }), !0), m.header.timeSignatures.map(function(k) {
3317
+ return d(k);
3318
+ }), !0)
3319
+ ], m.tracks.map(function(k) {
3320
+ return a(a(a([
3321
+ // Add the name
3322
+ h(k.name),
3323
+ // the instrument
3324
+ o(k)
3325
+ ], r(k), !0), c(k), !0), l(k), !0);
3326
+ }), !0)
3327
+ };
3328
+ return v.tracks = v.tracks.map(function(k) {
3329
+ k = k.sort(function(S, w) {
3330
+ return S.absoluteTime - w.absoluteTime;
3331
+ });
3332
+ var p = 0;
3333
+ return k.forEach(function(S) {
3334
+ S.deltaTime = S.absoluteTime - p, p = S.absoluteTime, delete S.absoluteTime;
3335
+ }), k.push({
3336
+ deltaTime: 0,
3337
+ meta: !0,
3338
+ type: "endOfTrack"
3339
+ }), k;
3340
+ }), new Uint8Array((0, t.writeMidi)(v));
3341
+ }
3342
+ return P.encode = y, P;
3343
+ }
3344
+ var At;
3345
+ function Ue() {
3346
+ return At || (At = 1, (function(a) {
3347
+ var t = M && M.__awaiter || function(h, f, d, g) {
3348
+ function b(y) {
3349
+ return y instanceof d ? y : new d(function(m) {
3350
+ m(y);
3351
+ });
3352
+ }
3353
+ return new (d || (d = Promise))(function(y, m) {
3354
+ function v(S) {
3355
+ try {
3356
+ p(g.next(S));
3357
+ } catch (w) {
3358
+ m(w);
3359
+ }
3360
+ }
3361
+ function k(S) {
3362
+ try {
3363
+ p(g.throw(S));
3364
+ } catch (w) {
3365
+ m(w);
3366
+ }
3367
+ }
3368
+ function p(S) {
3369
+ S.done ? y(S.value) : b(S.value).then(v, k);
3370
+ }
3371
+ p((g = g.apply(h, f || [])).next());
3372
+ });
3373
+ }, e = M && M.__generator || function(h, f) {
3374
+ var d = { label: 0, sent: function() {
3375
+ if (y[0] & 1) throw y[1];
3376
+ return y[1];
3377
+ }, trys: [], ops: [] }, g, b, y, m;
3378
+ return m = { next: v(0), throw: v(1), return: v(2) }, typeof Symbol == "function" && (m[Symbol.iterator] = function() {
3379
+ return this;
3380
+ }), m;
3381
+ function v(p) {
3382
+ return function(S) {
3383
+ return k([p, S]);
3384
+ };
3385
+ }
3386
+ function k(p) {
3387
+ if (g) throw new TypeError("Generator is already executing.");
3388
+ for (; d; ) try {
3389
+ if (g = 1, b && (y = p[0] & 2 ? b.return : p[0] ? b.throw || ((y = b.return) && y.call(b), 0) : b.next) && !(y = y.call(b, p[1])).done) return y;
3390
+ switch (b = 0, y && (p = [p[0] & 2, y.value]), p[0]) {
3391
+ case 0:
3392
+ case 1:
3393
+ y = p;
3394
+ break;
3395
+ case 4:
3396
+ return d.label++, { value: p[1], done: !1 };
3397
+ case 5:
3398
+ d.label++, b = p[1], p = [0];
3399
+ continue;
3400
+ case 7:
3401
+ p = d.ops.pop(), d.trys.pop();
3402
+ continue;
3403
+ default:
3404
+ if (y = d.trys, !(y = y.length > 0 && y[y.length - 1]) && (p[0] === 6 || p[0] === 2)) {
3405
+ d = 0;
3406
+ continue;
3407
+ }
3408
+ if (p[0] === 3 && (!y || p[1] > y[0] && p[1] < y[3])) {
3409
+ d.label = p[1];
3410
+ break;
3411
+ }
3412
+ if (p[0] === 6 && d.label < y[1]) {
3413
+ d.label = y[1], y = p;
3414
+ break;
3415
+ }
3416
+ if (y && d.label < y[2]) {
3417
+ d.label = y[2], d.ops.push(p);
3418
+ break;
3419
+ }
3420
+ y[2] && d.ops.pop(), d.trys.pop();
3421
+ continue;
3422
+ }
3423
+ p = f.call(h, d);
3424
+ } catch (S) {
3425
+ p = [6, S], b = 0;
3426
+ } finally {
3427
+ g = y = 0;
3428
+ }
3429
+ if (p[0] & 5) throw p[1];
3430
+ return { value: p[0] ? p[1] : void 0, done: !0 };
3431
+ }
3432
+ };
3433
+ Object.defineProperty(a, "__esModule", { value: !0 }), a.Header = a.Track = a.Midi = void 0;
3434
+ var n = Gt(), i = it(), r = Ut(), s = Ne(), c = (
3435
+ /** @class */
3436
+ (function() {
3437
+ function h(f) {
3438
+ var d = this, g = null;
3439
+ if (f) {
3440
+ var b = f instanceof ArrayBuffer ? new Uint8Array(f) : f;
3441
+ g = (0, n.parseMidi)(b), g.tracks.forEach(function(y) {
3442
+ var m = 0;
3443
+ y.forEach(function(v) {
3444
+ m += v.deltaTime, v.absoluteTime = m;
3445
+ });
3446
+ }), g.tracks = o(g.tracks);
3447
+ }
3448
+ this.header = new i.Header(g), this.tracks = [], f && (this.tracks = g.tracks.map(function(y) {
3449
+ return new r.Track(y, d.header);
3450
+ }), g.header.format === 1 && this.tracks[0].duration === 0 && this.tracks.shift());
3451
+ }
3452
+ return h.fromUrl = function(f) {
3453
+ return t(this, void 0, void 0, function() {
3454
+ var d, g;
3455
+ return e(this, function(b) {
3456
+ switch (b.label) {
3457
+ case 0:
3458
+ return [4, fetch(f)];
3459
+ case 1:
3460
+ return d = b.sent(), d.ok ? [4, d.arrayBuffer()] : [3, 3];
3461
+ case 2:
3462
+ return g = b.sent(), [2, new h(g)];
3463
+ case 3:
3464
+ throw new Error("Could not load '".concat(f, "'"));
3465
+ }
3466
+ });
3467
+ });
3468
+ }, Object.defineProperty(h.prototype, "name", {
3469
+ /**
3470
+ * The name of the midi file, taken from the first track.
3471
+ */
3472
+ get: function() {
3473
+ return this.header.name;
3474
+ },
3475
+ set: function(f) {
3476
+ this.header.name = f;
3477
+ },
3478
+ enumerable: !1,
3479
+ configurable: !0
3480
+ }), Object.defineProperty(h.prototype, "duration", {
3481
+ /**
3482
+ * The total length of the file in seconds.
3483
+ */
3484
+ get: function() {
3485
+ var f = this.tracks.map(function(d) {
3486
+ return d.duration;
3487
+ });
3488
+ return Math.max.apply(Math, f);
3489
+ },
3490
+ enumerable: !1,
3491
+ configurable: !0
3492
+ }), Object.defineProperty(h.prototype, "durationTicks", {
3493
+ /**
3494
+ * The total length of the file in ticks.
3495
+ */
3496
+ get: function() {
3497
+ var f = this.tracks.map(function(d) {
3498
+ return d.durationTicks;
3499
+ });
3500
+ return Math.max.apply(Math, f);
3501
+ },
3502
+ enumerable: !1,
3503
+ configurable: !0
3504
+ }), h.prototype.addTrack = function() {
3505
+ var f = new r.Track(void 0, this.header);
3506
+ return this.tracks.push(f), f;
3507
+ }, h.prototype.toArray = function() {
3508
+ return (0, s.encode)(this);
3509
+ }, h.prototype.toJSON = function() {
3510
+ return {
3511
+ header: this.header.toJSON(),
3512
+ tracks: this.tracks.map(function(f) {
3513
+ return f.toJSON();
3514
+ })
3515
+ };
3516
+ }, h.prototype.fromJSON = function(f) {
3517
+ var d = this;
3518
+ this.header = new i.Header(), this.header.fromJSON(f.header), this.tracks = f.tracks.map(function(g) {
3519
+ var b = new r.Track(void 0, d.header);
3520
+ return b.fromJSON(g), b;
3521
+ });
3522
+ }, h.prototype.clone = function() {
3523
+ var f = new h();
3524
+ return f.fromJSON(this.toJSON()), f;
3525
+ }, h;
3526
+ })()
3527
+ );
3528
+ a.Midi = c;
3529
+ var u = Ut();
3530
+ Object.defineProperty(a, "Track", { enumerable: !0, get: function() {
3531
+ return u.Track;
3532
+ } });
3533
+ var l = it();
3534
+ Object.defineProperty(a, "Header", { enumerable: !0, get: function() {
3535
+ return l.Header;
3536
+ } });
3537
+ function o(h) {
3538
+ for (var f = [], d = 0; d < h.length; d++)
3539
+ for (var g = f.length, b = /* @__PURE__ */ new Map(), y = Array(16).fill(0), m = 0, v = h[d]; m < v.length; m++) {
3540
+ var k = v[m], p = g, S = k.channel;
3541
+ if (S !== void 0) {
3542
+ k.type === "programChange" && (y[S] = k.programNumber);
3543
+ var w = y[S], N = "".concat(w, " ").concat(S);
3544
+ b.has(N) ? p = b.get(N) : (p = g + b.size, b.set(N, p));
3545
+ }
3546
+ f[p] || f.push([]), f[p].push(k);
3547
+ }
3548
+ return f;
3549
+ }
3550
+ })(M)), M;
3551
+ }
3552
+ var Oe = Ue();
3553
+ const Ae = [
3554
+ // Piano (0-7)
3555
+ "Acoustic Grand Piano",
3556
+ "Bright Acoustic Piano",
3557
+ "Electric Grand Piano",
3558
+ "Honky-tonk Piano",
3559
+ "Electric Piano 1",
3560
+ "Electric Piano 2",
3561
+ "Harpsichord",
3562
+ "Clavinet",
3563
+ // Chromatic Percussion (8-15)
3564
+ "Celesta",
3565
+ "Glockenspiel",
3566
+ "Music Box",
3567
+ "Vibraphone",
3568
+ "Marimba",
3569
+ "Xylophone",
3570
+ "Tubular Bells",
3571
+ "Dulcimer",
3572
+ // Organ (16-23)
3573
+ "Drawbar Organ",
3574
+ "Percussive Organ",
3575
+ "Rock Organ",
3576
+ "Church Organ",
3577
+ "Reed Organ",
3578
+ "Accordion",
3579
+ "Harmonica",
3580
+ "Tango Accordion",
3581
+ // Guitar (24-31)
3582
+ "Acoustic Guitar (nylon)",
3583
+ "Acoustic Guitar (steel)",
3584
+ "Electric Guitar (jazz)",
3585
+ "Electric Guitar (clean)",
3586
+ "Electric Guitar (muted)",
3587
+ "Overdriven Guitar",
3588
+ "Distortion Guitar",
3589
+ "Guitar Harmonics",
3590
+ // Bass (32-39)
3591
+ "Acoustic Bass",
3592
+ "Electric Bass (finger)",
3593
+ "Electric Bass (pick)",
3594
+ "Fretless Bass",
3595
+ "Slap Bass 1",
3596
+ "Slap Bass 2",
3597
+ "Synth Bass 1",
3598
+ "Synth Bass 2",
3599
+ // Strings (40-47)
3600
+ "Violin",
3601
+ "Viola",
3602
+ "Cello",
3603
+ "Contrabass",
3604
+ "Tremolo Strings",
3605
+ "Pizzicato Strings",
3606
+ "Orchestral Harp",
3607
+ "Timpani",
3608
+ // Ensemble (48-55)
3609
+ "String Ensemble 1",
3610
+ "String Ensemble 2",
3611
+ "Synth Strings 1",
3612
+ "Synth Strings 2",
3613
+ "Choir Aahs",
3614
+ "Voice Oohs",
3615
+ "Synth Voice",
3616
+ "Orchestra Hit",
3617
+ // Brass (56-63)
3618
+ "Trumpet",
3619
+ "Trombone",
3620
+ "Tuba",
3621
+ "Muted Trumpet",
3622
+ "French Horn",
3623
+ "Brass Section",
3624
+ "Synth Brass 1",
3625
+ "Synth Brass 2",
3626
+ // Reed (64-71)
3627
+ "Soprano Sax",
3628
+ "Alto Sax",
3629
+ "Tenor Sax",
3630
+ "Baritone Sax",
3631
+ "Oboe",
3632
+ "English Horn",
3633
+ "Bassoon",
3634
+ "Clarinet",
3635
+ // Pipe (72-79)
3636
+ "Piccolo",
3637
+ "Flute",
3638
+ "Recorder",
3639
+ "Pan Flute",
3640
+ "Blown Bottle",
3641
+ "Shakuhachi",
3642
+ "Whistle",
3643
+ "Ocarina",
3644
+ // Synth Lead (80-87)
3645
+ "Lead 1 (square)",
3646
+ "Lead 2 (sawtooth)",
3647
+ "Lead 3 (calliope)",
3648
+ "Lead 4 (chiff)",
3649
+ "Lead 5 (charang)",
3650
+ "Lead 6 (voice)",
3651
+ "Lead 7 (fifths)",
3652
+ "Lead 8 (bass + lead)",
3653
+ // Synth Pad (88-95)
3654
+ "Pad 1 (new age)",
3655
+ "Pad 2 (warm)",
3656
+ "Pad 3 (polysynth)",
3657
+ "Pad 4 (choir)",
3658
+ "Pad 5 (bowed)",
3659
+ "Pad 6 (metallic)",
3660
+ "Pad 7 (halo)",
3661
+ "Pad 8 (sweep)",
3662
+ // Synth Effects (96-103)
3663
+ "FX 1 (rain)",
3664
+ "FX 2 (soundtrack)",
3665
+ "FX 3 (crystal)",
3666
+ "FX 4 (atmosphere)",
3667
+ "FX 5 (brightness)",
3668
+ "FX 6 (goblins)",
3669
+ "FX 7 (echoes)",
3670
+ "FX 8 (sci-fi)",
3671
+ // Ethnic (104-111)
3672
+ "Sitar",
3673
+ "Banjo",
3674
+ "Shamisen",
3675
+ "Koto",
3676
+ "Kalimba",
3677
+ "Bagpipe",
3678
+ "Fiddle",
3679
+ "Shanai",
3680
+ // Percussive (112-119)
3681
+ "Tinkle Bell",
3682
+ "Agogo",
3683
+ "Steel Drums",
3684
+ "Woodblock",
3685
+ "Taiko Drum",
3686
+ "Melodic Tom",
3687
+ "Synth Drum",
3688
+ "Reverse Cymbal",
3689
+ // Sound Effects (120-127)
3690
+ "Guitar Fret Noise",
3691
+ "Breath Noise",
3692
+ "Seashore",
3693
+ "Bird Tweet",
3694
+ "Telephone Ring",
3695
+ "Helicopter",
3696
+ "Applause",
3697
+ "Gunshot"
3698
+ ];
3699
+ function Dt(a) {
3700
+ return Ae[a] ?? `Program ${a}`;
3701
+ }
3702
+ function De(a, t = {}) {
3703
+ const { flatten: e = !1 } = t, n = new Oe.Midi(a), i = n.header.tempos[0]?.bpm ?? 120, r = n.header.timeSignatures[0], s = r ? [r.timeSignature[0], r.timeSignature[1]] : [4, 4], c = n.name || "Untitled", u = /* @__PURE__ */ new Map();
3704
+ for (const h of n.tracks) {
3705
+ const f = h.channel, d = h.instrument.number, g = h.name || Dt(d);
3706
+ u.has(f) || u.set(f, { notes: [], programNumber: d, name: g });
3707
+ const b = u.get(f);
3708
+ h.name && !b.name.startsWith(h.name) && (b.name = h.name);
3709
+ for (const y of h.notes)
3710
+ b.notes.push({
3711
+ midi: y.midi,
3712
+ name: y.name,
3713
+ time: y.time,
3714
+ duration: y.duration,
3715
+ velocity: y.velocity,
3716
+ channel: f
3717
+ });
3718
+ }
3719
+ let l = 0;
3720
+ if (u.forEach(({ notes: h }) => {
3721
+ for (const f of h) {
3722
+ const d = f.time + f.duration;
3723
+ d > l && (l = d);
3724
+ }
3725
+ }), e) {
3726
+ const h = [];
3727
+ return u.forEach(({ notes: f }) => {
3728
+ h.push(...f);
3729
+ }), h.sort((f, d) => f.time - d.time), {
3730
+ tracks: [{
3731
+ name: c,
3732
+ notes: h,
3733
+ duration: l,
3734
+ channel: 0,
3735
+ instrument: "Mixed",
3736
+ programNumber: 0
3737
+ }],
3738
+ duration: l,
3739
+ name: c,
3740
+ bpm: i,
3741
+ timeSignature: s
3742
+ };
3743
+ }
3744
+ const o = [];
3745
+ return u.forEach(({ notes: h, programNumber: f, name: d }, g) => {
3746
+ if (h.length === 0) return;
3747
+ h.sort((y, m) => y.time - m.time);
3748
+ let b = 0;
3749
+ for (const y of h) {
3750
+ const m = y.time + y.duration;
3751
+ m > b && (b = m);
3752
+ }
3753
+ o.push({
3754
+ name: d,
3755
+ notes: h,
3756
+ duration: b,
3757
+ channel: g,
3758
+ instrument: g === 9 ? "Percussion" : Dt(f),
3759
+ programNumber: f
3760
+ });
3761
+ }), {
3762
+ tracks: o,
3763
+ duration: l,
3764
+ name: c,
3765
+ bpm: i,
3766
+ timeSignature: s
3767
+ };
3768
+ }
3769
+ async function Er(a, t = {}, e) {
3770
+ const n = await fetch(a, { signal: e });
3771
+ if (!n.ok)
3772
+ throw new Error(`Failed to fetch MIDI file: ${n.status} ${n.statusText}`);
3773
+ const i = await n.arrayBuffer();
3774
+ return De(i, t);
3775
+ }
3776
+ function Pr(a) {
3777
+ const t = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"], e = Math.floor(a / 12) - 1;
3778
+ return `${t[a % 12]}${e}`;
3779
+ }
3780
+ function Fr(a) {
3781
+ const t = a.match(/^([A-Ga-g])([#b]?)(-?\d+)$/);
3782
+ if (!t) throw new Error(`Invalid note name: ${a}`);
3783
+ const [, e, n, i] = t;
3784
+ let s = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 }[e.toUpperCase()];
3785
+ return n === "#" && (s += 1), n === "b" && (s -= 1), (parseInt(i, 10) + 1) * 12 + s;
3786
+ }
3787
+ const Nr = {
3788
+ NOTE_OFF: 8,
3789
+ NOTE_ON: 9,
3790
+ POLY_AFTERTOUCH: 10,
3791
+ CONTROL_CHANGE: 11,
3792
+ PROGRAM_CHANGE: 12,
3793
+ CHANNEL_AFTERTOUCH: 13,
3794
+ PITCH_BEND: 14
3795
+ }, Ur = {
3796
+ MODULATION: 1,
3797
+ BREATH: 2,
3798
+ VOLUME: 7,
3799
+ PAN: 10,
3800
+ EXPRESSION: 11,
3801
+ SUSTAIN: 64,
3802
+ PORTAMENTO: 65,
3803
+ SOSTENUTO: 66,
3804
+ SOFT_PEDAL: 67,
3805
+ ALL_SOUND_OFF: 120,
3806
+ RESET_ALL: 121,
3807
+ ALL_NOTES_OFF: 123
3808
+ };
3809
+ function Be(a, t) {
3810
+ const e = a[0], n = e >> 4 & 15, i = e & 15;
3811
+ return {
3812
+ command: n,
3813
+ channel: i,
3814
+ data1: a[1] ?? 0,
3815
+ data2: a[2] ?? 0,
3816
+ raw: a,
3817
+ timestamp: t
3818
+ };
3819
+ }
3820
+ function Ve() {
3821
+ return typeof navigator < "u" && "requestMIDIAccess" in navigator;
3822
+ }
3823
+ async function Le(a = !1) {
3824
+ if (!Ve())
3825
+ return console.warn("[MIDI] Web MIDI API not supported in this browser"), null;
3826
+ try {
3827
+ return await navigator.requestMIDIAccess({ sysex: a });
3828
+ } catch (t) {
3829
+ return console.error("[MIDI] Failed to request MIDI access:", t), null;
3830
+ }
3831
+ }
3832
+ function Re(a) {
3833
+ const t = [];
3834
+ return a.inputs.forEach((e) => {
3835
+ t.push({
3836
+ id: e.id,
3837
+ name: e.name || "Unknown Device",
3838
+ manufacturer: e.manufacturer || "Unknown",
3839
+ state: e.state
3840
+ });
3841
+ }), t;
3842
+ }
3843
+ function Ge(a) {
3844
+ const t = [];
3845
+ return a.outputs.forEach((e) => {
3846
+ t.push({
3847
+ id: e.id,
3848
+ name: e.name || "Unknown Device",
3849
+ manufacturer: e.manufacturer || "Unknown",
3850
+ state: e.state
3851
+ });
3852
+ }), t;
3853
+ }
3854
+ class Or {
3855
+ constructor() {
3856
+ this.access = null, this.activeInputId = null, this.messageCallbacks = /* @__PURE__ */ new Set(), this.stateChangeCallbacks = /* @__PURE__ */ new Set();
3857
+ }
3858
+ /**
3859
+ * Initialize MIDI access
3860
+ */
3861
+ async init(t = !1) {
3862
+ return this.access = await Le(t), this.access ? (this.access.onstatechange = () => {
3863
+ this.stateChangeCallbacks.forEach((e) => e());
3864
+ }, !0) : !1;
3865
+ }
3866
+ /**
3867
+ * Check if initialized
3868
+ */
3869
+ get isInitialized() {
3870
+ return this.access !== null;
3871
+ }
3872
+ /**
3873
+ * Get available input devices
3874
+ */
3875
+ getInputs() {
3876
+ return this.access ? Re(this.access) : [];
3877
+ }
3878
+ /**
3879
+ * Get available output devices
3880
+ */
3881
+ getOutputs() {
3882
+ return this.access ? Ge(this.access) : [];
3883
+ }
3884
+ /**
3885
+ * Connect to a specific MIDI input
3886
+ */
3887
+ connectInput(t) {
3888
+ if (!this.access) return !1;
3889
+ this.disconnectInput();
3890
+ const e = this.access.inputs.get(t);
3891
+ return e ? (this.activeInputId = t, e.onmidimessage = (n) => {
3892
+ if (!n.data) return;
3893
+ const i = Be(n.data, n.timeStamp);
3894
+ this.messageCallbacks.forEach((r) => r(i));
3895
+ }, console.log(`[MIDI] Connected to input: ${e.name}`), !0) : (console.warn(`[MIDI] Input device not found: ${t}`), !1);
3896
+ }
3897
+ /**
3898
+ * Connect to the first available MIDI input
3899
+ */
3900
+ connectFirstInput() {
3901
+ const t = this.getInputs();
3902
+ return t.length === 0 ? !1 : this.connectInput(t[0].id);
3903
+ }
3904
+ /**
3905
+ * Disconnect from current MIDI input
3906
+ */
3907
+ disconnectInput() {
3908
+ if (!this.access || !this.activeInputId) return;
3909
+ const t = this.access.inputs.get(this.activeInputId);
3910
+ t && (t.onmidimessage = null), this.activeInputId = null;
3911
+ }
3912
+ /**
3913
+ * Get the currently connected input ID
3914
+ */
3915
+ get connectedInputId() {
3916
+ return this.activeInputId;
3917
+ }
3918
+ /**
3919
+ * Subscribe to MIDI messages
3920
+ */
3921
+ onMessage(t) {
3922
+ return this.messageCallbacks.add(t), () => this.messageCallbacks.delete(t);
3923
+ }
3924
+ /**
3925
+ * Subscribe to device state changes (connect/disconnect)
3926
+ */
3927
+ onStateChange(t) {
3928
+ return this.stateChangeCallbacks.add(t), () => this.stateChangeCallbacks.delete(t);
3929
+ }
3930
+ /**
3931
+ * Send MIDI message to an output device
3932
+ */
3933
+ sendMessage(t, e) {
3934
+ if (!this.access) return !1;
3935
+ const n = this.access.outputs.get(t);
3936
+ return n ? (n.send(e), !0) : !1;
3937
+ }
3938
+ /**
3939
+ * Clean up resources
3940
+ */
3941
+ dispose() {
3942
+ this.disconnectInput(), this.messageCallbacks.clear(), this.stateChangeCallbacks.clear(), this.access = null;
3943
+ }
3944
+ }
3945
+ function Ar(a, t, e) {
3946
+ return [144 | a & 15, t & 127, e & 127];
3947
+ }
3948
+ function Dr(a, t, e = 0) {
3949
+ return [128 | a & 15, t & 127, e & 127];
3950
+ }
3951
+ function Br(a, t, e) {
3952
+ return [176 | a & 15, t & 127, e & 127];
3953
+ }
3954
+ class $e {
3955
+ constructor() {
3956
+ this.emitter = new Ht();
3957
+ }
3958
+ on(t, e) {
3959
+ this.emitter.on(String(t), e);
3960
+ }
3961
+ off(t, e) {
3962
+ this.emitter.off(String(t), e);
3963
+ }
3964
+ once(t, e) {
3965
+ this.emitter.once(String(t), e);
3966
+ }
3967
+ emit(t, ...e) {
3968
+ this.emitter.emit(String(t), ...e);
3969
+ }
3970
+ removeAllListeners() {
3971
+ this.emitter.removeAllListeners();
3972
+ }
3973
+ }
3974
+ class qe {
3975
+ constructor(t) {
3976
+ this.plugins = /* @__PURE__ */ new Map(), this.disposers = /* @__PURE__ */ new Map(), this.context = t;
3977
+ }
3978
+ getAll() {
3979
+ return [...this.plugins.values()];
3980
+ }
3981
+ async register(t) {
3982
+ if (this.plugins.has(t.id))
3983
+ throw new Error(`Songram engine plugin "${t.id}" is already registered.`);
3984
+ if (this.plugins.set(t.id, t), t.setup) {
3985
+ const e = await t.setup(this.context);
3986
+ typeof e == "function" && this.disposers.set(t.id, e);
3987
+ }
3988
+ this.context.events.emit("plugins:registered", t.id);
3989
+ }
3990
+ async unregister(t) {
3991
+ const e = this.disposers.get(t);
3992
+ e && (await e(), this.disposers.delete(t)), this.plugins.delete(t) && this.context.events.emit("plugins:unregistered", t);
3993
+ }
3994
+ async dispose() {
3995
+ const t = [...this.plugins.keys()];
3996
+ for (const e of t)
3997
+ await this.unregister(e);
3998
+ }
3999
+ }
4000
+ class ze {
4001
+ constructor(t = {}) {
4002
+ this.events = new $e(), this.plugins = new qe({
4003
+ events: this.events,
4004
+ requestAssistant: (c, u, l) => {
4005
+ this.events.emit("assistant:request", { assistantId: c, action: u, payload: l });
4006
+ }
4007
+ }), this.transport = {
4008
+ play: (c, u) => this.playlist.play(c, u),
4009
+ pause: () => this.playlist.pause(),
4010
+ stop: () => this.playlist.stop(),
4011
+ seek: (c) => {
4012
+ this.playlist.seek(c), this.events.emit("transport:seek", c);
4013
+ },
4014
+ getCurrentTime: () => this.playlist.getCurrentTime()
4015
+ }, this.tracks = {
4016
+ set: (c) => {
4017
+ this.playlist.setTracks(c), this.events.emit(
4018
+ "tracks:set",
4019
+ c.map((u) => u.id)
4020
+ );
4021
+ },
4022
+ add: (c) => {
4023
+ this.playlist.addTrack(c), this.events.emit("tracks:add", c.id);
4024
+ },
4025
+ remove: (c) => {
4026
+ this.playlist.removeTrack(c), this.events.emit("tracks:remove", c);
4027
+ },
4028
+ select: (c) => this.playlist.selectTrack(c)
4029
+ }, this.state = {
4030
+ getSnapshot: () => this.playlist.getState()
4031
+ }, this.handleStateChange = (c) => {
4032
+ this.events.emit("statechange", c);
4033
+ }, this.handleTimeUpdate = (c) => {
4034
+ this.events.emit("timeupdate", c);
4035
+ }, this.handlePlay = () => {
4036
+ this.events.emit("play");
4037
+ }, this.handlePause = () => {
4038
+ this.events.emit("pause");
4039
+ }, this.handleStop = () => {
4040
+ this.events.emit("stop");
4041
+ };
4042
+ const { adapter: e, audio: n, plugins: i = [], ...r } = t, s = e ?? ke(n);
4043
+ this.playlist = new ce({
4044
+ ...r,
4045
+ adapter: s
4046
+ }), this.initialPlugins = i, this.playlist.on("statechange", this.handleStateChange), this.playlist.on("timeupdate", this.handleTimeUpdate), this.playlist.on("play", this.handlePlay), this.playlist.on("pause", this.handlePause), this.playlist.on("stop", this.handleStop);
4047
+ }
4048
+ async init() {
4049
+ await this.playlist.init();
4050
+ for (const t of this.initialPlugins)
4051
+ await this.plugins.register(t);
4052
+ this.events.emit("ready");
4053
+ }
4054
+ async registerPlugin(t) {
4055
+ await this.plugins.register(t);
4056
+ }
4057
+ async unregisterPlugin(t) {
4058
+ await this.plugins.unregister(t);
4059
+ }
4060
+ async dispose() {
4061
+ this.playlist.off("statechange", this.handleStateChange), this.playlist.off("timeupdate", this.handleTimeUpdate), this.playlist.off("play", this.handlePlay), this.playlist.off("pause", this.handlePause), this.playlist.off("stop", this.handleStop), this.playlist.dispose(), await this.plugins.dispose(), this.events.emit("dispose"), this.events.removeAllListeners();
4062
+ }
4063
+ }
4064
+ function Vr(a = {}) {
4065
+ return new ze(a);
4066
+ }
4067
+ export {
4068
+ $e as EventBus,
4069
+ Zt as InteractionState,
4070
+ Je as MAX_CANVAS_WIDTH,
4071
+ Ur as MIDI_CC,
4072
+ Nr as MIDI_COMMANDS,
4073
+ Or as MidiController,
4074
+ me as MidiToneTrack,
4075
+ R as PPQN,
4076
+ ce as PlaylistEngine,
4077
+ qe as PluginHost,
4078
+ ze as SongramEngine,
4079
+ kr as SoundFontCache,
4080
+ nt as SoundFontToneTrack,
4081
+ pe as TonePlayout,
4082
+ de as ToneTrack,
4083
+ bt as applyFadeIn,
4084
+ kt as applyFadeOut,
4085
+ K as calculateDuration,
4086
+ ve as calculatePlaybackRate,
4087
+ pr as calculateSplitPoint,
4088
+ gr as calculateViewportBounds,
4089
+ br as calculateZoomScrollPosition,
4090
+ ne as canSplitAt,
4091
+ pt as clampSeekPosition,
4092
+ mt as clipDurationTime,
4093
+ dt as clipEndTime,
4094
+ ft as clipOffsetTime,
4095
+ mr as clipPixelWidth,
4096
+ q as clipStartTime,
4097
+ tr as clipsOverlap,
4098
+ Cr as closeGlobalAudioContext,
4099
+ ee as constrainBoundaryTrim,
4100
+ te as constrainClipDrag,
4101
+ et as createClip,
4102
+ Ke as createClipFromSeconds,
4103
+ Br as createControlChange,
4104
+ Dr as createNoteOff,
4105
+ Ar as createNoteOn,
4106
+ Vr as createSongramEngine,
4107
+ Ze as createTimeline,
4108
+ ke as createToneAdapter,
4109
+ Xe as createTrack,
4110
+ Yt as dBToNormalized,
4111
+ be as extractLoopAndEnvelope,
4112
+ ae as findClosestZoomIndex,
4113
+ er as findGaps,
4114
+ fr as gainToNormalized,
4115
+ Ye as getClipsAtSample,
4116
+ Qe as getClipsInRange,
4117
+ _ as getGeneratorValue,
4118
+ Sr as getGlobalAudioContext,
4119
+ _r as getGlobalAudioContextState,
4120
+ ut as getGlobalContext,
4121
+ wr as getGlobalToneContext,
4122
+ Dt as getInstrumentName,
4123
+ Ir as getMediaStreamSource,
4124
+ Re as getMidiInputs,
4125
+ Ge as getMidiOutputs,
4126
+ ct as getUnderlyingAudioParam,
4127
+ yr as getVisibleChunkIndices,
4128
+ Mr as hasMediaStreamSource,
4129
+ ye as int16ToFloat32,
4130
+ Ve as isWebMidiSupported,
4131
+ Pr as midiNoteToName,
4132
+ dr as normalizedToDb,
4133
+ Fr as noteNameToMidi,
4134
+ De as parseMidiFile,
4135
+ Be as parseMidiMessage,
4136
+ Er as parseMidiUrl,
4137
+ ir as pixelsToSamples,
4138
+ sr as pixelsToSeconds,
4139
+ xr as releaseMediaStreamSource,
4140
+ Le as requestMidiAccess,
4141
+ Tr as resumeGlobalAudioContext,
4142
+ ar as samplesToPixels,
4143
+ rr as samplesToSeconds,
4144
+ ur as samplesToTicks,
4145
+ or as secondsToPixels,
4146
+ nr as secondsToSamples,
4147
+ vr as shouldUpdateViewport,
4148
+ lr as snapToGrid,
4149
+ rt as sortClipsByTime,
4150
+ re as splitClip,
4151
+ Qt as ticksPerBar,
4152
+ Lt as ticksPerBeat,
4153
+ hr as ticksToBarBeatLabel,
4154
+ cr as ticksToSamples,
4155
+ z as timecentsToSeconds
4156
+ };
4157
+ //# sourceMappingURL=index.js.map