@libraz/libsonare 1.7.2 → 1.8.1
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/NOTICE +178 -0
- package/README.md +26 -203
- package/dist/_chain_config.d.ts +14 -0
- package/dist/_chain_config.d.ts.map +1 -0
- package/dist/_effects_common.d.ts +7 -0
- package/dist/_effects_common.d.ts.map +1 -0
- package/dist/_feature_validation.d.ts +8 -0
- package/dist/_feature_validation.d.ts.map +1 -0
- package/dist/_fft_options.d.ts +24 -0
- package/dist/_fft_options.d.ts.map +1 -0
- package/dist/align_take.d.ts +50 -0
- package/dist/align_take.d.ts.map +1 -0
- package/dist/analysis.d.ts +29 -5840
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +874 -722
- package/dist/analysis.js.map +1 -1
- package/dist/analysis_helpers.d.ts +9 -0
- package/dist/analysis_helpers.d.ts.map +1 -0
- package/dist/audio.d.ts +163 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/clip_page_streamer.d.ts +133 -0
- package/dist/clip_page_streamer.d.ts.map +1 -0
- package/dist/codes.d.ts +44 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/effects_mastering.d.ts +23 -0
- package/dist/effects_mastering.d.ts.map +1 -0
- package/dist/effects_note_ops.d.ts +502 -0
- package/dist/effects_note_ops.d.ts.map +1 -0
- package/dist/effects_percussive.d.ts +185 -0
- package/dist/effects_percussive.d.ts.map +1 -0
- package/dist/effects_separation.d.ts +65 -0
- package/dist/effects_separation.d.ts.map +1 -0
- package/dist/effects_spectral.d.ts +28 -0
- package/dist/effects_spectral.d.ts.map +1 -0
- package/dist/effects_timepitch.d.ts +134 -0
- package/dist/effects_timepitch.d.ts.map +1 -0
- package/dist/effects_voice_change.d.ts +53 -0
- package/dist/effects_voice_change.d.ts.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/feature_core.d.ts +341 -0
- package/dist/feature_core.d.ts.map +1 -0
- package/dist/feature_decompose.d.ts +278 -0
- package/dist/feature_decompose.d.ts.map +1 -0
- package/dist/feature_inverse.d.ts +128 -0
- package/dist/feature_inverse.d.ts.map +1 -0
- package/dist/feature_loudness.d.ts +66 -0
- package/dist/feature_loudness.d.ts.map +1 -0
- package/dist/feature_music.d.ts +307 -0
- package/dist/feature_music.d.ts.map +1 -0
- package/dist/feature_pitch.d.ts +108 -0
- package/dist/feature_pitch.d.ts.map +1 -0
- package/dist/feature_resample.d.ts +16 -0
- package/dist/feature_resample.d.ts.map +1 -0
- package/dist/feature_spectral.d.ts +137 -0
- package/dist/feature_spectral.d.ts.map +1 -0
- package/dist/feature_spectrogram.d.ts +198 -0
- package/dist/feature_spectrogram.d.ts.map +1 -0
- package/dist/features.d.ts +10 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/hrtf/default.shrf +0 -0
- package/dist/index.d.ts +74 -7431
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4173 -1621
- package/dist/index.js.map +1 -1
- package/dist/instrument_types.d.ts +517 -0
- package/dist/instrument_types.d.ts.map +1 -0
- package/dist/live_audio.d.ts +35 -0
- package/dist/live_audio.d.ts.map +1 -0
- package/dist/mastering_chain.d.ts +213 -0
- package/dist/mastering_chain.d.ts.map +1 -0
- package/dist/mastering_core.d.ts +483 -0
- package/dist/mastering_core.d.ts.map +1 -0
- package/dist/mastering_dynamics.d.ts +80 -0
- package/dist/mastering_dynamics.d.ts.map +1 -0
- package/dist/metering.d.ts +287 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/mixer.d.ts +464 -0
- package/dist/mixer.d.ts.map +1 -0
- package/dist/mixing_assistant.d.ts +62 -0
- package/dist/mixing_assistant.d.ts.map +1 -0
- package/dist/mixing_oneshot.d.ts +40 -0
- package/dist/mixing_oneshot.d.ts.map +1 -0
- package/dist/module_state.d.ts +15 -0
- package/dist/module_state.d.ts.map +1 -0
- package/dist/opfs_clip_pages.d.ts +28 -0
- package/dist/opfs_clip_pages.d.ts.map +1 -0
- package/dist/playback_renderer.d.ts +128 -0
- package/dist/playback_renderer.d.ts.map +1 -0
- package/dist/polyphony.d.ts +202 -0
- package/dist/polyphony.d.ts.map +1 -0
- package/dist/project.d.ts +8 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project_class.d.ts +562 -0
- package/dist/project_class.d.ts.map +1 -0
- package/dist/project_internal.d.ts +194 -0
- package/dist/project_internal.d.ts.map +1 -0
- package/dist/project_synth.d.ts +74 -0
- package/dist/project_synth.d.ts.map +1 -0
- package/dist/project_types.d.ts +654 -0
- package/dist/project_types.d.ts.map +1 -0
- package/dist/public_types.d.ts +185 -0
- package/dist/public_types.d.ts.map +1 -0
- package/dist/public_types_acoustic.d.ts +215 -0
- package/dist/public_types_acoustic.d.ts.map +1 -0
- package/dist/public_types_mastering.d.ts +528 -0
- package/dist/public_types_mastering.d.ts.map +1 -0
- package/dist/public_types_mixing.d.ts +436 -0
- package/dist/public_types_mixing.d.ts.map +1 -0
- package/dist/public_types_music.d.ts +619 -0
- package/dist/public_types_music.d.ts.map +1 -0
- package/dist/public_types_playback.d.ts +165 -0
- package/dist/public_types_playback.d.ts.map +1 -0
- package/dist/public_types_realtime.d.ts +174 -0
- package/dist/public_types_realtime.d.ts.map +1 -0
- package/dist/public_types_repair.d.ts +424 -0
- package/dist/public_types_repair.d.ts.map +1 -0
- package/dist/public_types_spectral.d.ts +697 -0
- package/dist/public_types_spectral.d.ts.map +1 -0
- package/dist/quick_analysis.d.ts +445 -0
- package/dist/quick_analysis.d.ts.map +1 -0
- package/dist/realtime_engine.d.ts +893 -0
- package/dist/realtime_engine.d.ts.map +1 -0
- package/dist/realtime_voice_changer.d.ts +158 -0
- package/dist/realtime_voice_changer.d.ts.map +1 -0
- package/dist/repair_dereverb.d.ts +187 -0
- package/dist/repair_dereverb.d.ts.map +1 -0
- package/dist/repair_impulsive.d.ts +186 -0
- package/dist/repair_impulsive.d.ts.map +1 -0
- package/dist/repair_noise.d.ts +239 -0
- package/dist/repair_noise.d.ts.map +1 -0
- package/dist/repair_trim.d.ts +123 -0
- package/dist/repair_trim.d.ts.map +1 -0
- package/dist/sample_bank.d.ts +84 -0
- package/dist/sample_bank.d.ts.map +1 -0
- package/dist/scale.d.ts +10 -0
- package/dist/scale.d.ts.map +1 -0
- package/dist/schemas/mixer-scene.schema.json +393 -0
- package/dist/schemas/playback-renderer-config.schema.json +392 -0
- package/dist/sonare-analysis.d.ts +8 -0
- package/dist/sonare-analysis.js +2 -2
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.d.ts +3945 -0
- package/dist/sonare.js +2 -2
- package/dist/sonare.wasm +0 -0
- package/dist/stream_analyzer.d.ts +163 -0
- package/dist/stream_analyzer.d.ts.map +1 -0
- package/dist/stream_types.d.ts +214 -0
- package/dist/stream_types.d.ts.map +1 -0
- package/dist/streaming_mixing.d.ts +6 -0
- package/dist/streaming_mixing.d.ts.map +1 -0
- package/dist/streaming_processors.d.ts +340 -0
- package/dist/streaming_processors.d.ts.map +1 -0
- package/dist/transcribe.d.ts +77 -0
- package/dist/transcribe.d.ts.map +1 -0
- package/dist/validation.d.ts +140 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/web_midi.d.ts +77 -0
- package/dist/web_midi.d.ts.map +1 -0
- package/dist/worker.d.ts +5 -48
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +94 -41
- package/dist/worker.js.map +1 -1
- package/dist/worker_client.d.ts +96 -0
- package/dist/worker_client.d.ts.map +1 -0
- package/dist/worker_protocol.d.ts +43 -0
- package/dist/worker_protocol.d.ts.map +1 -0
- package/dist/worklet/audio_types.d.ts +21 -0
- package/dist/worklet/audio_types.d.ts.map +1 -0
- package/dist/worklet/engine-automation.d.ts +29 -0
- package/dist/worklet/engine-automation.d.ts.map +1 -0
- package/dist/worklet/engine-capture-facade.d.ts +35 -0
- package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
- package/dist/worklet/engine-clips.d.ts +23 -0
- package/dist/worklet/engine-clips.d.ts.map +1 -0
- package/dist/worklet/engine-markers.d.ts +40 -0
- package/dist/worklet/engine-markers.d.ts.map +1 -0
- package/dist/worklet/engine-mixer-facade.d.ts +164 -0
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
- package/dist/worklet/engine-node.d.ts +83 -0
- package/dist/worklet/engine-node.d.ts.map +1 -0
- package/dist/worklet/engine-offline.d.ts +81 -0
- package/dist/worklet/engine-offline.d.ts.map +1 -0
- package/dist/worklet/engine-options.d.ts +12 -0
- package/dist/worklet/engine-options.d.ts.map +1 -0
- package/dist/worklet/engine-parameter-facade.d.ts +106 -0
- package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
- package/dist/worklet/engine-processor.d.ts +72 -0
- package/dist/worklet/engine-processor.d.ts.map +1 -0
- package/dist/worklet/engine-register.d.ts +2 -0
- package/dist/worklet/engine-register.d.ts.map +1 -0
- package/dist/worklet/engine-strips.d.ts +75 -0
- package/dist/worklet/engine-strips.d.ts.map +1 -0
- package/dist/worklet/engine-sync.d.ts +39 -0
- package/dist/worklet/engine-sync.d.ts.map +1 -0
- package/dist/worklet/engine-tempo-facade.d.ts +48 -0
- package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
- package/dist/worklet/engine.d.ts +418 -0
- package/dist/worklet/engine.d.ts.map +1 -0
- package/dist/worklet/guards.d.ts +53 -0
- package/dist/worklet/guards.d.ts.map +1 -0
- package/dist/worklet/messages.d.ts +710 -0
- package/dist/worklet/messages.d.ts.map +1 -0
- package/dist/worklet/mixer-processor.d.ts +46 -0
- package/dist/worklet/mixer-processor.d.ts.map +1 -0
- package/dist/worklet/playback-processor.d.ts +62 -0
- package/dist/worklet/playback-processor.d.ts.map +1 -0
- package/dist/worklet/protocol.d.ts +331 -0
- package/dist/worklet/protocol.d.ts.map +1 -0
- package/dist/worklet/voice-changer-processor.d.ts +41 -0
- package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
- package/dist/worklet.d.ts +16 -2515
- package/dist/worklet.d.ts.map +1 -0
- package/dist/worklet.js +3200 -541
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -12
- package/src/_effects_common.ts +47 -0
- package/src/_feature_validation.ts +34 -0
- package/src/_fft_options.ts +39 -0
- package/src/align_take.ts +64 -0
- package/src/analysis.ts +56 -3
- package/src/analysis_helpers.ts +7 -0
- package/src/audio.ts +106 -3
- package/src/codes.ts +39 -2
- package/src/effects_mastering.ts +101 -22
- package/src/effects_note_ops.ts +683 -0
- package/src/effects_percussive.ts +217 -0
- package/src/effects_separation.ts +150 -0
- package/src/effects_spectral.ts +60 -0
- package/src/effects_timepitch.ts +388 -0
- package/src/errors.ts +23 -1
- package/src/feature_core.ts +127 -2
- package/src/feature_decompose.ts +633 -0
- package/src/feature_inverse.ts +454 -0
- package/src/feature_loudness.ts +125 -0
- package/src/feature_music.ts +107 -14
- package/src/feature_pitch.ts +96 -1
- package/src/feature_spectral.ts +16 -611
- package/src/feature_spectrogram.ts +63 -450
- package/src/features.ts +36 -22
- package/src/index.ts +288 -30
- package/src/instrument_types.ts +645 -0
- package/src/live_audio.ts +27 -1
- package/src/mastering_chain.ts +184 -0
- package/src/mastering_core.ts +441 -32
- package/src/mastering_dynamics.ts +22 -11
- package/src/metering.ts +67 -24
- package/src/mixer.ts +251 -22
- package/src/mixing_assistant.ts +138 -0
- package/src/mixing_oneshot.ts +10 -5
- package/src/module_state.ts +24 -2
- package/src/playback_renderer.ts +252 -0
- package/src/polyphony.ts +279 -0
- package/src/project.ts +61 -24
- package/src/project_class.ts +450 -27
- package/src/project_internal.ts +149 -42
- package/src/project_synth.ts +67 -1
- package/src/project_types.ts +271 -271
- package/src/public_types.ts +122 -3
- package/src/public_types_acoustic.ts +112 -3
- package/src/public_types_mastering.ts +275 -73
- package/src/public_types_mixing.ts +363 -1
- package/src/public_types_music.ts +312 -2
- package/src/public_types_playback.ts +196 -0
- package/src/public_types_realtime.ts +39 -7
- package/src/public_types_repair.ts +446 -0
- package/src/public_types_spectral.ts +491 -5
- package/src/quick_analysis.ts +203 -26
- package/src/realtime_engine.ts +773 -34
- package/src/realtime_voice_changer.ts +55 -1
- package/src/repair_dereverb.ts +299 -0
- package/src/repair_impulsive.ts +395 -0
- package/src/repair_noise.ts +425 -0
- package/src/repair_trim.ts +226 -0
- package/src/sample_bank.ts +113 -0
- package/src/sonare.js.d.ts +1158 -30
- package/src/stream_analyzer.ts +36 -4
- package/src/stream_types.ts +37 -0
- package/src/streaming_mixing.ts +1 -1
- package/src/streaming_processors.ts +202 -10
- package/src/transcribe.ts +89 -0
- package/src/validation.ts +285 -11
- package/src/web_midi.ts +1 -6
- package/src/worker.ts +18 -2
- package/src/worklet/audio_types.ts +37 -0
- package/src/worklet/engine-mixer-facade.ts +800 -32
- package/src/worklet/engine-node.ts +99 -29
- package/src/worklet/engine-offline.ts +14 -8
- package/src/worklet/engine-parameter-facade.ts +21 -0
- package/src/worklet/engine-processor.ts +332 -93
- package/src/worklet/engine-register.ts +32 -18
- package/src/worklet/engine-strips.ts +275 -9
- package/src/worklet/engine-sync.ts +20 -7
- package/src/worklet/engine.ts +394 -48
- package/src/worklet/guards.ts +195 -44
- package/src/worklet/messages.ts +229 -2
- package/src/worklet/mixer-processor.ts +117 -48
- package/src/worklet/playback-processor.ts +300 -0
- package/src/worklet/protocol.ts +82 -11
- package/src/worklet/voice-changer-processor.ts +17 -11
- package/src/worklet.ts +17 -0
- package/src/effects_transform.ts +0 -718
- package/src/mastering_repair.ts +0 -273
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
isEngineTransportResponseMessage,
|
|
10
10
|
isExternalMidiBatchMessage,
|
|
11
11
|
isMeterSnapshot,
|
|
12
|
+
isScopeSnapshot,
|
|
13
|
+
requireChannelCount,
|
|
14
|
+
requireIntegerOption,
|
|
15
|
+
resolveScopeBandCount,
|
|
12
16
|
} from './guards';
|
|
13
17
|
import type {
|
|
14
18
|
SonareEngineCaptureRequestMessage,
|
|
@@ -29,6 +33,7 @@ import {
|
|
|
29
33
|
createSonareMeterRingBuffer,
|
|
30
34
|
createSonareScopeRingBuffer,
|
|
31
35
|
isRecord,
|
|
36
|
+
isUint32Slot,
|
|
32
37
|
pushSonareEngineCommandRingBuffer,
|
|
33
38
|
readSonareClipPageRequestRingBuffer,
|
|
34
39
|
readSonareEngineTelemetryRingBuffer,
|
|
@@ -63,30 +68,27 @@ function isTrackMonitorMode(value: number | bigint | undefined): boolean {
|
|
|
63
68
|
return typeof mode === 'number' && Number.isSafeInteger(mode) && mode >= 0 && mode <= 2;
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
/** A track-monitor command cannot infer a lane: its target is a uint32 index. */
|
|
67
|
-
function isTrackMonitorLaneIndex(value: number | undefined): boolean {
|
|
68
|
-
return (
|
|
69
|
-
typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 && value <= 0xffff_ffff
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
71
|
function isValidCommandRecord(command: SonareEngineCommandRecord): boolean {
|
|
74
72
|
const type = Number(command.type);
|
|
75
73
|
if (
|
|
76
74
|
!Number.isSafeInteger(type) ||
|
|
77
75
|
type < SonareEngineCommandType.SetParam ||
|
|
78
76
|
(type > SonareEngineCommandType.SeekMarker &&
|
|
79
|
-
type !== SonareEngineCommandType.SetTrackMonitorMode
|
|
77
|
+
type !== SonareEngineCommandType.SetTrackMonitorMode &&
|
|
78
|
+
type !== SonareEngineCommandType.ResetMasterLoudnessMeter)
|
|
80
79
|
) {
|
|
81
80
|
return false;
|
|
82
81
|
}
|
|
83
82
|
return (
|
|
84
|
-
|
|
83
|
+
// The record writer refuses a targetId outside the slot by throwing, and
|
|
84
|
+
// this path answers false instead, so it must reject the same domain here.
|
|
85
|
+
(command.targetId === undefined || isUint32Slot(command.targetId)) &&
|
|
85
86
|
(command.argFloat === undefined || Number.isFinite(command.argFloat)) &&
|
|
86
87
|
isFiniteInteger(command.argInt) &&
|
|
87
88
|
isFiniteInteger(command.sampleTime) &&
|
|
89
|
+
// A track-monitor command cannot infer a lane: its target is required.
|
|
88
90
|
(type !== SonareEngineCommandType.SetTrackMonitorMode ||
|
|
89
|
-
(
|
|
91
|
+
(isUint32Slot(command.targetId) && isTrackMonitorMode(command.argInt)))
|
|
90
92
|
);
|
|
91
93
|
}
|
|
92
94
|
|
|
@@ -172,6 +174,12 @@ export class SonareRealtimeEngineNode {
|
|
|
172
174
|
this.resolveReady();
|
|
173
175
|
}
|
|
174
176
|
this.node.port.onmessage = (event: MessageEvent<unknown>) => {
|
|
177
|
+
// A host that kept its own reference to this handler (or a port
|
|
178
|
+
// implementation that ignores the detach in destroy()) must not be able
|
|
179
|
+
// to reach listeners of a node the host already disposed.
|
|
180
|
+
if (this.destroyed) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
175
183
|
const captureRequestId = engineCaptureResponseRequestId(event.data);
|
|
176
184
|
if (captureRequestId !== undefined) {
|
|
177
185
|
const pending = this.captureRequests.get(captureRequestId);
|
|
@@ -201,6 +209,8 @@ export class SonareRealtimeEngineNode {
|
|
|
201
209
|
this.emitTelemetry(event.data);
|
|
202
210
|
} else if (isMeterSnapshot(event.data)) {
|
|
203
211
|
this.emitMeter(event.data);
|
|
212
|
+
} else if (isScopeSnapshot(event.data)) {
|
|
213
|
+
this.emitScope(event.data);
|
|
204
214
|
} else if (isExternalMidiBatchMessage(event.data)) {
|
|
205
215
|
this.emitMidiOut(event.data.events);
|
|
206
216
|
} else if (isClipPageRequestMessage(event.data)) {
|
|
@@ -208,7 +218,7 @@ export class SonareRealtimeEngineNode {
|
|
|
208
218
|
} else if (isRecord(event.data) && event.data.type === 'syncError') {
|
|
209
219
|
const syncError: SonareEngineSyncErrorMessage = {
|
|
210
220
|
type: 'syncError',
|
|
211
|
-
syncType: String(event.data.syncType)
|
|
221
|
+
syncType: String(event.data.syncType),
|
|
212
222
|
message: String(event.data.message ?? 'AudioWorklet sync failed'),
|
|
213
223
|
};
|
|
214
224
|
for (const listener of this.syncErrorListeners) {
|
|
@@ -268,44 +278,93 @@ export class SonareRealtimeEngineNode {
|
|
|
268
278
|
);
|
|
269
279
|
}
|
|
270
280
|
|
|
281
|
+
const meterIntervalFrames = requireIntegerOption(
|
|
282
|
+
options.meterIntervalFrames,
|
|
283
|
+
2048,
|
|
284
|
+
'meterIntervalFrames',
|
|
285
|
+
0,
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// Resolved before the transport branch, so a capacity the ring could not
|
|
289
|
+
// hold is refused by name whichever transport the caller ends up with.
|
|
290
|
+
const commandRingCapacity = requireIntegerOption(
|
|
291
|
+
options.commandRingCapacity,
|
|
292
|
+
128,
|
|
293
|
+
'commandRingCapacity',
|
|
294
|
+
1,
|
|
295
|
+
);
|
|
296
|
+
if (commandRingCapacity > 65536) {
|
|
297
|
+
throw new RangeError('commandRingCapacity must be at most 65536');
|
|
298
|
+
}
|
|
299
|
+
const telemetryRingCapacity = requireIntegerOption(
|
|
300
|
+
options.telemetryRingCapacity,
|
|
301
|
+
128,
|
|
302
|
+
'telemetryRingCapacity',
|
|
303
|
+
1,
|
|
304
|
+
);
|
|
305
|
+
const meterRingCapacity = requireIntegerOption(
|
|
306
|
+
options.meterRingCapacity,
|
|
307
|
+
128,
|
|
308
|
+
'meterRingCapacity',
|
|
309
|
+
1,
|
|
310
|
+
);
|
|
311
|
+
const scopeRingCapacity = requireIntegerOption(
|
|
312
|
+
options.scopeRingCapacity,
|
|
313
|
+
64,
|
|
314
|
+
'scopeRingCapacity',
|
|
315
|
+
1,
|
|
316
|
+
);
|
|
317
|
+
const scopeBands = resolveScopeBandCount(options.scopeBands);
|
|
318
|
+
const clipPageRequestRingCapacity = requireIntegerOption(
|
|
319
|
+
options.clipPageRequestRingCapacity,
|
|
320
|
+
128,
|
|
321
|
+
'clipPageRequestRingCapacity',
|
|
322
|
+
1,
|
|
323
|
+
);
|
|
324
|
+
const externalMidiRingCapacity = requireIntegerOption(
|
|
325
|
+
options.externalMidiRingCapacity,
|
|
326
|
+
256,
|
|
327
|
+
'externalMidiRingCapacity',
|
|
328
|
+
1,
|
|
329
|
+
);
|
|
271
330
|
const commandRing =
|
|
272
|
-
mode === 'sab'
|
|
273
|
-
? createSonareEngineCommandRingBuffer(options.commandRingCapacity ?? 128)
|
|
274
|
-
: undefined;
|
|
331
|
+
mode === 'sab' ? createSonareEngineCommandRingBuffer(commandRingCapacity) : undefined;
|
|
275
332
|
const telemetryRing =
|
|
276
|
-
mode === 'sab'
|
|
277
|
-
? createSonareEngineTelemetryRingBuffer(options.telemetryRingCapacity ?? 128)
|
|
278
|
-
: undefined;
|
|
333
|
+
mode === 'sab' ? createSonareEngineTelemetryRingBuffer(telemetryRingCapacity) : undefined;
|
|
279
334
|
// Meter ring: the engine publishes meters into a SAB ring. Lock-free meter
|
|
280
335
|
// delivery matches the telemetry path and keeps the audio render callback
|
|
281
336
|
// allocation-free in SAB mode.
|
|
282
|
-
const meterRing =
|
|
283
|
-
mode === 'sab' ? createSonareMeterRingBuffer(options.meterRingCapacity ?? 128) : undefined;
|
|
337
|
+
const meterRing = mode === 'sab' ? createSonareMeterRingBuffer(meterRingCapacity) : undefined;
|
|
284
338
|
// Scope ring (FFT spectrum + goniometer): opt-in. The per-block FFT is
|
|
285
339
|
// heavier than the meter path, so it is created only when the caller
|
|
286
|
-
// requests scope telemetry via scopeIntervalFrames > 0.
|
|
287
|
-
|
|
340
|
+
// requests scope telemetry via scopeIntervalFrames > 0. Zero is the off
|
|
341
|
+
// switch, so the interval's floor is 0 rather than the capacities' 1.
|
|
342
|
+
const scopeIntervalFrames = requireIntegerOption(
|
|
343
|
+
options.scopeIntervalFrames,
|
|
344
|
+
0,
|
|
345
|
+
'scopeIntervalFrames',
|
|
346
|
+
0,
|
|
347
|
+
);
|
|
288
348
|
const scopeRing =
|
|
289
349
|
mode === 'sab' && scopeIntervalFrames > 0
|
|
290
|
-
? createSonareScopeRingBuffer(
|
|
350
|
+
? createSonareScopeRingBuffer(scopeRingCapacity, scopeBands)
|
|
291
351
|
: undefined;
|
|
292
352
|
// Paged-clip cache misses are a worklet-to-main-thread control signal. A
|
|
293
353
|
// dedicated SPSC SAB ring keeps process() free of both embind request
|
|
294
354
|
// objects and postMessage structured cloning.
|
|
295
355
|
const clipPageRequestRing =
|
|
296
356
|
mode === 'sab'
|
|
297
|
-
? createSonareClipPageRequestRingBuffer(
|
|
357
|
+
? createSonareClipPageRequestRingBuffer(clipPageRequestRingCapacity)
|
|
298
358
|
: undefined;
|
|
299
359
|
const externalMidiRing =
|
|
300
|
-
mode === 'sab'
|
|
301
|
-
|
|
302
|
-
: undefined;
|
|
303
|
-
const channelCount = Math.max(1, Math.floor(options.channelCount ?? 2));
|
|
360
|
+
mode === 'sab' ? createSonareExternalMidiRingBuffer(externalMidiRingCapacity) : undefined;
|
|
361
|
+
const channelCount = requireChannelCount(options.channelCount, 2);
|
|
304
362
|
const cueOutput = options.cueOutput === true;
|
|
305
363
|
const processorOptions: SonareRealtimeEngineWorkletProcessorOptions = {
|
|
306
364
|
sampleRate: options.sampleRate ?? context.sampleRate,
|
|
307
365
|
blockSize,
|
|
308
366
|
channelCount,
|
|
367
|
+
meterIntervalFrames,
|
|
309
368
|
cueOutput,
|
|
310
369
|
commandSharedBuffer: commandRing?.sharedBuffer,
|
|
311
370
|
commandRingCapacity: commandRing?.capacity,
|
|
@@ -315,8 +374,8 @@ export class SonareRealtimeEngineNode {
|
|
|
315
374
|
meterRingCapacity: meterRing?.capacity,
|
|
316
375
|
scopeSharedBuffer: scopeRing?.sharedBuffer,
|
|
317
376
|
scopeRingCapacity: scopeRing?.capacity,
|
|
318
|
-
scopeBands: scopeRing?.bands,
|
|
319
|
-
scopeIntervalFrames:
|
|
377
|
+
scopeBands: scopeIntervalFrames > 0 ? (scopeRing?.bands ?? scopeBands) : undefined,
|
|
378
|
+
scopeIntervalFrames: scopeIntervalFrames > 0 ? scopeIntervalFrames : undefined,
|
|
320
379
|
clipPageRequestSharedBuffer: clipPageRequestRing?.sharedBuffer,
|
|
321
380
|
clipPageRequestRingCapacity: clipPageRequestRing?.capacity,
|
|
322
381
|
externalMidiSharedBuffer: externalMidiRing?.sharedBuffer,
|
|
@@ -370,6 +429,11 @@ export class SonareRealtimeEngineNode {
|
|
|
370
429
|
return this.sendCommand({ type: SonareEngineCommandType.TransportPlay, sampleTime });
|
|
371
430
|
}
|
|
372
431
|
|
|
432
|
+
/** Queues a reset of the master's integrated-loudness accumulator. */
|
|
433
|
+
resetMasterLoudnessMeter(sampleTime = -1): boolean {
|
|
434
|
+
return this.sendCommand({ type: SonareEngineCommandType.ResetMasterLoudnessMeter, sampleTime });
|
|
435
|
+
}
|
|
436
|
+
|
|
373
437
|
stop(sampleTime = -1): boolean {
|
|
374
438
|
return this.sendCommand({ type: SonareEngineCommandType.TransportStop, sampleTime });
|
|
375
439
|
}
|
|
@@ -600,6 +664,12 @@ export class SonareRealtimeEngineNode {
|
|
|
600
664
|
this.scopeListeners.clear();
|
|
601
665
|
this.midiOutListeners.clear();
|
|
602
666
|
this.clipPageRequestListeners.clear();
|
|
667
|
+
this.syncErrorListeners.clear();
|
|
668
|
+
// The port outlives destroy(): the worklet tears itself down asynchronously
|
|
669
|
+
// after the 'destroy' message above, so a syncError already in flight would
|
|
670
|
+
// still be dispatched here. Detaching the handler is what makes the
|
|
671
|
+
// listener sets stay empty rather than being refilled by a late message.
|
|
672
|
+
this.node.port.onmessage = null;
|
|
603
673
|
}
|
|
604
674
|
|
|
605
675
|
private emitTelemetry(telemetry: SonareEngineTelemetryRecord): void {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EngineCaptureStatus, EngineMarker, EngineTrackLane, RealtimeEngine } from '../index';
|
|
2
|
+
import { requireChannelCount, requireInteger, requireIntegerOption } from './guards';
|
|
2
3
|
import type { SonareEngineSyncCaptureMessage, SonareEngineTransportFacade } from './messages';
|
|
3
4
|
|
|
4
5
|
/** Capture configuration options accepted by the engine's `configureCapture`. */
|
|
@@ -12,20 +13,22 @@ export interface CaptureOptions {
|
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Normalizes capture options into the resolved config carried by the
|
|
15
|
-
* `syncCapture` message, applying
|
|
16
|
+
* `syncCapture` message, applying defaults and refusing a non-integer count.
|
|
16
17
|
*
|
|
17
18
|
* @param options Raw capture options.
|
|
18
19
|
* @param defaultChannels Channel count to use when `options.channels` is unset.
|
|
20
|
+
* @throws RangeError if a frame count, channel count or offset is not an integer.
|
|
19
21
|
*/
|
|
20
22
|
export function buildCaptureConfig(
|
|
21
23
|
options: CaptureOptions,
|
|
22
24
|
defaultChannels: number,
|
|
23
25
|
): Omit<SonareEngineSyncCaptureMessage, 'type'> {
|
|
24
26
|
return {
|
|
25
|
-
bufferFrames
|
|
26
|
-
|
|
27
|
+
// bufferFrames has no default; NaN makes the guard refuse an absent value.
|
|
28
|
+
bufferFrames: requireIntegerOption(options.bufferFrames, Number.NaN, 'bufferFrames', 1),
|
|
29
|
+
channels: requireChannelCount(options.channels, defaultChannels),
|
|
27
30
|
source: options.source ?? 'output',
|
|
28
|
-
recordOffsetSamples:
|
|
31
|
+
recordOffsetSamples: requireInteger(options.recordOffsetSamples, 0, 'recordOffsetSamples'),
|
|
29
32
|
inputMonitor: {
|
|
30
33
|
enabled: Boolean(options.inputMonitor?.enabled),
|
|
31
34
|
gain: options.inputMonitor?.gain ?? 1,
|
|
@@ -111,7 +114,7 @@ export function normalizeTrackLanes(
|
|
|
111
114
|
const ids: number[] = [];
|
|
112
115
|
for (const entry of entries) {
|
|
113
116
|
if (!Number.isInteger(entry.trackId) || entry.trackId <= 0) {
|
|
114
|
-
throw new
|
|
117
|
+
throw new RangeError(`Invalid track id for mixer lane: ${String(entry.trackId)}`);
|
|
115
118
|
}
|
|
116
119
|
ids.push(entry.trackId);
|
|
117
120
|
}
|
|
@@ -145,12 +148,15 @@ export function resolveMarkerSet(
|
|
|
145
148
|
const seen = new Set<number>();
|
|
146
149
|
let counter = nextMarkerId;
|
|
147
150
|
for (const marker of markers) {
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
// Non-negative as well as finite, which is the domain the native setter
|
|
152
|
+
// enforces; checking only finiteness here hands a negative ppq on to be
|
|
153
|
+
// refused a layer down, under that layer's name for the argument.
|
|
154
|
+
if (!Number.isFinite(marker.ppq) || marker.ppq < 0) {
|
|
155
|
+
throw new RangeError(`Invalid marker ppq: ${String(marker.ppq)}`);
|
|
150
156
|
}
|
|
151
157
|
if (marker.id !== undefined) {
|
|
152
158
|
if (!Number.isInteger(marker.id) || marker.id <= 0) {
|
|
153
|
-
throw new
|
|
159
|
+
throw new RangeError(`Invalid marker id: ${String(marker.id)}`);
|
|
154
160
|
}
|
|
155
161
|
if (seen.has(marker.id)) {
|
|
156
162
|
throw new Error(`Duplicate marker id: ${marker.id}`);
|
|
@@ -190,6 +190,27 @@ export function resolveBusInsertAutomationId(
|
|
|
190
190
|
return ctx.offlineEngine.resolveBusInsertAutomationId(busId, insertIndex, paramName);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Resolves a hosted instrument's continuous parameter to its reserved
|
|
195
|
+
* instrument-automation id, so an instrument parameter is driven from a
|
|
196
|
+
* breakpoint lane at audio-block precision like a strip insert.
|
|
197
|
+
*
|
|
198
|
+
* The instrument must already be bound on the offline engine for the
|
|
199
|
+
* destination (the worklet mirrors every instrument sync onto it), otherwise
|
|
200
|
+
* the resolve returns -1.
|
|
201
|
+
*
|
|
202
|
+
* @param destinationId MIDI destination the instrument is bound to.
|
|
203
|
+
* @param paramName Instrument JSON-key parameter name (e.g. `cutoffHz`).
|
|
204
|
+
* @returns Reserved instrument-automation id, or -1 when destination/key unknown.
|
|
205
|
+
*/
|
|
206
|
+
export function resolveInstrumentAutomationId(
|
|
207
|
+
ctx: EngineParameterContext,
|
|
208
|
+
destinationId: number,
|
|
209
|
+
paramName: string,
|
|
210
|
+
): number {
|
|
211
|
+
return ctx.offlineEngine.resolveInstrumentAutomationId(destinationId, paramName);
|
|
212
|
+
}
|
|
213
|
+
|
|
193
214
|
/**
|
|
194
215
|
* Returns the number of automation lanes installed on the engine, including
|
|
195
216
|
* lanes whose breakpoint list is currently empty.
|