@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
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { EngineClip } from '../index';
|
|
2
2
|
import { RealtimeEngine } from '../index';
|
|
3
|
-
import type
|
|
3
|
+
import { copyPlanesToOutput, type WorkletInput, type WorkletOutput } from './audio_types';
|
|
4
|
+
import {
|
|
5
|
+
requireChannelCount,
|
|
6
|
+
requireIntegerOption,
|
|
7
|
+
resolveScopeBandCount,
|
|
8
|
+
SONARE_SCOPE_MAX_BANDS,
|
|
9
|
+
SONARE_SCOPE_MAX_POINTS,
|
|
10
|
+
} from './guards';
|
|
4
11
|
import {
|
|
5
12
|
DEFAULT_METRONOME_CONFIG,
|
|
6
13
|
type ResolvedMetronomeConfig,
|
|
@@ -39,37 +46,13 @@ import {
|
|
|
39
46
|
type SonareEngineTelemetryRecord,
|
|
40
47
|
type SonareEngineTelemetryRingBuffer,
|
|
41
48
|
SonareEngineTelemetryType,
|
|
42
|
-
type
|
|
49
|
+
type SonareWorkletScopeSnapshot,
|
|
43
50
|
scopeRingFromSharedBuffer,
|
|
44
51
|
telemetryFromEngine,
|
|
45
52
|
writeInt64Words,
|
|
46
53
|
writeSonareEngineTelemetryRingBuffer,
|
|
47
54
|
} from './protocol';
|
|
48
55
|
|
|
49
|
-
/**
|
|
50
|
-
* Copies one plane per output channel, zero-filling the tail past `frames` and
|
|
51
|
-
* any channel the source does not cover. Shared by the program and cue outputs
|
|
52
|
-
* so the two cannot drift in their padding behaviour. Allocation-free.
|
|
53
|
-
*/
|
|
54
|
-
function copyPlanesToOutput(
|
|
55
|
-
output: Float32Array[],
|
|
56
|
-
planes: readonly Float32Array[],
|
|
57
|
-
frames: number,
|
|
58
|
-
): void {
|
|
59
|
-
for (let ch = 0; ch < output.length; ch++) {
|
|
60
|
-
const target = output[ch];
|
|
61
|
-
const source = planes[ch] ?? planes[0];
|
|
62
|
-
if (source) {
|
|
63
|
-
target.set(source.subarray(0, Math.min(target.length, frames)));
|
|
64
|
-
if (target.length > frames) {
|
|
65
|
-
target.fill(0, frames);
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
target.fill(0);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
56
|
function captureTransferList(channels: readonly Float32Array[]): Transferable[] {
|
|
74
57
|
const transfers: ArrayBuffer[] = [];
|
|
75
58
|
const seen = new Set<ArrayBuffer>();
|
|
@@ -107,6 +90,9 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
107
90
|
private transport?: WorkletTransport;
|
|
108
91
|
private meterIntervalFrames: number;
|
|
109
92
|
private lastMeterFrame = Number.NEGATIVE_INFINITY;
|
|
93
|
+
private scopeIntervalFrames: number;
|
|
94
|
+
private scopeEnabled: boolean;
|
|
95
|
+
private scopeBands: number;
|
|
110
96
|
// Latest metronome gains/click length pushed via 'syncMetronome'. The
|
|
111
97
|
// SetMetronome command only toggles enabled state; the config arrives here.
|
|
112
98
|
private metronomeConfig: ResolvedMetronomeConfig = { ...DEFAULT_METRONOME_CONFIG };
|
|
@@ -141,9 +127,15 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
141
127
|
) {
|
|
142
128
|
this.sampleRate = options.sampleRate ?? 48000;
|
|
143
129
|
this.blockSize = options.blockSize ?? 128;
|
|
144
|
-
this.channelCount =
|
|
130
|
+
this.channelCount = requireChannelCount(options.channelCount, 2);
|
|
145
131
|
this.transport = transport;
|
|
146
|
-
|
|
132
|
+
// Zero is the off switch for meter publication, so the floor is 0.
|
|
133
|
+
this.meterIntervalFrames = requireIntegerOption(
|
|
134
|
+
options.meterIntervalFrames,
|
|
135
|
+
2048,
|
|
136
|
+
'meterIntervalFrames',
|
|
137
|
+
0,
|
|
138
|
+
);
|
|
147
139
|
this.commandRing = options.commandSharedBuffer
|
|
148
140
|
? this.commandRingFromSharedBuffer(options.commandSharedBuffer, options.commandRingCapacity)
|
|
149
141
|
: undefined;
|
|
@@ -163,6 +155,16 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
163
155
|
options.scopeBands,
|
|
164
156
|
)
|
|
165
157
|
: undefined;
|
|
158
|
+
this.scopeIntervalFrames = requireIntegerOption(
|
|
159
|
+
options.scopeIntervalFrames,
|
|
160
|
+
this.scopeRing ? this.blockSize : 0,
|
|
161
|
+
'scopeIntervalFrames',
|
|
162
|
+
0,
|
|
163
|
+
);
|
|
164
|
+
this.scopeBands = resolveScopeBandCount(options.scopeBands);
|
|
165
|
+
this.scopeEnabled =
|
|
166
|
+
this.scopeIntervalFrames > 0 &&
|
|
167
|
+
(this.scopeRing !== undefined || typeof this.transport?.postMessage === 'function');
|
|
166
168
|
this.clipPageRequestRing = options.clipPageRequestSharedBuffer
|
|
167
169
|
? clipPageRequestRingFromSharedBuffer(
|
|
168
170
|
options.clipPageRequestSharedBuffer,
|
|
@@ -175,10 +177,13 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
175
177
|
options.externalMidiRingCapacity,
|
|
176
178
|
)
|
|
177
179
|
: undefined;
|
|
180
|
+
if (this.commandRing && this.commandRing.capacity > 65536) {
|
|
181
|
+
throw new RangeError('commandRingCapacity must be at most 65536');
|
|
182
|
+
}
|
|
178
183
|
this.engine = new RealtimeEngine(
|
|
179
184
|
this.sampleRate,
|
|
180
185
|
this.blockSize,
|
|
181
|
-
1024,
|
|
186
|
+
Math.max(1024, this.commandRing?.capacity ?? 0),
|
|
182
187
|
1024,
|
|
183
188
|
this.channelCount,
|
|
184
189
|
);
|
|
@@ -197,12 +202,12 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
197
202
|
this.monitorBuffers[ch] = this.engine.getMonitorChannelBuffer(ch, this.blockSize);
|
|
198
203
|
}
|
|
199
204
|
}
|
|
200
|
-
// Arm the
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
// Arm the native scope producer only when a SAB ring or postMessage sink exists.
|
|
206
|
+
if (this.scopeEnabled) {
|
|
207
|
+
this.engine.configureScopeTelemetry(
|
|
208
|
+
this.scopeIntervalFrames,
|
|
209
|
+
Math.min(this.scopeRing?.bands ?? this.scopeBands, SONARE_SCOPE_MAX_BANDS),
|
|
210
|
+
);
|
|
206
211
|
}
|
|
207
212
|
}
|
|
208
213
|
|
|
@@ -395,6 +400,14 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
395
400
|
}
|
|
396
401
|
break;
|
|
397
402
|
}
|
|
403
|
+
case 'syncClipPagePrefetchFrames': {
|
|
404
|
+
this.engine.setClipPagePrefetchFrames(message.frames);
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
case 'syncWarpVoiceCapacity': {
|
|
408
|
+
this.engine.setWarpVoiceCapacity(message.voices);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
398
411
|
case 'syncClipPageCommit': {
|
|
399
412
|
const providerId = this.pagedClipProviders.get(message.clipId);
|
|
400
413
|
const clip = message.clip ?? this.pendingPagedClips.get(message.clipId);
|
|
@@ -455,7 +468,47 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
455
468
|
);
|
|
456
469
|
}
|
|
457
470
|
break;
|
|
458
|
-
case 'syncMixer':
|
|
471
|
+
case 'syncMixer': {
|
|
472
|
+
if (message.sidechainDelta === true) {
|
|
473
|
+
// Sidechain setters send a binding delta through this message type.
|
|
474
|
+
// Their `lanes` field is context, not a request to rebuild routing;
|
|
475
|
+
// rebuilding it here would discard live insert smoother slots.
|
|
476
|
+
for (const binding of message.laneSidechains ?? []) {
|
|
477
|
+
this.engine.setLaneSidechain(
|
|
478
|
+
binding.trackId,
|
|
479
|
+
binding.insertIndex,
|
|
480
|
+
binding.sourceTrackId,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
for (const binding of message.busSidechains ?? []) {
|
|
484
|
+
this.engine.setBusSidechain(
|
|
485
|
+
binding.busId,
|
|
486
|
+
binding.insertIndex,
|
|
487
|
+
binding.sourceKind,
|
|
488
|
+
binding.sourceId,
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
for (const binding of message.masterSidechains ?? []) {
|
|
492
|
+
this.engine.setMasterSidechain(
|
|
493
|
+
binding.insertIndex,
|
|
494
|
+
binding.sourceKind,
|
|
495
|
+
binding.sourceId,
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
// SAB commands are published before the control thread posts this
|
|
501
|
+
// structural sync. Drain the whole snapshot so a future command past
|
|
502
|
+
// the normal 64-per-render budget cannot enter native after the strip
|
|
503
|
+
// replacement has invalidated its target.
|
|
504
|
+
if (this.commandRing) {
|
|
505
|
+
const write = Atomics.load(this.commandRing.header, 0);
|
|
506
|
+
const read = Atomics.load(this.commandRing.header, 1);
|
|
507
|
+
this.drainCommands(Math.min(this.commandRing.capacity, Math.max(0, write - read)));
|
|
508
|
+
}
|
|
509
|
+
// Complete earlier immediate edits in message order. Scheduled
|
|
510
|
+
// commands remain queued for their render frame.
|
|
511
|
+
this.engine.applyCommandsDueNowPreservingFuture();
|
|
459
512
|
if (message.buses) {
|
|
460
513
|
this.engine.setTrackBuses(message.buses);
|
|
461
514
|
}
|
|
@@ -469,10 +522,62 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
469
522
|
if (message.masterStripJson) {
|
|
470
523
|
this.engine.setMasterStripJson(message.masterStripJson);
|
|
471
524
|
}
|
|
525
|
+
for (const target of message.insertBaseResets ?? []) {
|
|
526
|
+
switch (target.kind) {
|
|
527
|
+
case 'track':
|
|
528
|
+
this.engine.clearTrackInsertParameterBases(target.trackId);
|
|
529
|
+
break;
|
|
530
|
+
case 'bus':
|
|
531
|
+
this.engine.clearBusInsertParameterBases(target.busId);
|
|
532
|
+
break;
|
|
533
|
+
case 'master':
|
|
534
|
+
this.engine.clearMasterInsertParameterBases();
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
472
538
|
for (const binding of message.laneSidechains ?? []) {
|
|
473
539
|
this.engine.setLaneSidechain(binding.trackId, binding.insertIndex, binding.sourceTrackId);
|
|
474
540
|
}
|
|
541
|
+
for (const binding of message.busSidechains ?? []) {
|
|
542
|
+
this.engine.setBusSidechain(
|
|
543
|
+
binding.busId,
|
|
544
|
+
binding.insertIndex,
|
|
545
|
+
binding.sourceKind,
|
|
546
|
+
binding.sourceId,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
for (const binding of message.masterSidechains ?? []) {
|
|
550
|
+
this.engine.setMasterSidechain(binding.insertIndex, binding.sourceKind, binding.sourceId);
|
|
551
|
+
}
|
|
552
|
+
for (const override of message.insertParamOverrides ?? []) {
|
|
553
|
+
switch (override.kind) {
|
|
554
|
+
case 'track':
|
|
555
|
+
this.engine.restoreTrackStripInsertParamByName(
|
|
556
|
+
override.trackId,
|
|
557
|
+
override.insertIndex,
|
|
558
|
+
override.paramName,
|
|
559
|
+
override.value,
|
|
560
|
+
);
|
|
561
|
+
break;
|
|
562
|
+
case 'bus':
|
|
563
|
+
this.engine.restoreBusStripInsertParamByName(
|
|
564
|
+
override.busId,
|
|
565
|
+
override.insertIndex,
|
|
566
|
+
override.paramName,
|
|
567
|
+
override.value,
|
|
568
|
+
);
|
|
569
|
+
break;
|
|
570
|
+
case 'master':
|
|
571
|
+
this.engine.restoreMasterStripInsertParamByName(
|
|
572
|
+
override.insertIndex,
|
|
573
|
+
override.paramName,
|
|
574
|
+
override.value,
|
|
575
|
+
);
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
475
579
|
break;
|
|
580
|
+
}
|
|
476
581
|
case 'syncCapture':
|
|
477
582
|
this.engine.setCaptureBuffer(message.channels, message.bufferFrames);
|
|
478
583
|
this.engine.setCaptureSource(message.source);
|
|
@@ -485,6 +590,9 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
485
590
|
case 'syncMasterStripEqBand':
|
|
486
591
|
this.engine.setMasterStripEqBandJson(message.bandIndex, message.bandJson);
|
|
487
592
|
break;
|
|
593
|
+
case 'syncBusStripEqBand':
|
|
594
|
+
this.engine.setBusStripEqBandJson(message.busId, message.bandIndex, message.bandJson);
|
|
595
|
+
break;
|
|
488
596
|
case 'syncTrackStripInsertBypassed':
|
|
489
597
|
this.engine.setTrackStripInsertBypassed(
|
|
490
598
|
message.trackId,
|
|
@@ -501,26 +609,65 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
501
609
|
);
|
|
502
610
|
break;
|
|
503
611
|
case 'syncTrackStripInsertParamByName':
|
|
504
|
-
this.engine.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
612
|
+
this.engine.applyCommandsDueNowPreservingFuture();
|
|
613
|
+
if (
|
|
614
|
+
!this.engine.applyTrackStripInsertParamByNameNow(
|
|
615
|
+
message.trackId,
|
|
616
|
+
message.insertIndex,
|
|
617
|
+
message.paramName,
|
|
618
|
+
message.value,
|
|
619
|
+
)
|
|
620
|
+
) {
|
|
621
|
+
// A burst can exhaust the fixed smoother slots before the next
|
|
622
|
+
// render quantum. Apply the last knob value exactly in that case.
|
|
623
|
+
this.engine.restoreTrackStripInsertParamByName(
|
|
624
|
+
message.trackId,
|
|
625
|
+
message.insertIndex,
|
|
626
|
+
message.paramName,
|
|
627
|
+
message.value,
|
|
628
|
+
);
|
|
629
|
+
}
|
|
510
630
|
break;
|
|
511
631
|
case 'syncMasterStripInsertParamByName':
|
|
512
|
-
this.engine.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
632
|
+
this.engine.applyCommandsDueNowPreservingFuture();
|
|
633
|
+
if (
|
|
634
|
+
!this.engine.applyMasterStripInsertParamByNameNow(
|
|
635
|
+
message.insertIndex,
|
|
636
|
+
message.paramName,
|
|
637
|
+
message.value,
|
|
638
|
+
)
|
|
639
|
+
) {
|
|
640
|
+
this.engine.restoreMasterStripInsertParamByName(
|
|
641
|
+
message.insertIndex,
|
|
642
|
+
message.paramName,
|
|
643
|
+
message.value,
|
|
644
|
+
);
|
|
645
|
+
}
|
|
517
646
|
break;
|
|
518
647
|
case 'syncBusStripInsertParamByName':
|
|
519
|
-
this.engine.
|
|
648
|
+
this.engine.applyCommandsDueNowPreservingFuture();
|
|
649
|
+
if (
|
|
650
|
+
!this.engine.applyBusStripInsertParamByNameNow(
|
|
651
|
+
message.busId,
|
|
652
|
+
message.insertIndex,
|
|
653
|
+
message.paramName,
|
|
654
|
+
message.value,
|
|
655
|
+
)
|
|
656
|
+
) {
|
|
657
|
+
this.engine.restoreBusStripInsertParamByName(
|
|
658
|
+
message.busId,
|
|
659
|
+
message.insertIndex,
|
|
660
|
+
message.paramName,
|
|
661
|
+
message.value,
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
break;
|
|
665
|
+
case 'syncBusStripInsertBypassed':
|
|
666
|
+
this.engine.setBusStripInsertBypassed(
|
|
520
667
|
message.busId,
|
|
521
668
|
message.insertIndex,
|
|
522
|
-
message.
|
|
523
|
-
message.
|
|
669
|
+
message.bypassed,
|
|
670
|
+
message.resetOnBypass,
|
|
524
671
|
);
|
|
525
672
|
break;
|
|
526
673
|
case 'syncTrackStripPan':
|
|
@@ -535,6 +682,18 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
535
682
|
case 'syncTrackStripDualPan':
|
|
536
683
|
this.engine.setTrackStripDualPan(message.trackId, message.leftPan, message.rightPan);
|
|
537
684
|
break;
|
|
685
|
+
case 'syncBusStripPan':
|
|
686
|
+
this.engine.setBusStripPan(message.busId, message.pan);
|
|
687
|
+
break;
|
|
688
|
+
case 'syncBusStripPanLaw':
|
|
689
|
+
this.engine.setBusStripPanLaw(message.busId, message.panLaw);
|
|
690
|
+
break;
|
|
691
|
+
case 'syncBusStripPanMode':
|
|
692
|
+
this.engine.setBusStripPanMode(message.busId, message.panMode);
|
|
693
|
+
break;
|
|
694
|
+
case 'syncBusStripDualPan':
|
|
695
|
+
this.engine.setBusStripDualPan(message.busId, message.leftPan, message.rightPan);
|
|
696
|
+
break;
|
|
538
697
|
case 'syncTrackStripChannelDelaySamples':
|
|
539
698
|
this.engine.setTrackStripChannelDelaySamples(message.trackId, message.delaySamples);
|
|
540
699
|
break;
|
|
@@ -586,8 +745,36 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
586
745
|
message.renderFrame,
|
|
587
746
|
);
|
|
588
747
|
break;
|
|
748
|
+
case 'syncMidiPitchBend':
|
|
749
|
+
this.engine.pushMidiPitchBend(
|
|
750
|
+
message.destinationId,
|
|
751
|
+
message.group,
|
|
752
|
+
message.channel,
|
|
753
|
+
message.data0,
|
|
754
|
+
message.renderFrame,
|
|
755
|
+
);
|
|
756
|
+
break;
|
|
757
|
+
case 'syncMidiChannelPressure':
|
|
758
|
+
this.engine.pushMidiChannelPressure(
|
|
759
|
+
message.destinationId,
|
|
760
|
+
message.group,
|
|
761
|
+
message.channel,
|
|
762
|
+
message.data0,
|
|
763
|
+
message.renderFrame,
|
|
764
|
+
);
|
|
765
|
+
break;
|
|
766
|
+
case 'syncMidiPolyPressure':
|
|
767
|
+
this.engine.pushMidiPolyPressure(
|
|
768
|
+
message.destinationId,
|
|
769
|
+
message.group,
|
|
770
|
+
message.channel,
|
|
771
|
+
message.data0,
|
|
772
|
+
message.data1,
|
|
773
|
+
message.renderFrame,
|
|
774
|
+
);
|
|
775
|
+
break;
|
|
589
776
|
case 'syncMidiUmp':
|
|
590
|
-
this.engine.pushMidiUmp(message.destinationId, message.word0, message.renderFrame);
|
|
777
|
+
this.engine.pushMidiUmp(message.destinationId, [message.word0], message.renderFrame);
|
|
591
778
|
break;
|
|
592
779
|
case 'syncMidiSysex':
|
|
593
780
|
this.engine.pushMidiSysex(message.destinationId, message.data, message.renderFrame);
|
|
@@ -640,6 +827,31 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
640
827
|
message.portTimeSamples,
|
|
641
828
|
);
|
|
642
829
|
break;
|
|
830
|
+
case 'syncMidiInputPitchBend':
|
|
831
|
+
this.engine.pushMidiInputPitchBend(
|
|
832
|
+
message.group,
|
|
833
|
+
message.channel,
|
|
834
|
+
message.data0,
|
|
835
|
+
message.portTimeSamples,
|
|
836
|
+
);
|
|
837
|
+
break;
|
|
838
|
+
case 'syncMidiInputChannelPressure':
|
|
839
|
+
this.engine.pushMidiInputChannelPressure(
|
|
840
|
+
message.group,
|
|
841
|
+
message.channel,
|
|
842
|
+
message.data0,
|
|
843
|
+
message.portTimeSamples,
|
|
844
|
+
);
|
|
845
|
+
break;
|
|
846
|
+
case 'syncMidiInputPolyPressure':
|
|
847
|
+
this.engine.pushMidiInputPolyPressure(
|
|
848
|
+
message.group,
|
|
849
|
+
message.channel,
|
|
850
|
+
message.data0,
|
|
851
|
+
message.data1,
|
|
852
|
+
message.portTimeSamples,
|
|
853
|
+
);
|
|
854
|
+
break;
|
|
643
855
|
}
|
|
644
856
|
}
|
|
645
857
|
|
|
@@ -727,11 +939,11 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
727
939
|
}
|
|
728
940
|
}
|
|
729
941
|
|
|
730
|
-
private drainCommands(): void {
|
|
942
|
+
private drainCommands(limit = 64): void {
|
|
731
943
|
if (!this.commandRing) {
|
|
732
944
|
return;
|
|
733
945
|
}
|
|
734
|
-
for (let i = 0; i <
|
|
946
|
+
for (let i = 0; i < limit; i++) {
|
|
735
947
|
const command = popSonareEngineCommandRingBuffer(this.commandRing);
|
|
736
948
|
if (!command) {
|
|
737
949
|
return;
|
|
@@ -852,6 +1064,9 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
852
1064
|
this.engine.setTrackMonitorMode(laneIndex, mode as 0 | 1 | 2, sampleTime);
|
|
853
1065
|
break;
|
|
854
1066
|
}
|
|
1067
|
+
case SonareEngineCommandType.ResetMasterLoudnessMeter:
|
|
1068
|
+
this.engine.resetMasterLoudnessMeter(sampleTime);
|
|
1069
|
+
break;
|
|
855
1070
|
default:
|
|
856
1071
|
this.publishTelemetryRecord({
|
|
857
1072
|
type: SonareEngineTelemetryType.Error,
|
|
@@ -947,14 +1162,15 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
947
1162
|
if (meter.frame !== this.lastMeterFrame) {
|
|
948
1163
|
this.lastMeterFrame = meter.frame;
|
|
949
1164
|
}
|
|
950
|
-
//
|
|
951
|
-
//
|
|
952
|
-
//
|
|
953
|
-
//
|
|
954
|
-
|
|
955
|
-
|
|
1165
|
+
// The ring branch returned above, so this is the structured-clone
|
|
1166
|
+
// fallback. `onMeter` and `postMessage` are alternative channels for the
|
|
1167
|
+
// same record, not a broadcast pair: the AudioWorklet registration
|
|
1168
|
+
// resolves BOTH to `port.postMessage`, so calling them in turn delivered
|
|
1169
|
+
// every record twice and doubled the host's peak-hold decay rate. Take
|
|
1170
|
+
// the first channel the transport offers.
|
|
1171
|
+
if (this.transport?.onMeter) {
|
|
1172
|
+
this.transport.onMeter(meter);
|
|
956
1173
|
} else {
|
|
957
|
-
this.transport?.onMeter?.(meter);
|
|
958
1174
|
this.transport?.postMessage?.(meter);
|
|
959
1175
|
}
|
|
960
1176
|
}
|
|
@@ -970,49 +1186,72 @@ export class SonareRealtimeEngineWorkletProcessor {
|
|
|
970
1186
|
for (let field = 0; field < 11; field++) {
|
|
971
1187
|
ring.records[offset + 3 + field] = this.engine.meterScratchValue(field);
|
|
972
1188
|
}
|
|
1189
|
+
ring.records[offset + 14] = this.engine.meterScratchInputPeakDbL();
|
|
1190
|
+
ring.records[offset + 15] = this.engine.meterScratchInputPeakDbR();
|
|
973
1191
|
Atomics.store(ring.header, 0, writeIndex + 1);
|
|
974
1192
|
}
|
|
975
1193
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
ring.records[offset + 5] = meter.rmsDbL;
|
|
989
|
-
ring.records[offset + 6] = meter.rmsDbR;
|
|
990
|
-
ring.records[offset + 7] = meter.correlation;
|
|
991
|
-
ring.records[offset + 8] = meter.truePeakDbL;
|
|
992
|
-
ring.records[offset + 9] = meter.truePeakDbR;
|
|
993
|
-
ring.records[offset + 10] = meter.momentaryLufs;
|
|
994
|
-
ring.records[offset + 11] = meter.shortTermLufs;
|
|
995
|
-
ring.records[offset + 12] = meter.integratedLufs;
|
|
996
|
-
ring.records[offset + 13] = meter.gainReductionDb;
|
|
997
|
-
Atomics.store(ring.header, 0, writeIndex + 1);
|
|
998
|
-
// writeIndex is a free-running monotonic counter, so an overflow guard here
|
|
999
|
-
// would fire on essentially every write past the first `capacity` records
|
|
1000
|
-
// and store an ever-growing value, not a dropped-record count. Readers
|
|
1001
|
-
// already detect silent overrun via firstReadable = max(readIndex,
|
|
1002
|
-
// writeIndex - capacity), so header slot 3 is left at its initial 0.
|
|
1003
|
-
}
|
|
1194
|
+
// A snapshot-object ring writer used to live here as well. It was
|
|
1195
|
+
// unreachable: publishMeters returns after the writeMeterScratch loop
|
|
1196
|
+
// whenever a ring exists, so the ring is never fed from a materialised
|
|
1197
|
+
// snapshot. writeMeterScratch above is the only ring writer, and it keeps the
|
|
1198
|
+
// render callback allocation-free by reading the engine's scratch registers
|
|
1199
|
+
// directly.
|
|
1200
|
+
//
|
|
1201
|
+
// writeIndex is a free-running monotonic counter, so an overflow guard would
|
|
1202
|
+
// fire on essentially every write past the first `capacity` records and store
|
|
1203
|
+
// an ever-growing value, not a dropped-record count. Readers already detect
|
|
1204
|
+
// silent overrun via firstReadable = max(readIndex, writeIndex - capacity),
|
|
1205
|
+
// so header slot 3 is left at its initial 0.
|
|
1004
1206
|
|
|
1005
1207
|
// Drains the engine's scope producer (FFT spectrum + goniometer points) into
|
|
1006
|
-
// the lock-free SAB scope ring
|
|
1007
|
-
//
|
|
1208
|
+
// the lock-free SAB scope ring or the bounded postMessage fallback. The SAB
|
|
1209
|
+
// path remains allocation-free; postMessage materialises only records that
|
|
1210
|
+
// are ready to publish.
|
|
1008
1211
|
private publishScope(): void {
|
|
1009
|
-
|
|
1010
|
-
if (!ring) {
|
|
1212
|
+
if (!this.scopeEnabled) {
|
|
1011
1213
|
return;
|
|
1012
1214
|
}
|
|
1215
|
+
const ring = this.scopeRing;
|
|
1216
|
+
const transport = this.transport;
|
|
1013
1217
|
for (let count = 0; count < 64 && this.engine.popScopeTelemetryToScratch(); count++) {
|
|
1014
|
-
|
|
1218
|
+
if (ring) {
|
|
1219
|
+
this.writeScopeScratch(ring);
|
|
1220
|
+
} else {
|
|
1221
|
+
this.postScopeScratch(transport);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
private postScopeScratch(transport: WorkletTransport | undefined): void {
|
|
1227
|
+
if (!transport?.postMessage) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
const bandCount = Math.min(
|
|
1231
|
+
SONARE_SCOPE_MAX_BANDS,
|
|
1232
|
+
Math.max(0, Math.trunc(Number(this.engine.scopeScratchBandCount()))),
|
|
1233
|
+
);
|
|
1234
|
+
const pointCount = Math.min(
|
|
1235
|
+
SONARE_SCOPE_MAX_POINTS,
|
|
1236
|
+
Math.max(0, Math.trunc(Number(this.engine.scopeScratchPointCount()))),
|
|
1237
|
+
);
|
|
1238
|
+
const bands = new Float32Array(bandCount);
|
|
1239
|
+
for (let i = 0; i < bandCount; i++) {
|
|
1240
|
+
bands[i] = this.engine.scopeScratchBand(i);
|
|
1241
|
+
}
|
|
1242
|
+
const points = new Float32Array(pointCount * 2);
|
|
1243
|
+
for (let i = 0; i < pointCount; i++) {
|
|
1244
|
+
points[2 * i] = this.engine.scopeScratchPointLeft(i);
|
|
1245
|
+
points[2 * i + 1] = this.engine.scopeScratchPointRight(i);
|
|
1015
1246
|
}
|
|
1247
|
+
const scope: SonareWorkletScopeSnapshot = {
|
|
1248
|
+
type: 'scope',
|
|
1249
|
+
targetId: this.engine.scopeScratchTargetId(),
|
|
1250
|
+
frame: Number(this.engine.scopeScratchRenderFrame()),
|
|
1251
|
+
bands,
|
|
1252
|
+
points,
|
|
1253
|
+
};
|
|
1254
|
+
transport.postMessage(scope, [bands.buffer, points.buffer]);
|
|
1016
1255
|
}
|
|
1017
1256
|
|
|
1018
1257
|
private writeScopeScratch(ring: SharedScopeRingWriter): void {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isEngineTransportRequestMessage,
|
|
10
10
|
} from './guards';
|
|
11
11
|
import type { SonareRealtimeEngineWorkletProcessorOptions, WorkletPort } from './messages';
|
|
12
|
+
import { isRecord } from './protocol';
|
|
12
13
|
|
|
13
14
|
export function registerSonareRealtimeEngineWorkletProcessor(
|
|
14
15
|
name = 'sonare-realtime-engine-processor',
|
|
@@ -43,15 +44,7 @@ export function registerSonareRealtimeEngineWorkletProcessor(
|
|
|
43
44
|
}
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
this.bridge.receiveCommand(event.data);
|
|
48
|
-
} else if (isEngineSyncMessage(event.data)) {
|
|
49
|
-
this.bridge.receiveSync(event.data);
|
|
50
|
-
} else if (isEngineCaptureRequestMessage(event.data)) {
|
|
51
|
-
this.bridge.receiveCaptureRequest(event.data);
|
|
52
|
-
} else if (isEngineTransportRequestMessage(event.data)) {
|
|
53
|
-
this.bridge.receiveTransportRequest(event.data);
|
|
54
|
-
}
|
|
47
|
+
this.routeMessage(event.data);
|
|
55
48
|
};
|
|
56
49
|
if (port?.addEventListener) {
|
|
57
50
|
port.addEventListener('message', onMessage);
|
|
@@ -72,18 +65,39 @@ export function registerSonareRealtimeEngineWorkletProcessor(
|
|
|
72
65
|
return true;
|
|
73
66
|
}
|
|
74
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Single dispatch point for the port, shared with the buffered replay so
|
|
70
|
+
* the two cannot recognize different message sets.
|
|
71
|
+
*/
|
|
72
|
+
private routeMessage(data: unknown): void {
|
|
73
|
+
const bridge = this.bridge;
|
|
74
|
+
if (!bridge) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (isEngineCommandRecord(data)) {
|
|
78
|
+
bridge.receiveCommand(data);
|
|
79
|
+
} else if (isEngineSyncMessage(data)) {
|
|
80
|
+
bridge.receiveSync(data);
|
|
81
|
+
} else if (isEngineCaptureRequestMessage(data)) {
|
|
82
|
+
bridge.receiveCaptureRequest(data);
|
|
83
|
+
} else if (isEngineTransportRequestMessage(data)) {
|
|
84
|
+
bridge.receiveTransportRequest(data);
|
|
85
|
+
} else if (isRecord(data) && typeof data.type === 'string' && data.type.startsWith('sync')) {
|
|
86
|
+
// A sync the guard does not accept would otherwise vanish, leaving the
|
|
87
|
+
// live engine out of step with the offline mirror and nothing to see.
|
|
88
|
+
// Report it through the same channel as a sync the engine rejected.
|
|
89
|
+
this.port?.postMessage?.({
|
|
90
|
+
type: 'syncError',
|
|
91
|
+
syncType: data.type,
|
|
92
|
+
message: `Unrecognized worklet sync message: ${data.type}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
75
97
|
private replayPendingMessages(): void {
|
|
76
98
|
const messages = this.pendingMessages.splice(0);
|
|
77
99
|
for (const data of messages) {
|
|
78
|
-
|
|
79
|
-
this.bridge?.receiveCommand(data);
|
|
80
|
-
} else if (isEngineSyncMessage(data)) {
|
|
81
|
-
this.bridge?.receiveSync(data);
|
|
82
|
-
} else if (isEngineCaptureRequestMessage(data)) {
|
|
83
|
-
this.bridge?.receiveCaptureRequest(data);
|
|
84
|
-
} else if (isEngineTransportRequestMessage(data)) {
|
|
85
|
-
this.bridge?.receiveTransportRequest(data);
|
|
86
|
-
}
|
|
100
|
+
this.routeMessage(data);
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
|