@libraz/libsonare 1.3.1 → 1.3.3

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 CHANGED
@@ -1,13 +1,168 @@
1
+ // src/errors.ts
2
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
3
+ ErrorCode2[ErrorCode2["Ok"] = 0] = "Ok";
4
+ ErrorCode2[ErrorCode2["FileNotFound"] = 1] = "FileNotFound";
5
+ ErrorCode2[ErrorCode2["InvalidFormat"] = 2] = "InvalidFormat";
6
+ ErrorCode2[ErrorCode2["DecodeFailed"] = 3] = "DecodeFailed";
7
+ ErrorCode2[ErrorCode2["InvalidParameter"] = 4] = "InvalidParameter";
8
+ ErrorCode2[ErrorCode2["OutOfMemory"] = 5] = "OutOfMemory";
9
+ ErrorCode2[ErrorCode2["NotSupported"] = 6] = "NotSupported";
10
+ ErrorCode2[ErrorCode2["InvalidState"] = 7] = "InvalidState";
11
+ ErrorCode2[ErrorCode2["Unknown"] = 99] = "Unknown";
12
+ return ErrorCode2;
13
+ })(ErrorCode || {});
14
+ var SonareError = class extends Error {
15
+ constructor(code, codeName, message) {
16
+ super(message);
17
+ this.name = "SonareError";
18
+ this.code = code;
19
+ this.codeName = codeName;
20
+ }
21
+ };
22
+ function isSonareError(value) {
23
+ return value instanceof Error && value.name === "SonareError" && typeof value.code === "number";
24
+ }
25
+
1
26
  // src/module_state.ts
