@libraz/libsonare 1.3.2 → 1.4.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/README.md +45 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +403 -70
- package/dist/index.js.map +1 -1
- package/dist/sonare-rt-module.js +2 -2
- package/dist/sonare-rt.js +2 -2
- package/dist/sonare-rt.wasm +0 -0
- package/dist/sonare.js +2 -2
- package/dist/sonare.wasm +0 -0
- package/dist/worklet.d.ts +907 -144
- package/dist/worklet.js +1803 -207
- package/dist/worklet.js.map +1 -1
- package/package.json +1 -1
- package/src/codes.ts +6 -1
- package/src/effects_mastering.ts +103 -1
- package/src/feature_music.ts +18 -4
- package/src/feature_spectral.ts +7 -1
- package/src/index.ts +27 -1
- package/src/mixer.ts +9 -0
- package/src/module_state.ts +82 -17
- package/src/opfs_clip_pages.ts +43 -9
- package/src/project.ts +74 -0
- package/src/public_types.ts +52 -0
- package/src/realtime_engine.ts +313 -109
- package/src/sonare.js.d.ts +140 -0
- package/src/stream_types.ts +7 -0
- package/src/validation.ts +7 -0
- package/src/web_midi.ts +15 -11
- package/src/worklet/audio_types.ts +2 -0
- package/src/worklet/guards.ts +146 -0
- package/src/worklet/messages.ts +461 -0
- package/src/worklet/protocol.ts +767 -0
- package/src/worklet.ts +1659 -888
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ function makeSonareError(raw, thrown) {
|
|
|
54
54
|
}
|
|
55
55
|
function wrapModuleErrors(raw) {
|
|
56
56
|
const cache = /* @__PURE__ */ new Map();
|
|
57
|
+
const objectCache = /* @__PURE__ */ new WeakMap();
|
|
57
58
|
const convert = (error) => {
|
|
58
59
|
const ptr = nativeExceptionPtr(error);
|
|
59
60
|
if (ptr !== null) {
|
|
@@ -61,6 +62,83 @@ function wrapModuleErrors(raw) {
|
|
|
61
62
|
}
|
|
62
63
|
throw error;
|
|
63
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
|
+
};
|
|
64
142
|
return new Proxy(raw, {
|
|
65
143
|
get(target, prop, receiver) {
|
|
66
144
|
const value = Reflect.get(target, prop, receiver);
|
|
@@ -71,23 +149,7 @@ function wrapModuleErrors(raw) {
|
|
|
71
149
|
if (cached) {
|
|
72
150
|
return cached;
|
|
73
151
|
}
|
|
74
|
-
const
|
|
75
|
-
const wrapped = new Proxy(fn, {
|
|
76
|
-
apply(t, thisArg, args) {
|
|
77
|
-
try {
|
|
78
|
-
return Reflect.apply(t, thisArg, args);
|
|
79
|
-
} catch (error) {
|
|
80
|
-
return convert(error);
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
construct(t, args, newTarget) {
|
|
84
|
-
try {
|
|
85
|
-
return Reflect.construct(t, args, newTarget);
|
|
86
|
-
} catch (error) {
|
|
87
|
-
return convert(error);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
});
|
|
152
|
+
const wrapped = wrapFunction(value);
|
|
91
153
|
cache.set(prop, wrapped);
|
|
92
154
|
return wrapped;
|
|
93
155
|
}
|
|
@@ -152,7 +214,10 @@ function meterTapCode(tap) {
|
|
|
152
214
|
return tap === "preFader" || tap === 0 ? 0 : 1;
|
|
153
215
|
}
|
|
154
216
|
function sendTimingCode(timing) {
|
|
155
|
-
|
|
217
|
+
if (typeof timing === "number") {
|
|
218
|
+
return timing;
|
|
219
|
+
}
|
|
220
|
+
return timing === "preFader" ? 1 : 0;
|
|
156
221
|
}
|
|
157
222
|
|
|
158
223
|
// src/mixer.ts
|
|
@@ -405,6 +470,13 @@ var Mixer = class _Mixer {
|
|
|
405
470
|
setDualPan(stripIndex, leftPan, rightPan) {
|
|
406
471
|
this.mixer.setDualPan(stripIndex, leftPan, rightPan);
|
|
407
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* Set the strip's surround pan position, used when it feeds a >2-channel bus.
|
|
475
|
+
* Stored on the scene; inert until the surround DSP path applies it.
|
|
476
|
+
*/
|
|
477
|
+
setSurroundPan(stripIndex, pan) {
|
|
478
|
+
this.mixer.setSurroundPan(stripIndex, pan);
|
|
479
|
+
}
|
|
408
480
|
/**
|
|
409
481
|
* Add a send to a strip after construction.
|
|
410
482
|
*
|
|
@@ -1107,6 +1179,11 @@ function normalize(samples, sampleRate, targetDb = 0, options = {}) {
|
|
|
1107
1179
|
assertSamples("normalize", samples, options.validate !== false);
|
|
1108
1180
|
return requireModule().normalize(samples, sampleRate, targetDb);
|
|
1109
1181
|
}
|
|
1182
|
+
function spectralEdit(samples, sampleRate, ops = [], options = {}) {
|
|
1183
|
+
assertSamples("spectralEdit", samples, options.validate !== false);
|
|
1184
|
+
assertSampleRate("spectralEdit", sampleRate);
|
|
1185
|
+
return requireModule().spectralEdit(samples, sampleRate, ops, options);
|
|
1186
|
+
}
|
|
1110
1187
|
function mastering(samples, sampleRate = 22050, options = {}) {
|
|
1111
1188
|
return requireModule().mastering(
|
|
1112
1189
|
samples,
|
|
@@ -1125,6 +1202,14 @@ function masteringInsertNames() {
|
|
|
1125
1202
|
function masteringInsertParamNames(name) {
|
|
1126
1203
|
return requireModule().masteringInsertParamNames(name);
|
|
1127
1204
|
}
|
|
1205
|
+
function masteringInsertParamInfo(name) {
|
|
1206
|
+
const json = requireModule().masteringInsertParamInfo(name);
|
|
1207
|
+
return JSON.parse(json);
|
|
1208
|
+
}
|
|
1209
|
+
function masteringProcessorCatalog() {
|
|
1210
|
+
const json = requireModule().masteringProcessorCatalog();
|
|
1211
|
+
return JSON.parse(json);
|
|
1212
|
+
}
|
|
1128
1213
|
function masteringPairProcessorNames() {
|
|
1129
1214
|
return requireModule().masteringPairProcessorNames();
|
|
1130
1215
|
}
|
|
@@ -1469,11 +1554,18 @@ function analyzeMelody(samples, sampleRate = 22050, options = {}) {
|
|
|
1469
1554
|
const fmin = options.fmin ?? 65;
|
|
1470
1555
|
const fmax = options.fmax ?? 2093;
|
|
1471
1556
|
validateFrequencyBounds("analyzeMelody", fmin, fmax);
|
|
1557
|
+
if (fmin <= 0) {
|
|
1558
|
+
throw new RangeError("analyzeMelody: fmin must be positive");
|
|
1559
|
+
}
|
|
1472
1560
|
validatePositiveIntegers("analyzeMelody", {
|
|
1473
1561
|
frameLength: options.frameLength ?? 2048,
|
|
1474
1562
|
hopLength: options.hopLength ?? 256
|
|
1475
1563
|
});
|
|
1476
|
-
|
|
1564
|
+
const threshold = options.threshold ?? 0.1;
|
|
1565
|
+
assertFiniteScalar("analyzeMelody", threshold, "threshold");
|
|
1566
|
+
if (threshold <= 0) {
|
|
1567
|
+
throw new RangeError("analyzeMelody: threshold must be positive");
|
|
1568
|
+
}
|
|
1477
1569
|
return requireModule3().analyzeMelody(
|
|
1478
1570
|
samples,
|
|
1479
1571
|
sampleRate,
|
|
@@ -2609,10 +2701,25 @@ function waveformPeakPyramid(samples, channels, options = {}) {
|
|
|
2609
2701
|
|
|
2610
2702
|
// src/opfs_clip_pages.ts
|
|
2611
2703
|
var opfsClipPageWorkerSource = `
|
|
2704
|
+
const sonareClipPageReadQueues = new Map();
|
|
2705
|
+
|
|
2706
|
+
function sonareEnqueueClipPageRead(key, task) {
|
|
2707
|
+
const previous = sonareClipPageReadQueues.get(key) || Promise.resolve();
|
|
2708
|
+
const next = previous.catch(() => undefined).then(task);
|
|
2709
|
+
const queued = next.finally(() => {
|
|
2710
|
+
if (sonareClipPageReadQueues.get(key) === queued) {
|
|
2711
|
+
sonareClipPageReadQueues.delete(key);
|
|
2712
|
+
}
|
|
2713
|
+
});
|
|
2714
|
+
sonareClipPageReadQueues.set(key, queued);
|
|
2715
|
+
return next;
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2612
2718
|
self.onmessage = async (event) => {
|
|
2613
2719
|
const message = event.data;
|
|
2614
2720
|
if (!message || message.type !== 'sonare:read-clip-page') return;
|
|
2615
2721
|
const { requestId, path, pageIndex, numChannels, numSamples, pageFrames, dataOffsetBytes = 0 } = message;
|
|
2722
|
+
await sonareEnqueueClipPageRead(String(path), async () => {
|
|
2616
2723
|
try {
|
|
2617
2724
|
if (pageIndex < 0) {
|
|
2618
2725
|
self.postMessage({ type: 'sonare:clip-page', requestId, pageIndex, ok: false });
|
|
@@ -2675,6 +2782,7 @@ self.onmessage = async (event) => {
|
|
|
2675
2782
|
error: error instanceof Error ? error.message : String(error),
|
|
2676
2783
|
});
|
|
2677
2784
|
}
|
|
2785
|
+
});
|
|
2678
2786
|
};
|
|
2679
2787
|
`;
|
|
2680
2788
|
function createOpfsClipPageWorker() {
|
|
@@ -2694,6 +2802,7 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2694
2802
|
const ownsWorker = options.worker === void 0 || options.terminateWorkerOnClose === true;
|
|
2695
2803
|
let nextRequestId = 1;
|
|
2696
2804
|
let closed = false;
|
|
2805
|
+
let readQueue = Promise.resolve();
|
|
2697
2806
|
const pending = /* @__PURE__ */ new Map();
|
|
2698
2807
|
const onMessage = (event) => {
|
|
2699
2808
|
const response = event.data;
|
|
@@ -2733,15 +2842,29 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2733
2842
|
const promise = new Promise((resolve, reject) => {
|
|
2734
2843
|
pending.set(requestId, { resolve, reject });
|
|
2735
2844
|
});
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2845
|
+
readQueue = readQueue.catch(() => void 0).then(() => {
|
|
2846
|
+
if (closed) {
|
|
2847
|
+
const entry = pending.get(requestId);
|
|
2848
|
+
pending.delete(requestId);
|
|
2849
|
+
entry?.reject(new Error("OpfsClipPageProvider is closed"));
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
worker.postMessage({
|
|
2853
|
+
type: "sonare:read-clip-page",
|
|
2854
|
+
requestId,
|
|
2855
|
+
path: options.path,
|
|
2856
|
+
pageIndex,
|
|
2857
|
+
numChannels: options.numChannels,
|
|
2858
|
+
numSamples: options.numSamples,
|
|
2859
|
+
pageFrames: options.pageFrames,
|
|
2860
|
+
dataOffsetBytes: options.dataOffsetBytes ?? 0
|
|
2861
|
+
});
|
|
2862
|
+
return promise.then(
|
|
2863
|
+
() => void 0,
|
|
2864
|
+
() => void 0
|
|
2865
|
+
);
|
|
2866
|
+
});
|
|
2867
|
+
readQueue.catch(() => {
|
|
2745
2868
|
});
|
|
2746
2869
|
return promise;
|
|
2747
2870
|
};
|
|
@@ -2771,6 +2894,13 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2771
2894
|
|
|
2772
2895
|
// src/project.ts
|
|
2773
2896
|
var EXPECTED_PROJECT_ABI_VERSION = 1;
|
|
2897
|
+
var MarkerKind = {
|
|
2898
|
+
marker: 0,
|
|
2899
|
+
text: 1,
|
|
2900
|
+
lyric: 2,
|
|
2901
|
+
cuePoint: 3,
|
|
2902
|
+
keySignature: 4
|
|
2903
|
+
};
|
|
2774
2904
|
var SYNTH_ENGINE_MODES = [
|
|
2775
2905
|
"default",
|
|
2776
2906
|
"subtractive",
|
|
@@ -3110,6 +3240,22 @@ var Project = class _Project {
|
|
|
3110
3240
|
setTrackMidiDestination(trackId, destinationId) {
|
|
3111
3241
|
this.native.setTrackMidiDestination(trackId, destinationId);
|
|
3112
3242
|
}
|
|
3243
|
+
/** Set a track's linear playback gain (1.0 = unity; >= 0) via an undoable edit. */
|
|
3244
|
+
setTrackGain(trackId, gain) {
|
|
3245
|
+
this.native.setTrackGain(trackId, gain);
|
|
3246
|
+
}
|
|
3247
|
+
/** Set a track's mute flag via an undoable edit (a muted track is silent). */
|
|
3248
|
+
setTrackMute(trackId, mute) {
|
|
3249
|
+
this.native.setTrackMute(trackId, mute);
|
|
3250
|
+
}
|
|
3251
|
+
/** Set a track's solo flag via an undoable edit (when any track is soloed, only soloed tracks sound). */
|
|
3252
|
+
setTrackSolo(trackId, solo) {
|
|
3253
|
+
this.native.setTrackSolo(trackId, solo);
|
|
3254
|
+
}
|
|
3255
|
+
/** Set a track's stereo balance in [-1, +1] (0 = center) via an undoable edit. */
|
|
3256
|
+
setTrackPan(trackId, pan) {
|
|
3257
|
+
this.native.setTrackPan(trackId, pan);
|
|
3258
|
+
}
|
|
3113
3259
|
/** Undo the most recent edit. */
|
|
3114
3260
|
undo() {
|
|
3115
3261
|
this.native.undo();
|
|
@@ -3399,6 +3545,22 @@ var Project = class _Project {
|
|
|
3399
3545
|
setMarker(markerId, ppq, name) {
|
|
3400
3546
|
return this.native.setMarker(markerId, ppq, name);
|
|
3401
3547
|
}
|
|
3548
|
+
/**
|
|
3549
|
+
* Add or replace a marker from a full {@link ProjectMarker}, including its
|
|
3550
|
+
* {@link MarkerKind} and (for key signatures) the key. Pass `id` 0 to allocate
|
|
3551
|
+
* a new id; returns the stable marker id.
|
|
3552
|
+
*/
|
|
3553
|
+
setMarkerEx(marker) {
|
|
3554
|
+
return this.native.setMarkerEx(marker);
|
|
3555
|
+
}
|
|
3556
|
+
/** Read a project marker by index (0-based, in stored order). */
|
|
3557
|
+
markerByIndex(index) {
|
|
3558
|
+
return this.native.markerByIndex(index);
|
|
3559
|
+
}
|
|
3560
|
+
/** Number of markers in the project. */
|
|
3561
|
+
markerCount() {
|
|
3562
|
+
return this.native.markerCount();
|
|
3563
|
+
}
|
|
3402
3564
|
/** Number of tracks in the project. */
|
|
3403
3565
|
trackCount() {
|
|
3404
3566
|
return this.native.trackCount();
|
|
@@ -3492,9 +3654,6 @@ function engineCapabilities() {
|
|
|
3492
3654
|
};
|
|
3493
3655
|
}
|
|
3494
3656
|
var RealtimeEngine = class {
|
|
3495
|
-
nativeExt() {
|
|
3496
|
-
return this.native;
|
|
3497
|
-
}
|
|
3498
3657
|
constructor(sampleRate = 48e3, maxBlockSize = 128, commandCapacity = 1024, telemetryCapacity = 1024) {
|
|
3499
3658
|
const module2 = getSonareModule();
|
|
3500
3659
|
const capabilities = engineCapabilities();
|
|
@@ -3521,8 +3680,14 @@ var RealtimeEngine = class {
|
|
|
3521
3680
|
setParameterSmoothed(paramId, value, renderFrame = -1) {
|
|
3522
3681
|
this.native.setParameterSmoothed(paramId, value, renderFrame);
|
|
3523
3682
|
}
|
|
3683
|
+
setSoloMute(laneIndex, solo, mute, renderFrame = -1) {
|
|
3684
|
+
this.native.setSoloMute(laneIndex, solo, mute, renderFrame);
|
|
3685
|
+
}
|
|
3686
|
+
setMidiClips(clips) {
|
|
3687
|
+
this.native.setMidiClips(clips);
|
|
3688
|
+
}
|
|
3524
3689
|
setBuiltinInstrument(config = {}, destinationId = config.destinationId ?? 0) {
|
|
3525
|
-
this.
|
|
3690
|
+
this.native.setBuiltinInstrument(destinationId, config);
|
|
3526
3691
|
}
|
|
3527
3692
|
/**
|
|
3528
3693
|
* Bind the patch-driven NativeSynth to a realtime MIDI destination. `patch`
|
|
@@ -3534,7 +3699,7 @@ var RealtimeEngine = class {
|
|
|
3534
3699
|
* binding convenience, not part of the NativeSynth patch itself.
|
|
3535
3700
|
*/
|
|
3536
3701
|
setSynthInstrument(patch = {}, destinationId = (typeof patch === "object" ? patch.destinationId : void 0) ?? 0) {
|
|
3537
|
-
this.
|
|
3702
|
+
this.native.setSynthInstrument(destinationId, patch);
|
|
3538
3703
|
}
|
|
3539
3704
|
/**
|
|
3540
3705
|
* Load (parse) SoundFont 2 bytes into the engine so SF2 instruments can be
|
|
@@ -3543,7 +3708,7 @@ var RealtimeEngine = class {
|
|
|
3543
3708
|
* not referenced afterwards. Replaces any previously loaded SoundFont.
|
|
3544
3709
|
*/
|
|
3545
3710
|
loadSoundFont(data) {
|
|
3546
|
-
this.
|
|
3711
|
+
this.native.loadSoundFont(data);
|
|
3547
3712
|
}
|
|
3548
3713
|
/**
|
|
3549
3714
|
* Bind a GS-compatible SoundFont player to a realtime MIDI destination, fed
|
|
@@ -3555,13 +3720,13 @@ var RealtimeEngine = class {
|
|
|
3555
3720
|
* synthesizer GM fallback bank (the data-free floor).
|
|
3556
3721
|
*/
|
|
3557
3722
|
setSf2Instrument(config = {}, destinationId = config.destinationId ?? 0) {
|
|
3558
|
-
this.
|
|
3723
|
+
this.native.setSf2Instrument(destinationId, config);
|
|
3559
3724
|
}
|
|
3560
3725
|
clearMidiInstrument(destinationId = 0) {
|
|
3561
|
-
this.
|
|
3726
|
+
this.native.clearMidiInstrument(destinationId);
|
|
3562
3727
|
}
|
|
3563
3728
|
midiInstrumentCount() {
|
|
3564
|
-
return this.
|
|
3729
|
+
return this.native.midiInstrumentCount();
|
|
3565
3730
|
}
|
|
3566
3731
|
/**
|
|
3567
3732
|
* Bind a live MIDI CC to an engine automation parameter. The MIDI event still
|
|
@@ -3569,7 +3734,7 @@ var RealtimeEngine = class {
|
|
|
3569
3734
|
* mapped into [minValue, maxValue] for `paramId`.
|
|
3570
3735
|
*/
|
|
3571
3736
|
bindMidiCc(channel, controller, paramId, options = {}) {
|
|
3572
|
-
this.
|
|
3737
|
+
this.native.bindMidiCc(
|
|
3573
3738
|
channel,
|
|
3574
3739
|
controller,
|
|
3575
3740
|
paramId,
|
|
@@ -3578,42 +3743,42 @@ var RealtimeEngine = class {
|
|
|
3578
3743
|
);
|
|
3579
3744
|
}
|
|
3580
3745
|
clearMidiCcBindings() {
|
|
3581
|
-
this.
|
|
3746
|
+
this.native.clearMidiCcBindings();
|
|
3582
3747
|
}
|
|
3583
3748
|
midiCcBindingCount() {
|
|
3584
|
-
return this.
|
|
3749
|
+
return this.native.midiCcBindingCount();
|
|
3585
3750
|
}
|
|
3586
3751
|
/** Install/replace a live non-destructive MIDI-FX insert for one destination. */
|
|
3587
3752
|
setMidiFx(destinationId, configJson) {
|
|
3588
|
-
this.
|
|
3753
|
+
this.native.setMidiFx(destinationId, configJson);
|
|
3589
3754
|
}
|
|
3590
3755
|
clearMidiFx(destinationId = 0) {
|
|
3591
|
-
this.
|
|
3756
|
+
this.native.clearMidiFx(destinationId);
|
|
3592
3757
|
}
|
|
3593
3758
|
/** Enable the engine-owned live MIDI input source for a destination. */
|
|
3594
3759
|
setMidiInputSource(destinationId = 0) {
|
|
3595
|
-
this.
|
|
3760
|
+
this.native.setMidiInputSource(destinationId);
|
|
3596
3761
|
}
|
|
3597
3762
|
clearMidiInputSource() {
|
|
3598
|
-
this.
|
|
3763
|
+
this.native.clearMidiInputSource();
|
|
3599
3764
|
}
|
|
3600
3765
|
midiInputPendingCount() {
|
|
3601
|
-
return this.
|
|
3766
|
+
return this.native.midiInputPendingCount();
|
|
3602
3767
|
}
|
|
3603
3768
|
pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples = 0) {
|
|
3604
|
-
this.
|
|
3769
|
+
this.native.pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples);
|
|
3605
3770
|
}
|
|
3606
3771
|
pushMidiInputNoteOff(group, channel, note, velocity = 0, portTimeSamples = 0) {
|
|
3607
|
-
this.
|
|
3772
|
+
this.native.pushMidiInputNoteOff(group, channel, note, velocity, portTimeSamples);
|
|
3608
3773
|
}
|
|
3609
3774
|
pushMidiInputCc(group, channel, controller, value, portTimeSamples = 0) {
|
|
3610
|
-
this.
|
|
3775
|
+
this.native.pushMidiInputCc(group, channel, controller, value, portTimeSamples);
|
|
3611
3776
|
}
|
|
3612
3777
|
pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame = -1) {
|
|
3613
|
-
this.
|
|
3778
|
+
this.native.pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame);
|
|
3614
3779
|
}
|
|
3615
3780
|
pushMidiNoteOff(destinationId, group, channel, note, velocity = 0, renderFrame = -1) {
|
|
3616
|
-
this.
|
|
3781
|
+
this.native.pushMidiNoteOff(destinationId, group, channel, note, velocity, renderFrame);
|
|
3617
3782
|
}
|
|
3618
3783
|
/**
|
|
3619
3784
|
* Queue an immediate (live) MIDI control change to a MIDI destination
|
|
@@ -3622,21 +3787,21 @@ var RealtimeEngine = class {
|
|
|
3622
3787
|
* immediate. Mirrors the Node/Python/C-ABI `pushMidiCc`.
|
|
3623
3788
|
*/
|
|
3624
3789
|
pushMidiCc(destinationId, group, channel, controller, value, renderFrame = -1) {
|
|
3625
|
-
this.
|
|
3790
|
+
this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
|
|
3626
3791
|
}
|
|
3627
3792
|
/**
|
|
3628
3793
|
* Queue a MIDI panic (all-notes-off) releasing every sounding note at
|
|
3629
3794
|
* `renderFrame` (-1 = immediate). Mirrors the C-ABI `pushMidiPanic`.
|
|
3630
3795
|
*/
|
|
3631
3796
|
pushMidiPanic(renderFrame = -1) {
|
|
3632
|
-
this.
|
|
3797
|
+
this.native.pushMidiPanic(renderFrame);
|
|
3633
3798
|
}
|
|
3634
3799
|
/**
|
|
3635
3800
|
* Remove all registered parameters (and their automation lanes). Control-thread
|
|
3636
3801
|
* only; not realtime-safe. Mirrors the C-ABI `clearParameters`.
|
|
3637
3802
|
*/
|
|
3638
3803
|
clearParameters() {
|
|
3639
|
-
this.
|
|
3804
|
+
this.native.clearParameters();
|
|
3640
3805
|
}
|
|
3641
3806
|
/** Read back the current transport state snapshot. */
|
|
3642
3807
|
getTransportState() {
|
|
@@ -3651,15 +3816,33 @@ var RealtimeEngine = class {
|
|
|
3651
3816
|
seekSample(timelineSample, renderFrame = -1) {
|
|
3652
3817
|
this.native.seekSample(timelineSample, renderFrame);
|
|
3653
3818
|
}
|
|
3819
|
+
/**
|
|
3820
|
+
* Snaps every in-flight parameter ramp (engine-level smoothed params, mixer
|
|
3821
|
+
* lane fader/pan/gate, bus gains) to its target value. Offline renders call
|
|
3822
|
+
* this after a priming process() block so the first audible block renders at
|
|
3823
|
+
* settled values instead of ramping in from defaults.
|
|
3824
|
+
*/
|
|
3825
|
+
settleParameters() {
|
|
3826
|
+
this.native.settleParameters();
|
|
3827
|
+
}
|
|
3654
3828
|
seekPpq(ppq, renderFrame = -1) {
|
|
3655
3829
|
this.native.seekPpq(ppq, renderFrame);
|
|
3656
3830
|
}
|
|
3657
3831
|
setTempo(bpm) {
|
|
3658
3832
|
this.native.setTempo(bpm);
|
|
3659
3833
|
}
|
|
3834
|
+
setTempoSegments(segments) {
|
|
3835
|
+
this.native.setTempoSegments([...segments]);
|
|
3836
|
+
}
|
|
3660
3837
|
setTimeSignature(numerator, denominator) {
|
|
3661
3838
|
this.native.setTimeSignature(numerator, denominator);
|
|
3662
3839
|
}
|
|
3840
|
+
setTimeSignatureSegments(segments) {
|
|
3841
|
+
this.native.setTimeSignatureSegments([...segments]);
|
|
3842
|
+
}
|
|
3843
|
+
sampleAtPpq(ppq) {
|
|
3844
|
+
return Number(this.native.sampleAtPpq(ppq));
|
|
3845
|
+
}
|
|
3663
3846
|
setLoop(startPpq, endPpq, enabled = true) {
|
|
3664
3847
|
this.native.setLoop(startPpq, endPpq, enabled);
|
|
3665
3848
|
}
|
|
@@ -3728,21 +3911,140 @@ var RealtimeEngine = class {
|
|
|
3728
3911
|
clipCount() {
|
|
3729
3912
|
return this.native.clipCount();
|
|
3730
3913
|
}
|
|
3914
|
+
setTrackLanes(lanes) {
|
|
3915
|
+
this.native.setTrackLanes(
|
|
3916
|
+
lanes.map((lane) => {
|
|
3917
|
+
if (typeof lane === "number") {
|
|
3918
|
+
return { trackId: lane };
|
|
3919
|
+
}
|
|
3920
|
+
if (!lane.sends) {
|
|
3921
|
+
return lane;
|
|
3922
|
+
}
|
|
3923
|
+
return {
|
|
3924
|
+
...lane,
|
|
3925
|
+
sends: lane.sends.map((send) => ({
|
|
3926
|
+
...send,
|
|
3927
|
+
// Post-fader (0) is the default for an omitted sendTiming.
|
|
3928
|
+
sendTiming: send.sendTiming === void 0 ? 0 : sendTimingCode(send.sendTiming)
|
|
3929
|
+
}))
|
|
3930
|
+
};
|
|
3931
|
+
})
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3934
|
+
/**
|
|
3935
|
+
* Keys one insert of a lane strip from another lane's post-strip audio
|
|
3936
|
+
* (ducking/sidechainRouter inserts). sourceTrackId 0 removes the binding.
|
|
3937
|
+
*/
|
|
3938
|
+
setLaneSidechain(trackId, insertIndex, sourceTrackId) {
|
|
3939
|
+
this.native.setLaneSidechain(trackId, insertIndex, sourceTrackId);
|
|
3940
|
+
}
|
|
3941
|
+
setTrackBuses(buses) {
|
|
3942
|
+
this.native.setTrackBuses(buses);
|
|
3943
|
+
}
|
|
3944
|
+
setBusStripJson(busId, sceneJson) {
|
|
3945
|
+
try {
|
|
3946
|
+
JSON.parse(sceneJson);
|
|
3947
|
+
} catch (error) {
|
|
3948
|
+
const message = error instanceof Error ? error.message : "invalid bus strip JSON";
|
|
3949
|
+
throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
|
|
3950
|
+
}
|
|
3951
|
+
this.native.setBusStripJson(busId, sceneJson);
|
|
3952
|
+
}
|
|
3953
|
+
setTrackStripJson(trackId, sceneJson) {
|
|
3954
|
+
try {
|
|
3955
|
+
JSON.parse(sceneJson);
|
|
3956
|
+
} catch (error) {
|
|
3957
|
+
const message = error instanceof Error ? error.message : "invalid track strip JSON";
|
|
3958
|
+
throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
|
|
3959
|
+
}
|
|
3960
|
+
this.native.setTrackStripJson(trackId, sceneJson);
|
|
3961
|
+
}
|
|
3962
|
+
setTrackStripEqBand(trackId, bandIndex, band) {
|
|
3963
|
+
this.native.setTrackStripEqBandJson(
|
|
3964
|
+
trackId,
|
|
3965
|
+
bandIndex,
|
|
3966
|
+
typeof band === "string" ? band : JSON.stringify(band)
|
|
3967
|
+
);
|
|
3968
|
+
}
|
|
3969
|
+
setTrackStripEqBandJson(trackId, bandIndex, bandJson) {
|
|
3970
|
+
this.native.setTrackStripEqBandJson(trackId, bandIndex, bandJson);
|
|
3971
|
+
}
|
|
3972
|
+
setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass = false) {
|
|
3973
|
+
this.native.setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass);
|
|
3974
|
+
}
|
|
3975
|
+
setMasterStripJson(sceneJson) {
|
|
3976
|
+
try {
|
|
3977
|
+
JSON.parse(sceneJson);
|
|
3978
|
+
} catch (error) {
|
|
3979
|
+
const message = error instanceof Error ? error.message : "invalid master strip JSON";
|
|
3980
|
+
throw new SonareError(2 /* InvalidFormat */, "InvalidFormat", message);
|
|
3981
|
+
}
|
|
3982
|
+
this.native.setMasterStripJson(sceneJson);
|
|
3983
|
+
}
|
|
3984
|
+
setMasterStripEqBand(bandIndex, band) {
|
|
3985
|
+
this.native.setMasterStripEqBandJson(
|
|
3986
|
+
bandIndex,
|
|
3987
|
+
typeof band === "string" ? band : JSON.stringify(band)
|
|
3988
|
+
);
|
|
3989
|
+
}
|
|
3990
|
+
setMasterStripEqBandJson(bandIndex, bandJson) {
|
|
3991
|
+
this.native.setMasterStripEqBandJson(bandIndex, bandJson);
|
|
3992
|
+
}
|
|
3993
|
+
setMasterStripInsertBypassed(insertIndex, bypassed, resetOnBypass = false) {
|
|
3994
|
+
this.native.setMasterStripInsertBypassed(insertIndex, bypassed, resetOnBypass);
|
|
3995
|
+
}
|
|
3996
|
+
/**
|
|
3997
|
+
* Changes one track-strip insert parameter in realtime, addressed by the
|
|
3998
|
+
* processor's JSON-key parameter name (see {@link masteringInsertParamInfo}).
|
|
3999
|
+
* Applied at the next block head via the engine command queue; safe during
|
|
4000
|
+
* playback. Throws if the track, insert, or name is unknown, the param is not
|
|
4001
|
+
* realtime-safe, or the command queue is full.
|
|
4002
|
+
*/
|
|
4003
|
+
setTrackStripInsertParamByName(trackId, insertIndex, paramName, value) {
|
|
4004
|
+
this.native.setTrackStripInsertParamByName(trackId, insertIndex, paramName, value);
|
|
4005
|
+
}
|
|
4006
|
+
/** Master-strip counterpart of {@link setTrackStripInsertParamByName}. */
|
|
4007
|
+
setMasterStripInsertParamByName(insertIndex, paramName, value) {
|
|
4008
|
+
this.native.setMasterStripInsertParamByName(insertIndex, paramName, value);
|
|
4009
|
+
}
|
|
4010
|
+
/** Sets a track lane strip's pan position in realtime (glitch-free). */
|
|
4011
|
+
setTrackStripPan(trackId, pan) {
|
|
4012
|
+
this.native.setTrackStripPan(trackId, pan);
|
|
4013
|
+
}
|
|
4014
|
+
/** Sets a track lane strip's pan law in realtime. */
|
|
4015
|
+
setTrackStripPanLaw(trackId, panLaw) {
|
|
4016
|
+
this.native.setTrackStripPanLaw(trackId, panLawCode(panLaw));
|
|
4017
|
+
}
|
|
4018
|
+
/** Sets a track lane strip's pan mode in realtime. */
|
|
4019
|
+
setTrackStripPanMode(trackId, panMode) {
|
|
4020
|
+
this.native.setTrackStripPanMode(trackId, panModeCode(panMode));
|
|
4021
|
+
}
|
|
4022
|
+
/** Sets a track lane strip's dual-pan left/right positions in realtime. */
|
|
4023
|
+
setTrackStripDualPan(trackId, leftPan, rightPan) {
|
|
4024
|
+
this.native.setTrackStripDualPan(trackId, leftPan, rightPan);
|
|
4025
|
+
}
|
|
4026
|
+
/**
|
|
4027
|
+
* Sets a track lane strip's inter-channel alignment delay (whole samples).
|
|
4028
|
+
* Adjusts strip latency, so PDC and reported graph latency are refreshed.
|
|
4029
|
+
*/
|
|
4030
|
+
setTrackStripChannelDelaySamples(trackId, delaySamples) {
|
|
4031
|
+
this.native.setTrackStripChannelDelaySamples(trackId, delaySamples);
|
|
4032
|
+
}
|
|
3731
4033
|
createClipPageProvider(numChannels, numSamples, pageFrames) {
|
|
3732
|
-
const id = this.
|
|
4034
|
+
const id = this.native.createClipPageProvider(numChannels, numSamples, pageFrames);
|
|
3733
4035
|
return new ClipPageProvider(this, id);
|
|
3734
4036
|
}
|
|
3735
4037
|
supplyClipPage(providerId, pageIndex, channels) {
|
|
3736
|
-
this.
|
|
4038
|
+
this.native.supplyClipPage(providerId, pageIndex, channels);
|
|
3737
4039
|
}
|
|
3738
4040
|
clearClipPage(providerId, pageIndex) {
|
|
3739
|
-
this.
|
|
4041
|
+
this.native.clearClipPage(providerId, pageIndex);
|
|
3740
4042
|
}
|
|
3741
4043
|
destroyClipPageProvider(providerId) {
|
|
3742
|
-
this.
|
|
4044
|
+
this.native.destroyClipPageProvider(providerId);
|
|
3743
4045
|
}
|
|
3744
4046
|
popClipPageRequest() {
|
|
3745
|
-
return this.
|
|
4047
|
+
return this.native.popClipPageRequest();
|
|
3746
4048
|
}
|
|
3747
4049
|
setCaptureBuffer(numChannels, capacityFrames) {
|
|
3748
4050
|
this.native.setCaptureBuffer(numChannels, capacityFrames);
|
|
@@ -3817,6 +4119,30 @@ var RealtimeEngine = class {
|
|
|
3817
4119
|
drainMeterTelemetry(maxRecords = 1024) {
|
|
3818
4120
|
return this.native.drainMeterTelemetry(maxRecords);
|
|
3819
4121
|
}
|
|
4122
|
+
/**
|
|
4123
|
+
* Drains pending meter telemetry as per-plane (wide) records for a surround
|
|
4124
|
+
* target. Use this for a surround mix target; {@link drainMeterTelemetry}
|
|
4125
|
+
* stays the stereo fast path. The two share one queue — call only one per
|
|
4126
|
+
* target. The live AudioWorklet path owns the queue via the stereo drain, so
|
|
4127
|
+
* this wide drain is for an offline (non-worklet) engine instance; per-plane
|
|
4128
|
+
* surround meters are not delivered over the live worklet meter ring.
|
|
4129
|
+
*/
|
|
4130
|
+
drainMeterTelemetryWide(maxRecords = 1024) {
|
|
4131
|
+
return this.native.drainMeterTelemetryWide(maxRecords);
|
|
4132
|
+
}
|
|
4133
|
+
/**
|
|
4134
|
+
* Enables per-target spectrum + vectorscope capture. @param intervalFrames is
|
|
4135
|
+
* the minimum render-frame gap between snapshots (0 disables). @param bandCount
|
|
4136
|
+
* is the FFT band resolution (1..64); changing it re-prepares the tap. Returns
|
|
4137
|
+
* the band count actually applied.
|
|
4138
|
+
*/
|
|
4139
|
+
configureScopeTelemetry(intervalFrames, bandCount) {
|
|
4140
|
+
return this.native.configureScopeTelemetry(intervalFrames, bandCount);
|
|
4141
|
+
}
|
|
4142
|
+
/** Drains pending spectrum + vectorscope snapshots (per mix target). */
|
|
4143
|
+
drainScopeTelemetry(maxRecords = 1024) {
|
|
4144
|
+
return this.native.drainScopeTelemetry(maxRecords);
|
|
4145
|
+
}
|
|
3820
4146
|
destroy() {
|
|
3821
4147
|
this.native.delete();
|
|
3822
4148
|
}
|
|
@@ -4105,7 +4431,6 @@ async function bindWebMidi(engine, options = {}) {
|
|
|
4105
4431
|
engine.setMidiInputSource(destinationId);
|
|
4106
4432
|
const bound = /* @__PURE__ */ new Map();
|
|
4107
4433
|
let closed = false;
|
|
4108
|
-
let runningStatus = 0;
|
|
4109
4434
|
const shouldBind = (input) => input.state !== "disconnected" && (selectedIds.size === 0 || selectedIds.has(input.id));
|
|
4110
4435
|
const snapshotInputs = () => Array.from(iterInputs(access), ([id, input]) => ({
|
|
4111
4436
|
id,
|
|
@@ -4118,22 +4443,26 @@ async function bindWebMidi(engine, options = {}) {
|
|
|
4118
4443
|
if (bound.has(input.id) || !shouldBind(input)) {
|
|
4119
4444
|
return;
|
|
4120
4445
|
}
|
|
4121
|
-
const
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4446
|
+
const entry = {
|
|
4447
|
+
input,
|
|
4448
|
+
listener: (event) => {
|
|
4449
|
+
entry.runningStatus = dispatchMidiMessage(
|
|
4450
|
+
engine,
|
|
4451
|
+
event,
|
|
4452
|
+
group,
|
|
4453
|
+
entry.runningStatus,
|
|
4454
|
+
options.timestampToSamples
|
|
4455
|
+
);
|
|
4456
|
+
},
|
|
4457
|
+
runningStatus: 0
|
|
4130
4458
|
};
|
|
4459
|
+
const listener = entry.listener;
|
|
4131
4460
|
if (input.addEventListener) {
|
|
4132
4461
|
input.addEventListener("midimessage", listener);
|
|
4133
4462
|
} else {
|
|
4134
4463
|
input.onmidimessage = listener;
|
|
4135
4464
|
}
|
|
4136
|
-
bound.set(input.id,
|
|
4465
|
+
bound.set(input.id, entry);
|
|
4137
4466
|
};
|
|
4138
4467
|
const unbindInput = (input) => {
|
|
4139
4468
|
const entry = bound.get(input.id);
|
|
@@ -4318,7 +4647,7 @@ async function init(options) {
|
|
|
4318
4647
|
}
|
|
4319
4648
|
initPromise = (async () => {
|
|
4320
4649
|
try {
|
|
4321
|
-
const createModule = (await import("./sonare.js")).default;
|
|
4650
|
+
const createModule = options?.moduleFactory ?? (await import("./sonare.js")).default;
|
|
4322
4651
|
module = await createModule(options);
|
|
4323
4652
|
setSonareModule(module);
|
|
4324
4653
|
} catch (error) {
|
|
@@ -4386,6 +4715,7 @@ export {
|
|
|
4386
4715
|
EXPECTED_PROJECT_ABI_VERSION,
|
|
4387
4716
|
ErrorCode,
|
|
4388
4717
|
KeyProfile,
|
|
4718
|
+
MarkerKind,
|
|
4389
4719
|
Mixer,
|
|
4390
4720
|
Mode,
|
|
4391
4721
|
PitchClass as Pitch,
|
|
@@ -4479,6 +4809,7 @@ export {
|
|
|
4479
4809
|
masteringDynamicsGate,
|
|
4480
4810
|
masteringDynamicsTransientShaper,
|
|
4481
4811
|
masteringInsertNames,
|
|
4812
|
+
masteringInsertParamInfo,
|
|
4482
4813
|
masteringInsertParamNames,
|
|
4483
4814
|
masteringPairAnalysisNames,
|
|
4484
4815
|
masteringPairAnalyze,
|
|
@@ -4487,6 +4818,7 @@ export {
|
|
|
4487
4818
|
masteringPresetNames,
|
|
4488
4819
|
masteringProcess,
|
|
4489
4820
|
masteringProcessStereo,
|
|
4821
|
+
masteringProcessorCatalog,
|
|
4490
4822
|
masteringProcessorNames,
|
|
4491
4823
|
masteringRepairDeclick,
|
|
4492
4824
|
masteringRepairDeclip,
|
|
@@ -4565,6 +4897,7 @@ export {
|
|
|
4565
4897
|
spectralBandwidth,
|
|
4566
4898
|
spectralCentroid,
|
|
4567
4899
|
spectralContrast,
|
|
4900
|
+
spectralEdit,
|
|
4568
4901
|
spectralFlatness,
|
|
4569
4902
|
spectralRolloff,
|
|
4570
4903
|
splitSilence,
|