@libraz/libsonare 1.6.0 → 1.7.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 +2 -2
- package/dist/analysis.d.ts +88 -9
- package/dist/analysis.js +152 -42
- package/dist/analysis.js.map +1 -1
- package/dist/index.d.ts +129 -24
- package/dist/index.js +455 -140
- package/dist/index.js.map +1 -1
- package/dist/schemas/realtime-voice-changer-preset.schema.json +2 -2
- package/dist/sonare-analysis.js +1 -1
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worker.js +56 -29
- package/dist/worker.js.map +1 -1
- package/dist/worklet.d.ts +62 -10
- package/dist/worklet.js +193 -42
- package/dist/worklet.js.map +1 -1
- package/package.json +3 -3
- package/src/analysis_helpers.ts +34 -29
- package/src/audio.ts +7 -2
- package/src/codes.ts +47 -11
- package/src/effects_transform.ts +179 -10
- package/src/feature_music.ts +8 -1
- package/src/feature_spectral.ts +64 -2
- package/src/feature_spectrogram.ts +44 -3
- package/src/index.ts +21 -3
- package/src/mixer.ts +3 -3
- package/src/project.ts +6 -0
- package/src/project_class.ts +143 -16
- package/src/project_internal.ts +14 -5
- package/src/project_types.ts +45 -1
- package/src/public_types_mixing.ts +16 -0
- package/src/public_types_realtime.ts +23 -5
- package/src/quick_analysis.ts +21 -3
- package/src/realtime_engine.ts +14 -3
- package/src/sonare.js.d.ts +64 -0
- package/src/stream_analyzer.ts +6 -1
- package/src/web_midi.ts +10 -7
- package/src/worklet/engine-node.ts +54 -19
- package/src/worklet/engine-parameter-facade.ts +30 -1
- package/src/worklet/engine-processor.ts +52 -20
- package/src/worklet/engine-register.ts +1 -1
- package/src/worklet/engine-strips.ts +2 -2
- package/src/worklet/engine.ts +10 -0
- package/src/worklet/guards.ts +99 -7
- package/src/worklet/messages.ts +41 -1
- package/src/worklet/protocol.ts +4 -0
package/dist/worklet.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ interface SynthPatch {
|
|
|
52
52
|
* `(destination_id, patch)` bindings instead. Defaults to `0`.
|
|
53
53
|
*/
|
|
54
54
|
destinationId?: number;
|
|
55
|
+
/** Resolve MIDI channels from incoming GM bank/program changes; defaults to false. */
|
|
56
|
+
useGmPrograms?: boolean;
|
|
55
57
|
/** Base preset name (see {@link synthPresetNames}); omit for the init patch. */
|
|
56
58
|
preset?: string;
|
|
57
59
|
engineMode?: SynthEngineMode | number;
|
|
@@ -128,6 +130,10 @@ type AutomationCurve = 'linear' | 'exponential' | 'hold' | 's-curve';
|
|
|
128
130
|
* remains unity. Maps to the underlying integer code.
|
|
129
131
|
*/
|
|
130
132
|
type PanLaw = 'const3dB' | 'const4.5dB' | 'const6dB' | 'linear0dB';
|
|
133
|
+
/** Accepted pan-law name aliases for mixer and realtime-engine inputs. */
|
|
134
|
+
type PanLawName = PanLaw | 'const-3db' | '-3db' | 'const-4.5db' | '-4.5db' | 'const-6db' | '-6db' | 'linear-0db' | 'linear' | '0db';
|
|
135
|
+
/** Pan-law name or raw C ABI ordinal. */
|
|
136
|
+
type PanLawInput = PanLawName | number;
|
|
131
137
|
/** Pre/post-fader send timing (see {@link Mixer.addSend}). */
|
|
132
138
|
type SendTiming = 'preFader' | 'postFader';
|
|
133
139
|
|
|
@@ -174,14 +180,21 @@ interface EqBand {
|
|
|
174
180
|
sidechainQ?: number;
|
|
175
181
|
}
|
|
176
182
|
type VoicePresetId = 'neutral-monitor' | 'bright-idol' | 'soft-whisper' | 'deep-narrator' | 'robot-mascot' | 'dark-villain';
|
|
177
|
-
|
|
183
|
+
type VoicePresetCategory = 'monitor' | 'bright' | 'soft' | 'deep' | 'robot' | 'dark' | 'custom';
|
|
184
|
+
interface RealtimeVoiceChangerPresetMetadata {
|
|
178
185
|
schemaVersion: 1;
|
|
179
|
-
id
|
|
180
|
-
name
|
|
186
|
+
id: string;
|
|
187
|
+
name: string;
|
|
181
188
|
description?: string;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
category: VoicePresetCategory;
|
|
190
|
+
}
|
|
191
|
+
type RealtimeVoiceChangerPreset = (RealtimeVoiceChangerPresetMetadata & {
|
|
192
|
+
dsp: Record<string, unknown>;
|
|
193
|
+
macros?: never;
|
|
194
|
+
}) | (RealtimeVoiceChangerPresetMetadata & {
|
|
195
|
+
macros: Record<string, number>;
|
|
196
|
+
dsp?: never;
|
|
197
|
+
});
|
|
185
198
|
type RealtimeVoiceChangerConfigInput = VoicePresetId | RealtimeVoiceChangerPreset;
|
|
186
199
|
/**
|
|
187
200
|
* Flat (POD) realtime voice-changer configuration. Keys are camelCase to match
|
|
@@ -274,6 +287,8 @@ interface EngineTrackLane {
|
|
|
274
287
|
*/
|
|
275
288
|
sourceChannelLayout?: number;
|
|
276
289
|
}
|
|
290
|
+
/** Per-track cue/monitor tap mode: off, pre-fader listen, or after-fader listen. */
|
|
291
|
+
type EngineTrackMonitorMode = 'off' | 'pfl' | 'afl' | 0 | 1 | 2;
|
|
277
292
|
interface EngineBus {
|
|
278
293
|
busId: number;
|
|
279
294
|
gainDb?: number;
|
|
@@ -330,6 +345,8 @@ declare class RealtimeEngine {
|
|
|
330
345
|
*/
|
|
331
346
|
setParamSmoothingMs(smoothingMs: number): void;
|
|
332
347
|
setSoloMute(laneIndex: number, solo: boolean, mute: boolean, renderFrame?: number): void;
|
|
348
|
+
/** Queue a per-track PFL/AFL monitor tap mode change. */
|
|
349
|
+
setTrackMonitorMode(laneIndex: number, mode: EngineTrackMonitorMode, renderFrame?: number): void;
|
|
333
350
|
setMidiClips(clips: readonly EngineMidiClipSchedule[]): void;
|
|
334
351
|
setBuiltinInstrument(config?: {
|
|
335
352
|
destinationId?: number;
|
|
@@ -536,7 +553,7 @@ declare class RealtimeEngine {
|
|
|
536
553
|
/** Sets a track lane strip's pan position in realtime (glitch-free). */
|
|
537
554
|
setTrackStripPan(trackId: number, pan: number): void;
|
|
538
555
|
/** Sets a track lane strip's pan law in realtime. */
|
|
539
|
-
setTrackStripPanLaw(trackId: number, panLaw:
|
|
556
|
+
setTrackStripPanLaw(trackId: number, panLaw: PanLawInput): void;
|
|
540
557
|
/** Sets a track lane strip's pan mode in realtime. */
|
|
541
558
|
setTrackStripPanMode(trackId: number, panMode: PanMode | number): void;
|
|
542
559
|
/** Sets a track lane strip's dual-pan left/right positions in realtime. */
|
|
@@ -902,7 +919,8 @@ declare enum SonareEngineCommandType {
|
|
|
902
919
|
Punch = 14,
|
|
903
920
|
SetMetronome = 15,
|
|
904
921
|
SetMarker = 16,
|
|
905
|
-
SeekMarker = 17
|
|
922
|
+
SeekMarker = 17,
|
|
923
|
+
SetTrackMonitorMode = 26
|
|
906
924
|
}
|
|
907
925
|
declare enum SonareEngineTelemetryType {
|
|
908
926
|
ProcessBlock = 0,
|
|
@@ -928,7 +946,8 @@ declare enum SonareEngineTelemetryError {
|
|
|
928
946
|
InsertAutomationOverflow = 16,
|
|
929
947
|
MidiClockOverflow = 17,
|
|
930
948
|
MetronomeOverflow = 18,
|
|
931
|
-
InvalidCommand = 19
|
|
949
|
+
InvalidCommand = 19,
|
|
950
|
+
MaxChannelsExceeded = 20
|
|
932
951
|
}
|
|
933
952
|
interface SonareMeterRingBuffer {
|
|
934
953
|
sharedBuffer: SharedArrayBuffer;
|
|
@@ -1220,7 +1239,7 @@ interface SonareEngineSyncErrorMessage {
|
|
|
1220
1239
|
}
|
|
1221
1240
|
type SonareWorkletTransportMessage = SonareWorkletMeterSnapshot | SonareWorkletSpectrumSnapshot | SonareWorkletExternalMidiMessage | SonareEngineClipPageRequestMessage | SonareEngineTelemetryRecord;
|
|
1222
1241
|
interface WorkletTransport {
|
|
1223
|
-
postMessage?: (message: SonareWorkletTransportMessage |
|
|
1242
|
+
postMessage?: (message: SonareWorkletTransportMessage | SonareEngineCaptureResponseMessageInternal | SonareEngineTransportResponseMessage | SonareEngineSyncErrorMessage, transfer?: Transferable[]) => void;
|
|
1224
1243
|
onMeter?: (meter: SonareWorkletMeterSnapshot) => void;
|
|
1225
1244
|
onSpectrum?: (spectrum: SonareWorkletSpectrumSnapshot) => void;
|
|
1226
1245
|
}
|
|
@@ -1524,6 +1543,12 @@ interface SonareEngineCaptureRequestMessage {
|
|
|
1524
1543
|
requestId: number;
|
|
1525
1544
|
op: 'status' | 'read' | 'reset';
|
|
1526
1545
|
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Public capture response shape retained for source compatibility.
|
|
1548
|
+
*
|
|
1549
|
+
* The worklet wire protocol is stricter than this legacy structural type; use
|
|
1550
|
+
* `SonareEngineCaptureResponseMessageInternal` inside the implementation.
|
|
1551
|
+
*/
|
|
1527
1552
|
interface SonareEngineCaptureResponseMessage {
|
|
1528
1553
|
type: 'captureResponse';
|
|
1529
1554
|
requestId: number;
|
|
@@ -1532,6 +1557,31 @@ interface SonareEngineCaptureResponseMessage {
|
|
|
1532
1557
|
channels?: Float32Array[] | number[][];
|
|
1533
1558
|
error?: string;
|
|
1534
1559
|
}
|
|
1560
|
+
interface SonareEngineCaptureStatusResponseMessageInternal {
|
|
1561
|
+
type: 'captureResponse';
|
|
1562
|
+
requestId: number;
|
|
1563
|
+
ok: true;
|
|
1564
|
+
status: EngineCaptureStatus;
|
|
1565
|
+
}
|
|
1566
|
+
interface SonareEngineCaptureReadResponseMessageInternal {
|
|
1567
|
+
type: 'captureResponse';
|
|
1568
|
+
requestId: number;
|
|
1569
|
+
ok: true;
|
|
1570
|
+
channels: Float32Array[];
|
|
1571
|
+
}
|
|
1572
|
+
interface SonareEngineCaptureResetResponseMessageInternal {
|
|
1573
|
+
type: 'captureResponse';
|
|
1574
|
+
requestId: number;
|
|
1575
|
+
ok: true;
|
|
1576
|
+
}
|
|
1577
|
+
interface SonareEngineCaptureErrorResponseMessageInternal {
|
|
1578
|
+
type: 'captureResponse';
|
|
1579
|
+
requestId: number;
|
|
1580
|
+
ok: false;
|
|
1581
|
+
error: string;
|
|
1582
|
+
}
|
|
1583
|
+
/** Strict wire response type used only by the worklet implementation. */
|
|
1584
|
+
type SonareEngineCaptureResponseMessageInternal = SonareEngineCaptureStatusResponseMessageInternal | SonareEngineCaptureReadResponseMessageInternal | SonareEngineCaptureResetResponseMessageInternal | SonareEngineCaptureErrorResponseMessageInternal;
|
|
1535
1585
|
interface SonareEngineTransportRequestMessage {
|
|
1536
1586
|
type: 'transportRequest';
|
|
1537
1587
|
requestId: number;
|
|
@@ -1687,6 +1737,8 @@ declare class SonareEngine {
|
|
|
1687
1737
|
/** Clears custom parameters and their automation lanes on both engines. */
|
|
1688
1738
|
clearParameters(): void;
|
|
1689
1739
|
setSoloMute(target: string | number, solo: boolean, mute: boolean): boolean;
|
|
1740
|
+
/** Queues a per-track PFL/AFL monitor tap mode change. */
|
|
1741
|
+
setTrackMonitorMode(target: string | number, mode: EngineTrackMonitorMode, renderFrame?: number): boolean;
|
|
1690
1742
|
setStripGain(target: string | number, db: number): boolean;
|
|
1691
1743
|
setStripPan(target: string | number, pan: number): boolean;
|
|
1692
1744
|
/**
|
package/dist/worklet.js
CHANGED
|
@@ -545,12 +545,25 @@ function getSonareModule() {
|
|
|
545
545
|
}
|
|
546
546
|
|
|
547
547
|
// src/codes.ts
|
|
548
|
+
function resolveOrdinalInRange(value, min, max, enumName) {
|
|
549
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) {
|
|
550
|
+
throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
|
|
551
|
+
}
|
|
552
|
+
return value;
|
|
553
|
+
}
|
|
548
554
|
function resolveEnumOrdinal(value, values, enumName) {
|
|
549
555
|
if (typeof value === "number") {
|
|
550
|
-
|
|
556
|
+
const ordinals = Object.values(values);
|
|
557
|
+
const ordinal = resolveOrdinalInRange(
|
|
558
|
+
value,
|
|
559
|
+
Math.min(...ordinals),
|
|
560
|
+
Math.max(...ordinals),
|
|
561
|
+
enumName
|
|
562
|
+
);
|
|
563
|
+
if (!ordinals.includes(ordinal)) {
|
|
551
564
|
throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
|
|
552
565
|
}
|
|
553
|
-
return
|
|
566
|
+
return ordinal;
|
|
554
567
|
}
|
|
555
568
|
if (typeof value === "string") {
|
|
556
569
|
const ordinal = values[value];
|
|
@@ -567,14 +580,23 @@ var AUTOMATION_CURVE_VALUES = {
|
|
|
567
580
|
"s-curve": 3
|
|
568
581
|
};
|
|
569
582
|
var PAN_LAW_VALUES = {
|
|
570
|
-
|
|
571
|
-
"
|
|
572
|
-
|
|
573
|
-
|
|
583
|
+
const3db: 0,
|
|
584
|
+
"const-3db": 0,
|
|
585
|
+
"-3db": 0,
|
|
586
|
+
"const4.5db": 1,
|
|
587
|
+
"const-4.5db": 1,
|
|
588
|
+
"-4.5db": 1,
|
|
589
|
+
const6db: 2,
|
|
590
|
+
"const-6db": 2,
|
|
591
|
+
"-6db": 2,
|
|
592
|
+
linear0db: 3,
|
|
593
|
+
"linear-0db": 3,
|
|
594
|
+
linear: 3,
|
|
595
|
+
"0db": 3
|
|
574
596
|
};
|
|
575
597
|
var PAN_MODE_VALUES = {
|
|
576
598
|
balance: 0,
|
|
577
|
-
pan:
|
|
599
|
+
pan: 1,
|
|
578
600
|
stereopan: 1,
|
|
579
601
|
"stereo-pan": 1,
|
|
580
602
|
dualpan: 2,
|
|
@@ -582,11 +604,13 @@ var PAN_MODE_VALUES = {
|
|
|
582
604
|
};
|
|
583
605
|
var METER_TAP_VALUES = { preFader: 0, postFader: 1 };
|
|
584
606
|
var SEND_TIMING_VALUES = { postFader: 0, preFader: 1 };
|
|
607
|
+
var TRACK_MONITOR_MODE_VALUES = { off: 0, pfl: 1, afl: 2 };
|
|
585
608
|
function automationCurveCode(curve) {
|
|
586
609
|
return resolveEnumOrdinal(curve, AUTOMATION_CURVE_VALUES, "automation curve");
|
|
587
610
|
}
|
|
588
611
|
function panLawCode(panLaw) {
|
|
589
|
-
|
|
612
|
+
const normalized = typeof panLaw === "string" ? panLaw.toLowerCase().replace(/_/g, "-") : panLaw;
|
|
613
|
+
return resolveEnumOrdinal(normalized, PAN_LAW_VALUES, "pan law");
|
|
590
614
|
}
|
|
591
615
|
function panModeCode(panMode) {
|
|
592
616
|
const normalized = typeof panMode === "string" ? panMode.replace(/_/g, "-").toLowerCase() : panMode;
|
|
@@ -598,6 +622,9 @@ function meterTapCode(tap) {
|
|
|
598
622
|
function sendTimingCode(timing) {
|
|
599
623
|
return resolveEnumOrdinal(timing, SEND_TIMING_VALUES, "send timing");
|
|
600
624
|
}
|
|
625
|
+
function trackMonitorModeCode(mode) {
|
|
626
|
+
return resolveEnumOrdinal(mode, TRACK_MONITOR_MODE_VALUES, "track monitor mode");
|
|
627
|
+
}
|
|
601
628
|
|
|
602
629
|
// src/realtime_engine.ts
|
|
603
630
|
var EXPECTED_ENGINE_ABI_VERSION = 3;
|
|
@@ -661,6 +688,10 @@ var RealtimeEngine = class {
|
|
|
661
688
|
setSoloMute(laneIndex, solo, mute, renderFrame = -1) {
|
|
662
689
|
this.native.setSoloMute(laneIndex, solo, mute, renderFrame);
|
|
663
690
|
}
|
|
691
|
+
/** Queue a per-track PFL/AFL monitor tap mode change. */
|
|
692
|
+
setTrackMonitorMode(laneIndex, mode, renderFrame = -1) {
|
|
693
|
+
this.native.setTrackMonitorMode(laneIndex, trackMonitorModeCode(mode), renderFrame);
|
|
694
|
+
}
|
|
664
695
|
setMidiClips(clips) {
|
|
665
696
|
this.native.setMidiClips(clips);
|
|
666
697
|
}
|
|
@@ -1579,7 +1610,7 @@ var Mixer = class _Mixer {
|
|
|
1579
1610
|
setPolarityInvert(stripIndex, invertLeft, invertRight) {
|
|
1580
1611
|
this.mixer.setPolarityInvert(stripIndex, invertLeft, invertRight);
|
|
1581
1612
|
}
|
|
1582
|
-
/** Set the strip's pan law. */
|
|
1613
|
+
/** Set the strip's pan law (a {@link PanLawName} alias or raw C ABI ordinal). */
|
|
1583
1614
|
setPanLaw(stripIndex, panLaw) {
|
|
1584
1615
|
this.mixer.setPanLaw(stripIndex, panLawCode(panLaw));
|
|
1585
1616
|
}
|
|
@@ -2220,6 +2251,7 @@ var SonareEngineCommandType = /* @__PURE__ */ ((SonareEngineCommandType2) => {
|
|
|
2220
2251
|
SonareEngineCommandType2[SonareEngineCommandType2["SetMetronome"] = 15] = "SetMetronome";
|
|
2221
2252
|
SonareEngineCommandType2[SonareEngineCommandType2["SetMarker"] = 16] = "SetMarker";
|
|
2222
2253
|
SonareEngineCommandType2[SonareEngineCommandType2["SeekMarker"] = 17] = "SeekMarker";
|
|
2254
|
+
SonareEngineCommandType2[SonareEngineCommandType2["SetTrackMonitorMode"] = 26] = "SetTrackMonitorMode";
|
|
2223
2255
|
return SonareEngineCommandType2;
|
|
2224
2256
|
})(SonareEngineCommandType || {});
|
|
2225
2257
|
var SonareEngineTelemetryType = /* @__PURE__ */ ((SonareEngineTelemetryType2) => {
|
|
@@ -2248,6 +2280,7 @@ var SonareEngineTelemetryError = /* @__PURE__ */ ((SonareEngineTelemetryError2)
|
|
|
2248
2280
|
SonareEngineTelemetryError2[SonareEngineTelemetryError2["MidiClockOverflow"] = 17] = "MidiClockOverflow";
|
|
2249
2281
|
SonareEngineTelemetryError2[SonareEngineTelemetryError2["MetronomeOverflow"] = 18] = "MetronomeOverflow";
|
|
2250
2282
|
SonareEngineTelemetryError2[SonareEngineTelemetryError2["InvalidCommand"] = 19] = "InvalidCommand";
|
|
2283
|
+
SonareEngineTelemetryError2[SonareEngineTelemetryError2["MaxChannelsExceeded"] = 20] = "MaxChannelsExceeded";
|
|
2251
2284
|
return SonareEngineTelemetryError2;
|
|
2252
2285
|
})(SonareEngineTelemetryError || {});
|
|
2253
2286
|
function toDb(value) {
|
|
@@ -3136,8 +3169,60 @@ function isEngineSyncMessage(value) {
|
|
|
3136
3169
|
function isEngineCaptureRequestMessage(value) {
|
|
3137
3170
|
return isRecord(value) && value.type === "captureRequest" && typeof value.requestId === "number" && (value.op === "status" || value.op === "read" || value.op === "reset");
|
|
3138
3171
|
}
|
|
3172
|
+
function isCaptureStatus(value) {
|
|
3173
|
+
return isRecord(value) && typeof value.capturedFrames === "number" && Number.isSafeInteger(value.capturedFrames) && value.capturedFrames >= 0 && typeof value.overflowCount === "number" && Number.isSafeInteger(value.overflowCount) && value.overflowCount >= 0 && typeof value.armed === "boolean" && typeof value.punchEnabled === "boolean" && (value.source === "input" || value.source === "output") && typeof value.recordOffsetSamples === "number" && Number.isSafeInteger(value.recordOffsetSamples);
|
|
3174
|
+
}
|
|
3175
|
+
function isCaptureChannel(value) {
|
|
3176
|
+
return value instanceof Float32Array && typeof ArrayBuffer !== "undefined" && value.buffer instanceof ArrayBuffer;
|
|
3177
|
+
}
|
|
3178
|
+
function isCaptureChannels(value) {
|
|
3179
|
+
return Array.isArray(value) && value.every((channel) => isCaptureChannel(channel));
|
|
3180
|
+
}
|
|
3181
|
+
function hasOwn(value, key) {
|
|
3182
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
3183
|
+
}
|
|
3184
|
+
function engineCaptureResponseRequestId(value) {
|
|
3185
|
+
if (!isRecord(value) || value.type !== "captureResponse" || typeof value.requestId !== "number" || !Number.isSafeInteger(value.requestId)) {
|
|
3186
|
+
return void 0;
|
|
3187
|
+
}
|
|
3188
|
+
return value.requestId;
|
|
3189
|
+
}
|
|
3139
3190
|
function isEngineCaptureResponseMessage(value) {
|
|
3140
|
-
|
|
3191
|
+
const requestId = engineCaptureResponseRequestId(value);
|
|
3192
|
+
if (requestId === void 0 || !isRecord(value)) {
|
|
3193
|
+
return false;
|
|
3194
|
+
}
|
|
3195
|
+
if (value.ok === false) {
|
|
3196
|
+
return typeof value.error === "string" && !hasOwn(value, "status") && !hasOwn(value, "channels");
|
|
3197
|
+
}
|
|
3198
|
+
if (value.ok !== true || hasOwn(value, "error")) {
|
|
3199
|
+
return false;
|
|
3200
|
+
}
|
|
3201
|
+
const hasStatus = hasOwn(value, "status");
|
|
3202
|
+
const hasChannels = hasOwn(value, "channels");
|
|
3203
|
+
if (hasStatus && hasChannels) {
|
|
3204
|
+
return false;
|
|
3205
|
+
}
|
|
3206
|
+
if (hasStatus) {
|
|
3207
|
+
return isCaptureStatus(value.status);
|
|
3208
|
+
}
|
|
3209
|
+
if (hasChannels) {
|
|
3210
|
+
return isCaptureChannels(value.channels);
|
|
3211
|
+
}
|
|
3212
|
+
return true;
|
|
3213
|
+
}
|
|
3214
|
+
function isEngineCaptureResponseForOperation(response, op) {
|
|
3215
|
+
if (!response.ok) {
|
|
3216
|
+
return true;
|
|
3217
|
+
}
|
|
3218
|
+
switch (op) {
|
|
3219
|
+
case "status":
|
|
3220
|
+
return "status" in response;
|
|
3221
|
+
case "read":
|
|
3222
|
+
return "channels" in response;
|
|
3223
|
+
case "reset":
|
|
3224
|
+
return !("status" in response) && !("channels" in response);
|
|
3225
|
+
}
|
|
3141
3226
|
}
|
|
3142
3227
|
function isEngineTransportRequestMessage(value) {
|
|
3143
3228
|
return isRecord(value) && value.type === "transportRequest" && typeof value.requestId === "number" && value.op === "state";
|
|
@@ -3173,12 +3258,22 @@ function isFiniteInteger(value) {
|
|
|
3173
3258
|
}
|
|
3174
3259
|
return typeof value === "bigint" || Number.isFinite(value) && Number.isSafeInteger(value);
|
|
3175
3260
|
}
|
|
3261
|
+
function isTrackMonitorMode(value) {
|
|
3262
|
+
if (value === void 0) {
|
|
3263
|
+
return false;
|
|
3264
|
+
}
|
|
3265
|
+
const mode = typeof value === "bigint" ? Number(value) : value;
|
|
3266
|
+
return typeof mode === "number" && Number.isSafeInteger(mode) && mode >= 0 && mode <= 2;
|
|
3267
|
+
}
|
|
3268
|
+
function isTrackMonitorLaneIndex(value) {
|
|
3269
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= 4294967295;
|
|
3270
|
+
}
|
|
3176
3271
|
function isValidCommandRecord(command) {
|
|
3177
3272
|
const type = Number(command.type);
|
|
3178
|
-
if (!Number.isSafeInteger(type) || type < 0 /* SetParam */ || type > 17 /* SeekMarker */) {
|
|
3273
|
+
if (!Number.isSafeInteger(type) || type < 0 /* SetParam */ || type > 17 /* SeekMarker */ && type !== 26 /* SetTrackMonitorMode */) {
|
|
3179
3274
|
return false;
|
|
3180
3275
|
}
|
|
3181
|
-
return (command.targetId === void 0 || Number.isSafeInteger(command.targetId)) && (command.argFloat === void 0 || Number.isFinite(command.argFloat)) && isFiniteInteger(command.argInt) && isFiniteInteger(command.sampleTime);
|
|
3276
|
+
return (command.targetId === void 0 || Number.isSafeInteger(command.targetId)) && (command.argFloat === void 0 || Number.isFinite(command.argFloat)) && isFiniteInteger(command.argInt) && isFiniteInteger(command.sampleTime) && (type !== 26 /* SetTrackMonitorMode */ || isTrackMonitorLaneIndex(command.targetId) && isTrackMonitorMode(command.argInt));
|
|
3182
3277
|
}
|
|
3183
3278
|
var AUDIO_WORKLET_RENDER_QUANTUM = 128;
|
|
3184
3279
|
function workletBlockSize(blockSize) {
|
|
@@ -3223,14 +3318,19 @@ var SonareRealtimeEngineNode = class _SonareRealtimeEngineNode {
|
|
|
3223
3318
|
this.resolveReady();
|
|
3224
3319
|
}
|
|
3225
3320
|
this.node.port.onmessage = (event) => {
|
|
3226
|
-
|
|
3227
|
-
|
|
3321
|
+
const captureRequestId = engineCaptureResponseRequestId(event.data);
|
|
3322
|
+
if (captureRequestId !== void 0) {
|
|
3323
|
+
const pending = this.captureRequests.get(captureRequestId);
|
|
3228
3324
|
if (pending) {
|
|
3229
|
-
this.captureRequests.delete(
|
|
3230
|
-
if (event.data
|
|
3325
|
+
this.captureRequests.delete(captureRequestId);
|
|
3326
|
+
if (!isEngineCaptureResponseMessage(event.data)) {
|
|
3327
|
+
pending.reject(new Error("Malformed capture response."));
|
|
3328
|
+
} else if (!isEngineCaptureResponseForOperation(event.data, pending.op)) {
|
|
3329
|
+
pending.reject(new Error("Capture response does not match request operation."));
|
|
3330
|
+
} else if (event.data.ok) {
|
|
3231
3331
|
pending.resolve(event.data);
|
|
3232
3332
|
} else {
|
|
3233
|
-
pending.reject(new Error(event.data.error
|
|
3333
|
+
pending.reject(new Error(event.data.error));
|
|
3234
3334
|
}
|
|
3235
3335
|
}
|
|
3236
3336
|
} else if (isEngineTransportResponseMessage(event.data)) {
|
|
@@ -3398,18 +3498,19 @@ var SonareRealtimeEngineNode = class _SonareRealtimeEngineNode {
|
|
|
3398
3498
|
}
|
|
3399
3499
|
requestCaptureStatus() {
|
|
3400
3500
|
return this.sendCaptureRequest("status").then((response) => {
|
|
3401
|
-
if (!response.status) {
|
|
3501
|
+
if (!response.ok || !("status" in response)) {
|
|
3402
3502
|
throw new Error("Capture status response is missing status.");
|
|
3403
3503
|
}
|
|
3404
3504
|
return response.status;
|
|
3405
3505
|
});
|
|
3406
3506
|
}
|
|
3407
3507
|
requestCapturedAudio() {
|
|
3408
|
-
return this.sendCaptureRequest("read").then(
|
|
3409
|
-
(response
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3508
|
+
return this.sendCaptureRequest("read").then((response) => {
|
|
3509
|
+
if (!response.ok || !("channels" in response)) {
|
|
3510
|
+
throw new Error("Capture read response is missing channels.");
|
|
3511
|
+
}
|
|
3512
|
+
return response.channels;
|
|
3513
|
+
});
|
|
3413
3514
|
}
|
|
3414
3515
|
requestCaptureReset() {
|
|
3415
3516
|
return this.sendCaptureRequest("reset").then(() => void 0);
|
|
@@ -3540,6 +3641,7 @@ var SonareRealtimeEngineNode = class _SonareRealtimeEngineNode {
|
|
|
3540
3641
|
this.startRingPolling();
|
|
3541
3642
|
return () => {
|
|
3542
3643
|
this.midiOutListeners.delete(callback);
|
|
3644
|
+
this.stopRingPollingIfUnused();
|
|
3543
3645
|
};
|
|
3544
3646
|
}
|
|
3545
3647
|
/**
|
|
@@ -3628,10 +3730,17 @@ var SonareRealtimeEngineNode = class _SonareRealtimeEngineNode {
|
|
|
3628
3730
|
return Promise.reject(new Error("Realtime engine node is destroyed."));
|
|
3629
3731
|
}
|
|
3630
3732
|
const requestId = this.captureRequestId++;
|
|
3733
|
+
let rejectRequest;
|
|
3631
3734
|
const promise = new Promise((resolve, reject) => {
|
|
3632
|
-
|
|
3735
|
+
rejectRequest = reject;
|
|
3736
|
+
this.captureRequests.set(requestId, { op, resolve, reject });
|
|
3633
3737
|
});
|
|
3634
|
-
|
|
3738
|
+
try {
|
|
3739
|
+
this.node.port.postMessage({ type: "captureRequest", requestId, op });
|
|
3740
|
+
} catch (error) {
|
|
3741
|
+
this.captureRequests.delete(requestId);
|
|
3742
|
+
rejectRequest(error);
|
|
3743
|
+
}
|
|
3635
3744
|
return promise;
|
|
3636
3745
|
}
|
|
3637
3746
|
sendTransportRequest() {
|
|
@@ -3668,6 +3777,21 @@ function setSoloMute(ctx, target, solo, mute) {
|
|
|
3668
3777
|
argInt: (mute ? 1 : 0) | (solo ? 2 : 0)
|
|
3669
3778
|
});
|
|
3670
3779
|
}
|
|
3780
|
+
function setTrackMonitorMode(ctx, target, mode, renderFrame = -1) {
|
|
3781
|
+
const modeOrdinal = trackMonitorModeCode(mode);
|
|
3782
|
+
const laneIndex = ctx.ensureTrackLane(target);
|
|
3783
|
+
ctx.offlineEngine.setTrackMonitorMode(
|
|
3784
|
+
laneIndex,
|
|
3785
|
+
modeOrdinal,
|
|
3786
|
+
renderFrame
|
|
3787
|
+
);
|
|
3788
|
+
return ctx.sendCommand({
|
|
3789
|
+
type: 26 /* SetTrackMonitorMode */,
|
|
3790
|
+
targetId: laneIndex,
|
|
3791
|
+
sampleTime: renderFrame,
|
|
3792
|
+
argInt: modeOrdinal
|
|
3793
|
+
});
|
|
3794
|
+
}
|
|
3671
3795
|
function automationParamId(ctx, target, kind) {
|
|
3672
3796
|
const paramKind = kind === "pan" ? ENGINE_MIXER_PARAM_PAN : ENGINE_MIXER_PARAM_FADER_DB;
|
|
3673
3797
|
if (target === "master") {
|
|
@@ -4181,6 +4305,10 @@ var SonareEngine = class _SonareEngine {
|
|
|
4181
4305
|
setSoloMute(target, solo, mute) {
|
|
4182
4306
|
return setSoloMute(this.parameterContext, target, solo, mute);
|
|
4183
4307
|
}
|
|
4308
|
+
/** Queues a per-track PFL/AFL monitor tap mode change. */
|
|
4309
|
+
setTrackMonitorMode(target, mode, renderFrame = -1) {
|
|
4310
|
+
return setTrackMonitorMode(this.parameterContext, target, mode, renderFrame);
|
|
4311
|
+
}
|
|
4184
4312
|
setStripGain(target, db) {
|
|
4185
4313
|
return this.sendSmoothedParam(this.stripParamId(target, ENGINE_MIXER_PARAM_FADER_DB), db);
|
|
4186
4314
|
}
|
|
@@ -4965,6 +5093,21 @@ function resolveMetronomeConfig(config) {
|
|
|
4965
5093
|
}
|
|
4966
5094
|
|
|
4967
5095
|
// src/worklet/engine-processor.ts
|
|
5096
|
+
function captureTransferList(channels) {
|
|
5097
|
+
const transfers = [];
|
|
5098
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5099
|
+
for (const channel of channels) {
|
|
5100
|
+
const buffer = channel.buffer;
|
|
5101
|
+
if (!(buffer instanceof ArrayBuffer)) {
|
|
5102
|
+
throw new TypeError("capture response channels must use plain ArrayBuffers");
|
|
5103
|
+
}
|
|
5104
|
+
if (!seen.has(buffer)) {
|
|
5105
|
+
seen.add(buffer);
|
|
5106
|
+
transfers.push(buffer);
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
return transfers;
|
|
5110
|
+
}
|
|
4968
5111
|
var _SonareRealtimeEngineWorkletProcessor = class _SonareRealtimeEngineWorkletProcessor {
|
|
4969
5112
|
constructor(options = {}, transport) {
|
|
4970
5113
|
this.closed = false;
|
|
@@ -5445,22 +5588,17 @@ var _SonareRealtimeEngineWorkletProcessor = class _SonareRealtimeEngineWorkletPr
|
|
|
5445
5588
|
return;
|
|
5446
5589
|
}
|
|
5447
5590
|
if (message.op === "read") {
|
|
5448
|
-
const
|
|
5449
|
-
const
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
type: "captureResponse",
|
|
5460
|
-
requestId: message.requestId,
|
|
5461
|
-
ok: true,
|
|
5462
|
-
channels
|
|
5463
|
-
});
|
|
5591
|
+
const channels = Array.from(this.engine.capturedAudio());
|
|
5592
|
+
const transfer = captureTransferList(channels);
|
|
5593
|
+
this.transport?.postMessage?.(
|
|
5594
|
+
{
|
|
5595
|
+
type: "captureResponse",
|
|
5596
|
+
requestId: message.requestId,
|
|
5597
|
+
ok: true,
|
|
5598
|
+
channels
|
|
5599
|
+
},
|
|
5600
|
+
transfer
|
|
5601
|
+
);
|
|
5464
5602
|
return;
|
|
5465
5603
|
}
|
|
5466
5604
|
this.engine.resetCapture();
|
|
@@ -5598,6 +5736,19 @@ var _SonareRealtimeEngineWorkletProcessor = class _SonareRealtimeEngineWorkletPr
|
|
|
5598
5736
|
sampleTime
|
|
5599
5737
|
);
|
|
5600
5738
|
break;
|
|
5739
|
+
case 26 /* SetTrackMonitorMode */: {
|
|
5740
|
+
const rawMode = command.argInt;
|
|
5741
|
+
const mode = typeof rawMode === "bigint" ? Number(rawMode) : rawMode;
|
|
5742
|
+
if (typeof mode !== "number" || !Number.isSafeInteger(mode) || mode < 0 || mode > 2) {
|
|
5743
|
+
throw new RangeError(`Invalid track monitor mode: ${String(rawMode)}`);
|
|
5744
|
+
}
|
|
5745
|
+
const laneIndex = command.targetId;
|
|
5746
|
+
if (typeof laneIndex !== "number" || !Number.isSafeInteger(laneIndex) || laneIndex < 0 || laneIndex > 4294967295) {
|
|
5747
|
+
throw new RangeError(`Invalid track monitor lane index: ${String(laneIndex)}`);
|
|
5748
|
+
}
|
|
5749
|
+
this.engine.setTrackMonitorMode(laneIndex, mode, sampleTime);
|
|
5750
|
+
break;
|
|
5751
|
+
}
|
|
5601
5752
|
default:
|
|
5602
5753
|
this.publishTelemetryRecord({
|
|
5603
5754
|
type: 1 /* Error */,
|
|
@@ -5995,7 +6146,7 @@ function registerSonareRealtimeEngineWorkletProcessor(name = "sonare-realtime-en
|
|
|
5995
6146
|
throw new Error("AudioWorklet initialization message buffer overflowed.");
|
|
5996
6147
|
}
|
|
5997
6148
|
this.bridge = new SonareRealtimeEngineWorkletProcessor(options, {
|
|
5998
|
-
postMessage: (message) => port?.postMessage?.(message),
|
|
6149
|
+
postMessage: (message, transfer) => port?.postMessage?.(message, transfer),
|
|
5999
6150
|
onMeter: (meter) => port?.postMessage?.(meter)
|
|
6000
6151
|
});
|
|
6001
6152
|
for (const message of options.initialSyncMessages ?? []) {
|