2
- var wasmModule = null;
27
+ var wrappedModule = null;
28
+ function nativeExceptionPtr(error) {
29
+ if (typeof error === "number") {
30
+ return error;
31
+ }
32
+ if (error !== null && typeof error === "object") {
33
+ const ptr = error.excPtr;
34
+ if (typeof ptr === "number") {
35
+ return ptr;
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function makeSonareError(raw, thrown) {
41
+ let code = 99 /* Unknown */;
42
+ let codeName = "Unknown";
43
+ let message = `libsonare native exception (${thrown})`;
44
+ try {
45
+ const info = raw.sonareExceptionInfo?.(thrown);
46
+ if (info) {
47
+ code = info.code ?? code;
48
+ codeName = info.codeName ?? codeName;
49
+ message = info.message || message;
50
+ }
51
+ } catch {
52
+ }
53
+ return new SonareError(code, codeName, message);
54
+ }
55
+ function wrapModuleErrors(raw) {
56
+ const cache = /* @__PURE__ */ new Map();
57
+ const objectCache = /* @__PURE__ */ new WeakMap();
58
+ const convert = (error) => {
59
+ const ptr = nativeExceptionPtr(error);
60
+ if (ptr !== null) {
61
+ throw makeSonareError(raw, ptr);
62
+ }
63
+ throw error;
64
+ };
65
+ const wrapNativeObject = (value) => {
66
+ if (value === null || typeof value !== "object") {
67
+ return value;
68
+ }
69
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer || value instanceof Promise) {
70
+ return value;
71
+ }
72
+ const objectValue = value;
73
+ const cached = objectCache.get(objectValue);
74
+ if (cached) {
75
+ return cached;
76
+ }
77
+ const methodCache = /* @__PURE__ */ new Map();
78
+ const wrapped = new Proxy(objectValue, {
79
+ get(target, prop, receiver) {
80
+ const member = Reflect.get(target, prop, receiver);
81
+ if (typeof member !== "function") {
82
+ return member;
83
+ }
84
+ const cachedMethod = methodCache.get(prop);
85
+ if (cachedMethod) {
86
+ return cachedMethod;
87
+ }
88
+ const method = member;
89
+ const wrappedMethod = (...args) => {
90
+ try {
91
+ return wrapNativeObject(Reflect.apply(method, target, args));
92
+ } catch (error) {
93
+ return convert(error);
94
+ }
95
+ };
96
+ methodCache.set(prop, wrappedMethod);
97
+ return wrappedMethod;
98
+ }
99
+ });
100
+ objectCache.set(objectValue, wrapped);
101
+ return wrapped;
102
+ };
103
+ const wrapFunction = (value) => {
104
+ const fnCache = /* @__PURE__ */ new Map();
105
+ return new Proxy(value, {
106
+ get(target, prop, receiver) {
107
+ const member = Reflect.get(target, prop, receiver);
108
+ if (typeof member !== "function") {
109
+ return member;
110
+ }
111
+ const cachedMember = fnCache.get(prop);
112
+ if (cachedMember) {
113
+ return cachedMember;
114
+ }
115
+ const fn = member;
116
+ const wrappedMember = (...args) => {
117
+ try {
118
+ return wrapNativeObject(Reflect.apply(fn, target, args));
119
+ } catch (error) {
120
+ return convert(error);
121
+ }
122
+ };
123
+ fnCache.set(prop, wrappedMember);
124
+ return wrappedMember;
125
+ },
126
+ apply(t, thisArg, args) {
127
+ try {
128
+ return wrapNativeObject(Reflect.apply(t, thisArg, args));
129
+ } catch (error) {
130
+ return convert(error);
131
+ }
132
+ },
133
+ construct(t, args, newTarget) {
134
+ try {
135
+ return wrapNativeObject(Reflect.construct(t, args, newTarget));
136
+ } catch (error) {
137
+ return convert(error);
138
+ }
139
+ }
140
+ });
141
+ };
142
+ return new Proxy(raw, {
143
+ get(target, prop, receiver) {
144
+ const value = Reflect.get(target, prop, receiver);
145
+ if (typeof value !== "function") {
146
+ return value;
147
+ }
148
+ const cached = cache.get(prop);
149
+ if (cached) {
150
+ return cached;
151
+ }
152
+ const wrapped = wrapFunction(value);
153
+ cache.set(prop, wrapped);
154
+ return wrapped;
155
+ }
156
+ });
157
+ }
3
158
  function setSonareModule(module2) {
4
- wasmModule = module2;
159
+ wrappedModule = wrapModuleErrors(module2);
5
160
  }
6
161
  function getSonareModule() {
7
- if (!wasmModule) {
162
+ if (!wrappedModule) {
8
163
  throw new Error("Module not initialized. Call init() first.");
9
164
  }
10
- return wasmModule;
165
+ return wrappedModule;
11
166
  }
12
167
 
13
168
  // src/codes.ts
@@ -82,6 +237,16 @@ var Mixer = class _Mixer {
82
237
  compile() {
83
238
  this.mixer.compile();
84
239
  }
240
+ /**
241
+ * Non-fatal warnings captured when this mixer was built from scene JSON: one
242
+ * entry per channel-strip insert that was handed param keys it does not read
243
+ * (a likely typo, or a key meant for a different processor). The scene still
244
+ * loaded; these keys simply took no effect. Empty when every key was consumed.
245
+ * Use {@link masteringInsertParamNames} to discover the keys an insert accepts.
246
+ */
247
+ sceneWarnings() {
248
+ return this.mixer.sceneWarnings();
249
+ }
85
250
  /**
86
251
  * Mix one block of per-strip stereo audio into the stereo master.
87
252
  *
@@ -1019,6 +1184,9 @@ function masteringProcessorNames() {
1019
1184
  function masteringInsertNames() {
1020
1185
  return requireModule().masteringInsertNames();
1021
1186
  }
1187
+ function masteringInsertParamNames(name) {
1188
+ return requireModule().masteringInsertParamNames(name);
1189
+ }
1022
1190
  function masteringPairProcessorNames() {
1023
1191
  return requireModule().masteringPairProcessorNames();
1024
1192
  }
@@ -2503,10 +2671,25 @@ function waveformPeakPyramid(samples, channels, options = {}) {
2503
2671
 
2504
2672
  // src/opfs_clip_pages.ts
2505
2673
  var opfsClipPageWorkerSource = `
2674
+ const sonareClipPageReadQueues = new Map();
2675
+
2676
+ function sonareEnqueueClipPageRead(key, task) {
2677
+ const previous = sonareClipPageReadQueues.get(key) || Promise.resolve();
2678
+ const next = previous.catch(() => undefined).then(task);
2679
+ const queued = next.finally(() => {
2680
+ if (sonareClipPageReadQueues.get(key) === queued) {
2681
+ sonareClipPageReadQueues.delete(key);
2682
+ }
2683
+ });
2684
+ sonareClipPageReadQueues.set(key, queued);
2685
+ return next;
2686
+ }
2687
+
2506
2688
  self.onmessage = async (event) => {
2507
2689
  const message = event.data;
2508
2690
  if (!message || message.type !== 'sonare:read-clip-page') return;
2509
2691
  const { requestId, path, pageIndex, numChannels, numSamples, pageFrames, dataOffsetBytes = 0 } = message;
2692
+ await sonareEnqueueClipPageRead(String(path), async () => {
2510
2693
  try {
2511
2694
  if (pageIndex < 0) {
2512
2695
  self.postMessage({ type: 'sonare:clip-page', requestId, pageIndex, ok: false });
@@ -2569,6 +2752,7 @@ self.onmessage = async (event) => {
2569
2752
  error: error instanceof Error ? error.message : String(error),
2570
2753
  });
2571
2754
  }
2755
+ });
2572
2756
  };
2573
2757
  `;
2574
2758
  function createOpfsClipPageWorker() {
@@ -2588,6 +2772,7 @@ function createOpfsClipPageProvider(engine, options) {
2588
2772
  const ownsWorker = options.worker === void 0 || options.terminateWorkerOnClose === true;
2589
2773
  let nextRequestId = 1;
2590
2774
  let closed = false;
2775
+ let readQueue = Promise.resolve();
2591
2776
  const pending = /* @__PURE__ */ new Map();
2592
2777
  const onMessage = (event) => {
2593
2778
  const response = event.data;
@@ -2627,15 +2812,29 @@ function createOpfsClipPageProvider(engine, options) {
2627
2812
  const promise = new Promise((resolve, reject) => {
2628
2813
  pending.set(requestId, { resolve, reject });
2629
2814
  });
2630
- worker.postMessage({
2631
- type: "sonare:read-clip-page",
2632
- requestId,
2633
- path: options.path,
2634
- pageIndex,
2635
- numChannels: options.numChannels,
2636
- numSamples: options.numSamples,
2637
- pageFrames: options.pageFrames,
2638
- dataOffsetBytes: options.dataOffsetBytes ?? 0
2815
+ readQueue = readQueue.catch(() => void 0).then(() => {
2816
+ if (closed) {
2817
+ const entry = pending.get(requestId);
2818
+ pending.delete(requestId);
2819
+ entry?.reject(new Error("OpfsClipPageProvider is closed"));
2820
+ return;
2821
+ }
2822
+ worker.postMessage({
2823
+ type: "sonare:read-clip-page",
2824
+ requestId,
2825
+ path: options.path,
2826
+ pageIndex,
2827
+ numChannels: options.numChannels,
2828
+ numSamples: options.numSamples,
2829
+ pageFrames: options.pageFrames,
2830
+ dataOffsetBytes: options.dataOffsetBytes ?? 0
2831
+ });
2832
+ return promise.then(
2833
+ () => void 0,
2834
+ () => void 0
2835
+ );
2836
+ });
2837
+ readQueue.catch(() => {
2639
2838
  });
2640
2839
  return promise;
2641
2840
  };
@@ -3386,9 +3585,6 @@ function engineCapabilities() {
3386
3585
  };
3387
3586
  }
3388
3587
  var RealtimeEngine = class {
3389
- nativeExt() {
3390
- return this.native;
3391
- }
3392
3588
  constructor(sampleRate = 48e3, maxBlockSize = 128, commandCapacity = 1024, telemetryCapacity = 1024) {
3393
3589
  const module2 = getSonareModule();
3394
3590
  const capabilities = engineCapabilities();
@@ -3415,8 +3611,14 @@ var RealtimeEngine = class {
3415
3611
  setParameterSmoothed(paramId, value, renderFrame = -1) {
3416
3612
  this.native.setParameterSmoothed(paramId, value, renderFrame);
3417
3613
  }
3614
+ setSoloMute(laneIndex, solo, mute, renderFrame = -1) {
3615
+ this.native.setSoloMute(laneIndex, solo, mute, renderFrame);
3616
+ }
3617
+ setMidiClips(clips) {
3618
+ this.native.setMidiClips(clips);
3619
+ }
3418
3620
  setBuiltinInstrument(config = {}, destinationId = config.destinationId ?? 0) {
3419
- this.nativeExt().setBuiltinInstrument(destinationId, config);
3621
+ this.native.setBuiltinInstrument(destinationId, config);
3420
3622
  }
3421
3623
  /**
3422
3624
  * Bind the patch-driven NativeSynth to a realtime MIDI destination. `patch`
@@ -3428,7 +3630,7 @@ var RealtimeEngine = class {
3428
3630
  * binding convenience, not part of the NativeSynth patch itself.
3429
3631
  */
3430
3632
  setSynthInstrument(patch = {}, destinationId = (typeof patch === "object" ? patch.destinationId : void 0) ?? 0) {
3431
- this.nativeExt().setSynthInstrument(destinationId, patch);
3633
+ this.native.setSynthInstrument(destinationId, patch);
3432
3634
  }
3433
3635
  /**
3434
3636
  * Load (parse) SoundFont 2 bytes into the engine so SF2 instruments can be
@@ -3437,7 +3639,7 @@ var RealtimeEngine = class {
3437
3639
  * not referenced afterwards. Replaces any previously loaded SoundFont.
3438
3640
  */
3439
3641
  loadSoundFont(data) {
3440
- this.nativeExt().loadSoundFont(data);
3642
+ this.native.loadSoundFont(data);
3441
3643
  }
3442
3644
  /**
3443
3645
  * Bind a GS-compatible SoundFont player to a realtime MIDI destination, fed
@@ -3449,13 +3651,13 @@ var RealtimeEngine = class {
3449
3651
  * synthesizer GM fallback bank (the data-free floor).
3450
3652
  */
3451
3653
  setSf2Instrument(config = {}, destinationId = config.destinationId ?? 0) {
3452
- this.nativeExt().setSf2Instrument(destinationId, config);
3654
+ this.native.setSf2Instrument(destinationId, config);
3453
3655
  }
3454
3656
  clearMidiInstrument(destinationId = 0) {
3455
- this.nativeExt().clearMidiInstrument(destinationId);
3657
+ this.native.clearMidiInstrument(destinationId);
3456
3658
  }
3457
3659
  midiInstrumentCount() {
3458
- return this.nativeExt().midiInstrumentCount();
3660
+ return this.native.midiInstrumentCount();
3459
3661
  }
3460
3662
  /**
3461
3663
  * Bind a live MIDI CC to an engine automation parameter. The MIDI event still
@@ -3463,7 +3665,7 @@ var RealtimeEngine = class {
3463
3665
  * mapped into [minValue, maxValue] for `paramId`.
3464
3666
  */
3465
3667
  bindMidiCc(channel, controller, paramId, options = {}) {
3466
- this.nativeExt().bindMidiCc(
3668
+ this.native.bindMidiCc(
3467
3669
  channel,
3468
3670
  controller,
3469
3671
  paramId,
@@ -3472,42 +3674,42 @@ var RealtimeEngine = class {
3472
3674
  );
3473
3675
  }
3474
3676
  clearMidiCcBindings() {
3475
- this.nativeExt().clearMidiCcBindings();
3677
+ this.native.clearMidiCcBindings();
3476
3678
  }
3477
3679
  midiCcBindingCount() {
3478
- return this.nativeExt().midiCcBindingCount();
3680
+ return this.native.midiCcBindingCount();
3479
3681
  }
3480
3682
  /** Install/replace a live non-destructive MIDI-FX insert for one destination. */
3481
3683
  setMidiFx(destinationId, configJson) {
3482
- this.nativeExt().setMidiFx(destinationId, configJson);
3684
+ this.native.setMidiFx(destinationId, configJson);
3483
3685
  }
3484
3686
  clearMidiFx(destinationId = 0) {
3485
- this.nativeExt().clearMidiFx(destinationId);
3687
+ this.native.clearMidiFx(destinationId);
3486
3688
  }
3487
3689
  /** Enable the engine-owned live MIDI input source for a destination. */
3488
3690
  setMidiInputSource(destinationId = 0) {
3489
- this.nativeExt().setMidiInputSource(destinationId);
3691
+ this.native.setMidiInputSource(destinationId);
3490
3692
  }
3491
3693
  clearMidiInputSource() {
3492
- this.nativeExt().clearMidiInputSource();
3694
+ this.native.clearMidiInputSource();
3493
3695
  }
3494
3696
  midiInputPendingCount() {
3495
- return this.nativeExt().midiInputPendingCount();
3697
+ return this.native.midiInputPendingCount();
3496
3698
  }
3497
3699
  pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples = 0) {
3498
- this.nativeExt().pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples);
3700
+ this.native.pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples);
3499
3701
  }
3500
3702
  pushMidiInputNoteOff(group, channel, note, velocity = 0, portTimeSamples = 0) {
3501
- this.nativeExt().pushMidiInputNoteOff(group, channel, note, velocity, portTimeSamples);
3703
+ this.native.pushMidiInputNoteOff(group, channel, note, velocity, portTimeSamples);
3502
3704
  }
3503
3705
  pushMidiInputCc(group, channel, controller, value, portTimeSamples = 0) {
3504
- this.nativeExt().pushMidiInputCc(group, channel, controller, value, portTimeSamples);
3706
+ this.native.pushMidiInputCc(group, channel, controller, value, portTimeSamples);
3505
3707
  }
3506
3708
  pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame = -1) {
3507
- this.nativeExt().pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame);
3709
+ this.native.pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame);
3508
3710
  }
3509
3711
  pushMidiNoteOff(destinationId, group, channel, note, velocity = 0, renderFrame = -1) {
3510
- this.nativeExt().pushMidiNoteOff(destinationId, group, channel, note, velocity, renderFrame);
3712
+ this.native.pushMidiNoteOff(destinationId, group, channel, note, velocity, renderFrame);
3511
3713
  }
3512
3714
  /**
3513
3715
  * Queue an immediate (live) MIDI control change to a MIDI destination
@@ -3516,21 +3718,21 @@ var RealtimeEngine = class {
3516
3718
  * immediate. Mirrors the Node/Python/C-ABI `pushMidiCc`.
3517
3719
  */
3518
3720
  pushMidiCc(destinationId, group, channel, controller, value, renderFrame = -1) {
3519
- this.nativeExt().pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
3721
+ this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
3520
3722
  }
3521
3723
  /**
3522
3724
  * Queue a MIDI panic (all-notes-off) releasing every sounding note at
3523
3725
  * `renderFrame` (-1 = immediate). Mirrors the C-ABI `pushMidiPanic`.
3524
3726
  */
3525
3727
  pushMidiPanic(renderFrame = -1) {
3526
- this.nativeExt().pushMidiPanic(renderFrame);
3728
+ this.native.pushMidiPanic(renderFrame);
3527
3729
  }
3528
3730
  /**
3529
3731
  * Remove all registered parameters (and their automation lanes). Control-thread
3530
3732
  * only; not realtime-safe. Mirrors the C-ABI `clearParameters`.
3531
3733
  */
3532
3734
  clearParameters() {
3533
- this.nativeExt().clearParameters();
3735
+ this.native.clearParameters();
3534
3736
  }
3535
3737
  /** Read back the current transport state snapshot. */
3536
3738
  getTransportState() {
@@ -3551,9 +3753,18 @@ var RealtimeEngine = class {
3551
3753
  setTempo(bpm) {
3552
3754
  this.native.setTempo(bpm);
3553
3755
  }
3756
+ setTempoSegments(segments) {
3757
+ this.native.setTempoSegments([...segments]);
3758
+ }
3554
3759
  setTimeSignature(numerator, denominator) {
3555
3760
  this.native.setTimeSignature(numerator, denominator);
3556
3761
  }
3762
+ setTimeSignatureSegments(segments) {
3763
+ this.native.setTimeSignatureSegments([...segments]);
3764
+ }
3765
+ sampleAtPpq(ppq) {
3766
+ return Number(this.native.sampleAtPpq(ppq));
3767
+ }
3557
3768
  setLoop(startPpq, endPpq, enabled = true) {
3558
3769
  this.native.setLoop(startPpq, endPpq, enabled);
3559
3770
  }
@@ -3622,21 +3833,81 @@ var RealtimeEngine = class {
3622
3833
  clipCount() {
3623
3834
  return this.native.clipCount();
3624
3835
  }
3836
+ setTrackLanes(lanes) {
3837
+ this.native.setTrackLanes(
3838
+ lanes.map((lane) => typeof lane === "number" ? { trackId: lane } : lane)
3839
+ );
3840
+ }
3841
+ setTrackBuses(buses) {
3842
+ this.native.setTrackBuses(buses);
3843
+ }
3844
+ setBusStripJson(busId, sceneJson) {
3845
+ try {
3846
+ JSON.parse(sceneJson);
3847
+ } catch (error) {
3848
+ const message = error instanceof Error ? error.message : "invalid bus strip JSON";
3849
+ throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
3850
+ }
3851
+ this.native.setBusStripJson(busId, sceneJson);
3852
+ }
3853
+ setTrackStripJson(trackId, sceneJson) {
3854
+ try {
3855
+ JSON.parse(sceneJson);
3856
+ } catch (error) {
3857
+ const message = error instanceof Error ? error.message : "invalid track strip JSON";
3858
+ throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
3859
+ }
3860
+ this.native.setTrackStripJson(trackId, sceneJson);
3861
+ }
3862
+ setTrackStripEqBand(trackId, bandIndex, band) {
3863
+ this.native.setTrackStripEqBandJson(
3864
+ trackId,
3865
+ bandIndex,
3866
+ typeof band === "string" ? band : JSON.stringify(band)
3867
+ );
3868
+ }
3869
+ setTrackStripEqBandJson(trackId, bandIndex, bandJson) {
3870
+ this.native.setTrackStripEqBandJson(trackId, bandIndex, bandJson);
3871
+ }
3872
+ setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass = false) {
3873
+ this.native.setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass);
3874
+ }
3875
+ setMasterStripJson(sceneJson) {
3876
+ try {
3877
+ JSON.parse(sceneJson);
3878
+ } catch (error) {
3879
+ const message = error instanceof Error ? error.message : "invalid master strip JSON";
3880
+ throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
3881
+ }
3882
+ this.native.setMasterStripJson(sceneJson);
3883
+ }
3884
+ setMasterStripEqBand(bandIndex, band) {
3885
+ this.native.setMasterStripEqBandJson(
3886
+ bandIndex,
3887
+ typeof band === "string" ? band : JSON.stringify(band)
3888
+ );
3889
+ }
3890
+ setMasterStripEqBandJson(bandIndex, bandJson) {
3891
+ this.native.setMasterStripEqBandJson(bandIndex, bandJson);
3892
+ }
3893
+ setMasterStripInsertBypassed(insertIndex, bypassed, resetOnBypass = false) {
3894
+ this.native.setMasterStripInsertBypassed(insertIndex, bypassed, resetOnBypass);
3895
+ }
3625
3896
  createClipPageProvider(numChannels, numSamples, pageFrames) {
3626
- const id = this.nativeExt().createClipPageProvider(numChannels, numSamples, pageFrames);
3897
+ const id = this.native.createClipPageProvider(numChannels, numSamples, pageFrames);
3627
3898
  return new ClipPageProvider(this, id);
3628
3899
  }
3629
3900
  supplyClipPage(providerId, pageIndex, channels) {
3630
- this.nativeExt().supplyClipPage(providerId, pageIndex, channels);
3901
+ this.native.supplyClipPage(providerId, pageIndex, channels);
3631
3902
  }
3632
3903
  clearClipPage(providerId, pageIndex) {
3633
- this.nativeExt().clearClipPage(providerId, pageIndex);
3904
+ this.native.clearClipPage(providerId, pageIndex);
3634
3905
  }
3635
3906
  destroyClipPageProvider(providerId) {
3636
- this.nativeExt().destroyClipPageProvider(providerId);
3907
+ this.native.destroyClipPageProvider(providerId);
3637
3908
  }
3638
3909
  popClipPageRequest() {
3639
- return this.nativeExt().popClipPageRequest();
3910
+ return this.native.popClipPageRequest();
3640
3911
  }
3641
3912
  setCaptureBuffer(numChannels, capacityFrames) {
3642
3913
  this.native.setCaptureBuffer(numChannels, capacityFrames);
@@ -3999,7 +4270,6 @@ async function bindWebMidi(engine, options = {}) {
3999
4270
  engine.setMidiInputSource(destinationId);
4000
4271
  const bound = /* @__PURE__ */ new Map();
4001
4272
  let closed = false;
4002
- let runningStatus = 0;
4003
4273
  const shouldBind = (input) => input.state !== "disconnected" && (selectedIds.size === 0 || selectedIds.has(input.id));
4004
4274
  const snapshotInputs = () => Array.from(iterInputs(access), ([id, input]) => ({
4005
4275
  id,
@@ -4012,22 +4282,26 @@ async function bindWebMidi(engine, options = {}) {
4012
4282
  if (bound.has(input.id) || !shouldBind(input)) {
4013
4283
  return;
4014
4284
  }
4015
- const listener = (event) => {
4016
- const status = dispatchMidiMessage(
4017
- engine,
4018
- event,
4019
- group,
4020
- runningStatus,
4021
- options.timestampToSamples
4022
- );
4023
- runningStatus = status;
4285
+ const entry = {
4286
+ input,
4287
+ listener: (event) => {
4288
+ entry.runningStatus = dispatchMidiMessage(
4289
+ engine,
4290
+ event,
4291
+ group,
4292
+ entry.runningStatus,
4293
+ options.timestampToSamples
4294
+ );
4295
+ },
4296
+ runningStatus: 0
4024
4297
  };
4298
+ const listener = entry.listener;
4025
4299
  if (input.addEventListener) {
4026
4300
  input.addEventListener("midimessage", listener);
4027
4301
  } else {
4028
4302
  input.onmidimessage = listener;
4029
4303
  }
4030
- bound.set(input.id, { input, listener });
4304
+ bound.set(input.id, entry);
4031
4305
  };
4032
4306
  const unbindInput = (input) => {
4033
4307
  const entry = bound.get(input.id);
@@ -4212,7 +4486,7 @@ async function init(options) {
4212
4486
  }
4213
4487
  initPromise = (async () => {
4214
4488
  try {
4215
- const createModule = (await import("./sonare.js")).default;
4489
+ const createModule = options?.moduleFactory ?? (await import("./sonare.js")).default;
4216
4490
  module = await createModule(options);
4217
4491
  setSonareModule(module);
4218
4492
  } catch (error) {
@@ -4278,6 +4552,7 @@ export {
4278
4552
  ChordQuality,
4279
4553
  EXPECTED_ENGINE_ABI_VERSION,
4280
4554
  EXPECTED_PROJECT_ABI_VERSION,
4555
+ ErrorCode,
4281
4556
  KeyProfile,
4282
4557
  Mixer,
4283
4558
  Mode,
@@ -4294,6 +4569,7 @@ export {
4294
4569
  SYNTH_MOD_SOURCES,
4295
4570
  SYNTH_OSC_WAVEFORMS,
4296
4571
  SectionType,
4572
+ SonareError,
4297
4573
  StreamAnalyzer,
4298
4574
  StreamingEqualizer,
4299
4575
  StreamingMasteringChain,
@@ -4352,6 +4628,7 @@ export {
4352
4628
  hzToNote,
4353
4629
  init,
4354
4630
  isInitialized,
4631
+ isSonareError,
4355
4632
  isWebMidiAvailable,
4356
4633
  lufs,
4357
4634
  lufsInterleaved,
@@ -4370,6 +4647,7 @@ export {
4370
4647
  masteringDynamicsGate,
4371
4648
  masteringDynamicsTransientShaper,
4372
4649
  masteringInsertNames,
4650
+ masteringInsertParamNames,
4373
4651
  masteringPairAnalysisNames,
4374
4652
  masteringPairAnalyze,
4375
4653
  masteringPairProcess,