@libraz/libsonare 1.7.2 → 1.8.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/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 +6 -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 +873 -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 +477 -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 +129 -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 +3758 -1362
- 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 +457 -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 +652 -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 +510 -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 +164 -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 +850 -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 +3909 -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 +335 -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 +128 -0
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
- package/dist/worklet/engine-node.d.ts +81 -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 +68 -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 +73 -0
- package/dist/worklet/engine-strips.d.ts.map +1 -0
- package/dist/worklet/engine-sync.d.ts +37 -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 +397 -0
- package/dist/worklet/engine.d.ts.map +1 -0
- package/dist/worklet/guards.d.ts +47 -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 +323 -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 +2763 -501
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -12
- package/src/_effects_common.ts +17 -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 +97 -22
- package/src/effects_note_ops.ts +635 -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 +377 -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 +282 -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 +346 -32
- package/src/mastering_dynamics.ts +22 -11
- package/src/metering.ts +67 -24
- package/src/mixer.ts +212 -3
- 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 +268 -270
- package/src/public_types.ts +122 -3
- package/src/public_types_acoustic.ts +112 -3
- package/src/public_types_mastering.ts +254 -73
- package/src/public_types_mixing.ts +363 -1
- package/src/public_types_music.ts +312 -2
- package/src/public_types_playback.ts +195 -0
- package/src/public_types_realtime.ts +39 -7
- package/src/public_types_repair.ts +446 -0
- package/src/public_types_spectral.ts +487 -1
- package/src/quick_analysis.ts +203 -26
- package/src/realtime_engine.ts +711 -28
- 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 +1122 -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 +194 -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 +444 -10
- package/src/worklet/engine-node.ts +78 -26
- package/src/worklet/engine-offline.ts +14 -8
- package/src/worklet/engine-parameter-facade.ts +21 -0
- package/src/worklet/engine-processor.ts +272 -83
- package/src/worklet/engine-register.ts +32 -18
- package/src/worklet/engine-strips.ts +280 -9
- package/src/worklet/engine-sync.ts +14 -6
- package/src/worklet/engine.ts +365 -31
- package/src/worklet/guards.ts +140 -44
- package/src/worklet/messages.ts +227 -2
- package/src/worklet/mixer-processor.ts +109 -47
- package/src/worklet/playback-processor.ts +300 -0
- package/src/worklet/protocol.ts +53 -3
- 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,9 +1,26 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { sidechainSourceKindCode } from '../codes';
|
|
2
|
+
import type {
|
|
3
|
+
EngineBus,
|
|
4
|
+
EngineTrackLane,
|
|
5
|
+
EngineTrackSend,
|
|
6
|
+
RealtimeEngine,
|
|
7
|
+
SidechainSourceKind,
|
|
8
|
+
} from '../index';
|
|
2
9
|
import { normalizeTrackLanes } from './engine-offline';
|
|
3
10
|
import { buildMixerLanes } from './engine-sync';
|
|
4
|
-
import type { SonareEngineSyncMessage } from './messages';
|
|
11
|
+
import type { SonareEngineSyncMessage, SonareEngineSyncMixerInsertParamOverride } from './messages';
|
|
5
12
|
import { ENGINE_MIXER_PARAM_FADER_DB, engineMixerBusTarget } from './protocol';
|
|
6
13
|
|
|
14
|
+
/** A latest by-name insert value retained across a later topology replay. */
|
|
15
|
+
export interface InsertParamOverride {
|
|
16
|
+
target: StripJsonTarget;
|
|
17
|
+
insertIndex: number;
|
|
18
|
+
paramName: string;
|
|
19
|
+
value: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type InsertParamOverrideMap = Map<string, InsertParamOverride>;
|
|
23
|
+
|
|
7
24
|
/**
|
|
8
25
|
* Collaborator surface the mixer/routing setters need from the owning
|
|
9
26
|
* {@link SonareEngine}: the offline engine they mirror writes into, the mutable
|
|
@@ -19,16 +36,230 @@ export interface EngineMixerContext {
|
|
|
19
36
|
string,
|
|
20
37
|
{ trackId: number; insertIndex: number; sourceTrackId: number }
|
|
21
38
|
>;
|
|
39
|
+
readonly busSidechains: Map<
|
|
40
|
+
string,
|
|
41
|
+
{ busId: number; insertIndex: number; sourceKind: number; sourceId: number }
|
|
42
|
+
>;
|
|
43
|
+
readonly masterSidechains: Map<
|
|
44
|
+
number,
|
|
45
|
+
{ insertIndex: number; sourceKind: number; sourceId: number }
|
|
46
|
+
>;
|
|
22
47
|
readonly buses: EngineBus[];
|
|
23
48
|
readonly trackStripJson: Map<number, string>;
|
|
24
49
|
readonly busStripJson: Map<number, string>;
|
|
50
|
+
readonly insertParamOverrides: InsertParamOverrideMap;
|
|
51
|
+
clearInsertAutomationLanes(target: StripJsonTarget, forgetResolvedIds?: boolean): void;
|
|
52
|
+
flushOfflineMirror(): void;
|
|
25
53
|
postSync(message: SonareEngineSyncMessage): void;
|
|
26
54
|
ensureTrackLane(target: string | number): number;
|
|
27
55
|
ensureBus(busId: number): number;
|
|
28
56
|
mixerLanes(): EngineTrackLane[];
|
|
29
|
-
syncMixer(): void;
|
|
57
|
+
syncMixer(forceInsertResets?: StripJsonTarget[]): void;
|
|
30
58
|
sendSmoothedParam(paramId: number, value: number): boolean;
|
|
31
59
|
getMasterStripJson(): string | undefined;
|
|
60
|
+
cacheMasterStripJson(sceneJson: string): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Addresses one strip's cached scene JSON, the state a syncMixer re-post replays. */
|
|
64
|
+
export type StripJsonTarget =
|
|
65
|
+
| { kind: 'track'; trackId: number }
|
|
66
|
+
| { kind: 'bus'; busId: number }
|
|
67
|
+
| { kind: 'master' };
|
|
68
|
+
|
|
69
|
+
/** An empty construction scene used only within an explicit strip replacement. */
|
|
70
|
+
export function emptyStripJson(target: StripJsonTarget): string {
|
|
71
|
+
switch (target.kind) {
|
|
72
|
+
case 'track':
|
|
73
|
+
return `{"version":1,"strips":[{"id":"track-${target.trackId}"}],"buses":[],"connections":[]}`;
|
|
74
|
+
case 'bus':
|
|
75
|
+
return `{"version":1,"strips":[],"buses":[{"id":"bus-${target.busId}"}],"connections":[]}`;
|
|
76
|
+
case 'master':
|
|
77
|
+
return '{"version":1,"strips":[{"id":"master"}],"buses":[],"connections":[]}';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Drop bindings whose insert was removed by an explicit scene replacement. */
|
|
82
|
+
export function pruneStripSidechains(
|
|
83
|
+
ctx: EngineMixerContext,
|
|
84
|
+
target: StripJsonTarget,
|
|
85
|
+
sceneJson: string,
|
|
86
|
+
): void {
|
|
87
|
+
const scene = JSON.parse(sceneJson) as {
|
|
88
|
+
strips?: Array<{ inserts?: unknown[] }>;
|
|
89
|
+
buses?: Array<{ inserts?: unknown[] }>;
|
|
90
|
+
};
|
|
91
|
+
const entry = target.kind === 'bus' ? scene.buses?.[0] : scene.strips?.[0];
|
|
92
|
+
const insertCount = Array.isArray(entry?.inserts) ? entry.inserts.length : 0;
|
|
93
|
+
if (target.kind === 'track') {
|
|
94
|
+
for (const [key, binding] of ctx.laneSidechains) {
|
|
95
|
+
if (binding.trackId === target.trackId && binding.insertIndex >= insertCount) {
|
|
96
|
+
ctx.laneSidechains.delete(key);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else if (target.kind === 'bus') {
|
|
100
|
+
for (const [key, binding] of ctx.busSidechains) {
|
|
101
|
+
if (binding.busId === target.busId && binding.insertIndex >= insertCount) {
|
|
102
|
+
ctx.busSidechains.delete(key);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
for (const [key, binding] of ctx.masterSidechains) {
|
|
107
|
+
if (binding.insertIndex >= insertCount) {
|
|
108
|
+
ctx.masterSidechains.delete(key);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function hasInsertParamOverrides(
|
|
115
|
+
overrides: InsertParamOverrideMap,
|
|
116
|
+
target: StripJsonTarget,
|
|
117
|
+
): boolean {
|
|
118
|
+
for (const override of overrides.values()) {
|
|
119
|
+
if (sameStripTarget(override.target, target)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Apply the replacement first to validate it, then force fresh insert state. */
|
|
127
|
+
export function applyFullStripJson(
|
|
128
|
+
engine: RealtimeEngine,
|
|
129
|
+
target: StripJsonTarget,
|
|
130
|
+
sceneJson: string,
|
|
131
|
+
resetInserts: boolean,
|
|
132
|
+
): void {
|
|
133
|
+
const apply = (json: string): void => {
|
|
134
|
+
switch (target.kind) {
|
|
135
|
+
case 'track':
|
|
136
|
+
engine.setTrackStripJson(target.trackId, json);
|
|
137
|
+
break;
|
|
138
|
+
case 'bus':
|
|
139
|
+
engine.setBusStripJson(target.busId, json);
|
|
140
|
+
break;
|
|
141
|
+
case 'master':
|
|
142
|
+
engine.setMasterStripJson(json);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
engine.applyCommandsDueNowPreservingFuture();
|
|
147
|
+
apply(sceneJson);
|
|
148
|
+
if (resetInserts) {
|
|
149
|
+
switch (target.kind) {
|
|
150
|
+
case 'track':
|
|
151
|
+
engine.clearTrackInsertParameterBases(target.trackId);
|
|
152
|
+
break;
|
|
153
|
+
case 'bus':
|
|
154
|
+
engine.clearBusInsertParameterBases(target.busId);
|
|
155
|
+
break;
|
|
156
|
+
case 'master':
|
|
157
|
+
engine.clearMasterInsertParameterBases();
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
apply(emptyStripJson(target));
|
|
161
|
+
apply(sceneJson);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Builds a collision-safe key for one target/insert/parameter tuple. */
|
|
166
|
+
export function insertParamOverrideKey(override: InsertParamOverride): string {
|
|
167
|
+
const targetId =
|
|
168
|
+
override.target.kind === 'track'
|
|
169
|
+
? override.target.trackId
|
|
170
|
+
: override.target.kind === 'bus'
|
|
171
|
+
? override.target.busId
|
|
172
|
+
: 'master';
|
|
173
|
+
return JSON.stringify([override.target.kind, targetId, override.insertIndex, override.paramName]);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Removes all retained insert values for one strip after a full scene replacement. */
|
|
177
|
+
export function clearInsertParamOverrides(
|
|
178
|
+
overrides: InsertParamOverrideMap,
|
|
179
|
+
target: StripJsonTarget,
|
|
180
|
+
): void {
|
|
181
|
+
for (const [key, override] of overrides) {
|
|
182
|
+
if (sameStripTarget(override.target, target)) {
|
|
183
|
+
overrides.delete(key);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function sameStripTarget(left: StripJsonTarget, right: StripJsonTarget): boolean {
|
|
189
|
+
if (left.kind !== right.kind) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (left.kind === 'track' && right.kind === 'track') {
|
|
193
|
+
return left.trackId === right.trackId;
|
|
194
|
+
}
|
|
195
|
+
if (left.kind === 'bus' && right.kind === 'bus') {
|
|
196
|
+
return left.busId === right.busId;
|
|
197
|
+
}
|
|
198
|
+
return left.kind === 'master' && right.kind === 'master';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function flattenInsertParamOverride(
|
|
202
|
+
override: InsertParamOverride,
|
|
203
|
+
): SonareEngineSyncMixerInsertParamOverride {
|
|
204
|
+
switch (override.target.kind) {
|
|
205
|
+
case 'track':
|
|
206
|
+
return {
|
|
207
|
+
kind: 'track',
|
|
208
|
+
trackId: override.target.trackId,
|
|
209
|
+
insertIndex: override.insertIndex,
|
|
210
|
+
paramName: override.paramName,
|
|
211
|
+
value: override.value,
|
|
212
|
+
};
|
|
213
|
+
case 'bus':
|
|
214
|
+
return {
|
|
215
|
+
kind: 'bus',
|
|
216
|
+
busId: override.target.busId,
|
|
217
|
+
insertIndex: override.insertIndex,
|
|
218
|
+
paramName: override.paramName,
|
|
219
|
+
value: override.value,
|
|
220
|
+
};
|
|
221
|
+
case 'master':
|
|
222
|
+
return {
|
|
223
|
+
kind: 'master',
|
|
224
|
+
insertIndex: override.insertIndex,
|
|
225
|
+
paramName: override.paramName,
|
|
226
|
+
value: override.value,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Reads a strip's cached scene JSON; undefined when none was ever set. */
|
|
232
|
+
export function cachedStripJson(
|
|
233
|
+
ctx: EngineMixerContext,
|
|
234
|
+
target: StripJsonTarget,
|
|
235
|
+
): string | undefined {
|
|
236
|
+
switch (target.kind) {
|
|
237
|
+
case 'track':
|
|
238
|
+
return ctx.trackStripJson.get(target.trackId);
|
|
239
|
+
case 'bus':
|
|
240
|
+
return ctx.busStripJson.get(target.busId);
|
|
241
|
+
case 'master':
|
|
242
|
+
return ctx.getMasterStripJson();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Replaces a strip's cached scene JSON without syncing it. */
|
|
247
|
+
export function cacheStripJson(
|
|
248
|
+
ctx: EngineMixerContext,
|
|
249
|
+
target: StripJsonTarget,
|
|
250
|
+
sceneJson: string,
|
|
251
|
+
): void {
|
|
252
|
+
switch (target.kind) {
|
|
253
|
+
case 'track':
|
|
254
|
+
ctx.trackStripJson.set(target.trackId, sceneJson);
|
|
255
|
+
return;
|
|
256
|
+
case 'bus':
|
|
257
|
+
ctx.busStripJson.set(target.busId, sceneJson);
|
|
258
|
+
return;
|
|
259
|
+
case 'master':
|
|
260
|
+
ctx.cacheMasterStripJson(sceneJson);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
32
263
|
}
|
|
33
264
|
|
|
34
265
|
/** Builds the engine's track-lane descriptors from the current routing stores. */
|
|
@@ -40,13 +271,47 @@ export function mixerLanes(ctx: EngineMixerContext): EngineTrackLane[] {
|
|
|
40
271
|
* Mirrors the current mixer routing into the offline engine and posts the full
|
|
41
272
|
* mixer-sync message (lanes, buses, strip JSON, sidechains) to the worklet.
|
|
42
273
|
*/
|
|
43
|
-
export function syncMixer(
|
|
274
|
+
export function syncMixer(
|
|
275
|
+
ctx: EngineMixerContext,
|
|
276
|
+
busesAlreadyApplied = false,
|
|
277
|
+
forceInsertResets: StripJsonTarget[] = [],
|
|
278
|
+
): void {
|
|
44
279
|
const lanes = mixerLanes(ctx);
|
|
45
280
|
const buses = ctx.buses.map((bus) => ({ ...bus }));
|
|
46
|
-
|
|
281
|
+
if (!busesAlreadyApplied) {
|
|
282
|
+
ctx.offlineEngine.setTrackBuses(buses);
|
|
283
|
+
}
|
|
47
284
|
if (lanes.length > 0) {
|
|
285
|
+
ctx.offlineEngine.settleInsertParameters();
|
|
48
286
|
ctx.offlineEngine.setTrackLanes(lanes);
|
|
49
287
|
}
|
|
288
|
+
if (forceInsertResets.length > 0) {
|
|
289
|
+
// The temporary empty strip drops native sidechain bindings. Restore the
|
|
290
|
+
// offline mirror in the same order the worklet restores them below.
|
|
291
|
+
for (const binding of ctx.laneSidechains.values()) {
|
|
292
|
+
ctx.offlineEngine.setLaneSidechain(
|
|
293
|
+
binding.trackId,
|
|
294
|
+
binding.insertIndex,
|
|
295
|
+
binding.sourceTrackId,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
for (const binding of ctx.busSidechains.values()) {
|
|
299
|
+
ctx.offlineEngine.setBusSidechain(
|
|
300
|
+
binding.busId,
|
|
301
|
+
binding.insertIndex,
|
|
302
|
+
binding.sourceKind,
|
|
303
|
+
binding.sourceId,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
for (const binding of ctx.masterSidechains.values()) {
|
|
307
|
+
ctx.offlineEngine.setMasterSidechain(
|
|
308
|
+
binding.insertIndex,
|
|
309
|
+
binding.sourceKind,
|
|
310
|
+
binding.sourceId,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
replayInsertParamOverrides(ctx, lanes, buses);
|
|
50
315
|
const trackStrips = Array.from(ctx.trackStripJson, ([trackId, sceneJson]) => ({
|
|
51
316
|
trackId,
|
|
52
317
|
sceneJson,
|
|
@@ -55,6 +320,10 @@ export function syncMixer(ctx: EngineMixerContext): void {
|
|
|
55
320
|
busId,
|
|
56
321
|
sceneJson,
|
|
57
322
|
}));
|
|
323
|
+
const insertParamOverrides = Array.from(
|
|
324
|
+
ctx.insertParamOverrides.values(),
|
|
325
|
+
flattenInsertParamOverride,
|
|
326
|
+
);
|
|
58
327
|
ctx.postSync({
|
|
59
328
|
type: 'syncMixer',
|
|
60
329
|
lanes,
|
|
@@ -63,9 +332,63 @@ export function syncMixer(ctx: EngineMixerContext): void {
|
|
|
63
332
|
laneSidechains: Array.from(ctx.laneSidechains.values()),
|
|
64
333
|
busStrips,
|
|
65
334
|
masterStripJson: ctx.getMasterStripJson(),
|
|
335
|
+
busSidechains: Array.from(ctx.busSidechains.values()),
|
|
336
|
+
masterSidechains: Array.from(ctx.masterSidechains.values()),
|
|
337
|
+
...(insertParamOverrides.length > 0 ? { insertParamOverrides } : {}),
|
|
338
|
+
...(forceInsertResets.length > 0 ? { forceInsertResets } : {}),
|
|
66
339
|
});
|
|
67
340
|
}
|
|
68
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Reapplies retained by-name values after native topology setters clear their
|
|
344
|
+
* smoother slots. This runs once per mixer sync, never once per knob tick.
|
|
345
|
+
*/
|
|
346
|
+
export function replayInsertParamOverrides(
|
|
347
|
+
ctx: EngineMixerContext,
|
|
348
|
+
lanes = mixerLanes(ctx),
|
|
349
|
+
buses = ctx.buses,
|
|
350
|
+
): void {
|
|
351
|
+
const activeTrackIds = new Set(lanes.map((lane) => lane.trackId));
|
|
352
|
+
const activeBusIds = new Set(buses.map((bus) => bus.busId));
|
|
353
|
+
for (const [key, override] of ctx.insertParamOverrides) {
|
|
354
|
+
const active =
|
|
355
|
+
override.target.kind === 'track'
|
|
356
|
+
? activeTrackIds.has(override.target.trackId)
|
|
357
|
+
: override.target.kind === 'bus'
|
|
358
|
+
? activeBusIds.has(override.target.busId)
|
|
359
|
+
: true;
|
|
360
|
+
if (!active) {
|
|
361
|
+
ctx.insertParamOverrides.delete(key);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
switch (override.target.kind) {
|
|
365
|
+
case 'track':
|
|
366
|
+
ctx.offlineEngine.restoreTrackStripInsertParamByName(
|
|
367
|
+
override.target.trackId,
|
|
368
|
+
override.insertIndex,
|
|
369
|
+
override.paramName,
|
|
370
|
+
override.value,
|
|
371
|
+
);
|
|
372
|
+
break;
|
|
373
|
+
case 'bus':
|
|
374
|
+
ctx.offlineEngine.restoreBusStripInsertParamByName(
|
|
375
|
+
override.target.busId,
|
|
376
|
+
override.insertIndex,
|
|
377
|
+
override.paramName,
|
|
378
|
+
override.value,
|
|
379
|
+
);
|
|
380
|
+
break;
|
|
381
|
+
case 'master':
|
|
382
|
+
ctx.offlineEngine.restoreMasterStripInsertParamByName(
|
|
383
|
+
override.insertIndex,
|
|
384
|
+
override.paramName,
|
|
385
|
+
override.value,
|
|
386
|
+
);
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
69
392
|
/**
|
|
70
393
|
* Declares the mixer track lanes in an explicit order.
|
|
71
394
|
*
|
|
@@ -139,19 +462,91 @@ export function setLaneSidechain(
|
|
|
139
462
|
const sourceIndex = ctx.ensureTrackLane(sourceTarget);
|
|
140
463
|
sourceTrackId = ctx.trackLaneIds[sourceIndex];
|
|
141
464
|
}
|
|
465
|
+
ctx.offlineEngine.setLaneSidechain(trackId, insertIndex, sourceTrackId);
|
|
142
466
|
if (sourceTrackId === 0) {
|
|
143
467
|
ctx.laneSidechains.delete(key);
|
|
144
468
|
} else {
|
|
145
469
|
ctx.laneSidechains.set(key, { trackId, insertIndex, sourceTrackId });
|
|
146
470
|
}
|
|
147
|
-
ctx.offlineEngine.setLaneSidechain(trackId, insertIndex, sourceTrackId);
|
|
148
471
|
ctx.postSync({
|
|
149
472
|
type: 'syncMixer',
|
|
473
|
+
sidechainDelta: true,
|
|
150
474
|
lanes: ctx.mixerLanes(),
|
|
151
475
|
laneSidechains: [{ trackId, insertIndex, sourceTrackId }],
|
|
152
476
|
});
|
|
153
477
|
}
|
|
154
478
|
|
|
479
|
+
/**
|
|
480
|
+
* Keys one insert of a bus strip from a track lane or another bus
|
|
481
|
+
* (ducking/sidechainRouter inserts). `sourceId` 0 removes the binding. The
|
|
482
|
+
* binding is cached for resync only once the engine has accepted it.
|
|
483
|
+
*/
|
|
484
|
+
export function setBusSidechain(
|
|
485
|
+
ctx: EngineMixerContext,
|
|
486
|
+
busId: number,
|
|
487
|
+
insertIndex: number,
|
|
488
|
+
kind: SidechainSourceKind | number,
|
|
489
|
+
sourceId: number,
|
|
490
|
+
): void {
|
|
491
|
+
const sourceKind = sidechainSourceKindCode(kind);
|
|
492
|
+
ctx.ensureBus(busId);
|
|
493
|
+
ensureSidechainSource(ctx, sourceKind, sourceId);
|
|
494
|
+
ctx.offlineEngine.setBusSidechain(busId, insertIndex, sourceKind, sourceId);
|
|
495
|
+
const key = `${busId}:${insertIndex}`;
|
|
496
|
+
if (sourceId === 0) {
|
|
497
|
+
ctx.busSidechains.delete(key);
|
|
498
|
+
} else {
|
|
499
|
+
ctx.busSidechains.set(key, { busId, insertIndex, sourceKind, sourceId });
|
|
500
|
+
}
|
|
501
|
+
ctx.postSync({
|
|
502
|
+
type: 'syncMixer',
|
|
503
|
+
sidechainDelta: true,
|
|
504
|
+
lanes: ctx.mixerLanes(),
|
|
505
|
+
busSidechains: [{ busId, insertIndex, sourceKind, sourceId }],
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Keys one insert of the master strip from a track lane or a bus. Same source
|
|
511
|
+
* rules as {@link setBusSidechain}.
|
|
512
|
+
*/
|
|
513
|
+
export function setMasterSidechain(
|
|
514
|
+
ctx: EngineMixerContext,
|
|
515
|
+
insertIndex: number,
|
|
516
|
+
kind: SidechainSourceKind | number,
|
|
517
|
+
sourceId: number,
|
|
518
|
+
): void {
|
|
519
|
+
const sourceKind = sidechainSourceKindCode(kind);
|
|
520
|
+
ensureSidechainSource(ctx, sourceKind, sourceId);
|
|
521
|
+
ctx.offlineEngine.setMasterSidechain(insertIndex, sourceKind, sourceId);
|
|
522
|
+
if (sourceId === 0) {
|
|
523
|
+
ctx.masterSidechains.delete(insertIndex);
|
|
524
|
+
} else {
|
|
525
|
+
ctx.masterSidechains.set(insertIndex, { insertIndex, sourceKind, sourceId });
|
|
526
|
+
}
|
|
527
|
+
ctx.postSync({
|
|
528
|
+
type: 'syncMixer',
|
|
529
|
+
sidechainDelta: true,
|
|
530
|
+
lanes: ctx.mixerLanes(),
|
|
531
|
+
masterSidechains: [{ insertIndex, sourceKind, sourceId }],
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function ensureSidechainSource(
|
|
536
|
+
ctx: EngineMixerContext,
|
|
537
|
+
sourceKind: number,
|
|
538
|
+
sourceId: number,
|
|
539
|
+
): void {
|
|
540
|
+
if (sourceId === 0) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (sourceKind === 1) {
|
|
544
|
+
ctx.ensureBus(sourceId);
|
|
545
|
+
} else {
|
|
546
|
+
ctx.ensureTrackLane(sourceId);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
155
550
|
export function setSends(
|
|
156
551
|
ctx: EngineMixerContext,
|
|
157
552
|
target: string | number,
|
|
@@ -167,20 +562,59 @@ export function setSends(
|
|
|
167
562
|
}
|
|
168
563
|
|
|
169
564
|
export function setTrackBuses(ctx: EngineMixerContext, buses: EngineBus[]): void {
|
|
565
|
+
// Validate and apply before pruning retained scenes. Native rejects a bus
|
|
566
|
+
// removal while a lane still routes to it; that failure must leave JS state
|
|
567
|
+
// untouched so a later valid edit can still replay the existing inserts.
|
|
568
|
+
ctx.offlineEngine.setTrackBuses(buses);
|
|
569
|
+
const retainedBusIds = new Set(buses.map((bus) => bus.busId));
|
|
570
|
+
for (const bus of ctx.buses) {
|
|
571
|
+
if (!retainedBusIds.has(bus.busId)) {
|
|
572
|
+
ctx.clearInsertAutomationLanes({ kind: 'bus', busId: bus.busId }, true);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
170
575
|
ctx.buses.splice(0, ctx.buses.length, ...buses.map((bus) => ({ ...bus })));
|
|
171
|
-
ctx.
|
|
576
|
+
const activeBusIds = new Set(ctx.buses.map((bus) => bus.busId));
|
|
577
|
+
for (const busId of ctx.busStripJson.keys()) {
|
|
578
|
+
if (!activeBusIds.has(busId)) {
|
|
579
|
+
ctx.busStripJson.delete(busId);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
for (const [key, binding] of ctx.busSidechains) {
|
|
583
|
+
if (
|
|
584
|
+
!activeBusIds.has(binding.busId) ||
|
|
585
|
+
(binding.sourceKind === 1 && !activeBusIds.has(binding.sourceId))
|
|
586
|
+
) {
|
|
587
|
+
ctx.busSidechains.delete(key);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
for (const [key, binding] of ctx.masterSidechains) {
|
|
591
|
+
if (binding.sourceKind === 1 && !activeBusIds.has(binding.sourceId)) {
|
|
592
|
+
ctx.masterSidechains.delete(key);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
syncMixer(ctx, true);
|
|
172
596
|
}
|
|
173
597
|
|
|
174
598
|
export function setBusGain(ctx: EngineMixerContext, busId: number, db: number): boolean {
|
|
175
599
|
const busIndex = ctx.ensureBus(busId);
|
|
176
600
|
ctx.buses[busIndex] = { ...ctx.buses[busIndex], busId, gainDb: db };
|
|
177
|
-
|
|
601
|
+
// The reserved smoothed parameter updates both engines. Rebuilding the bus
|
|
602
|
+
// topology for every fader tick would reset insert slots and their tails.
|
|
178
603
|
return ctx.sendSmoothedParam(engineMixerBusTarget(busIndex, ENGINE_MIXER_PARAM_FADER_DB), db);
|
|
179
604
|
}
|
|
180
605
|
|
|
181
606
|
export function setBusStripJson(ctx: EngineMixerContext, busId: number, sceneJson: string): void {
|
|
182
607
|
ctx.ensureBus(busId);
|
|
183
|
-
|
|
608
|
+
const target: StripJsonTarget = { kind: 'bus', busId };
|
|
609
|
+
const resetInserts =
|
|
610
|
+
(ctx.busStripJson.has(busId) && ctx.busStripJson.get(busId) !== sceneJson) ||
|
|
611
|
+
hasInsertParamOverrides(ctx.insertParamOverrides, target);
|
|
612
|
+
applyFullStripJson(ctx.offlineEngine, target, sceneJson, resetInserts);
|
|
613
|
+
if (resetInserts) {
|
|
614
|
+
ctx.clearInsertAutomationLanes(target);
|
|
615
|
+
}
|
|
616
|
+
pruneStripSidechains(ctx, target, sceneJson);
|
|
184
617
|
ctx.busStripJson.set(busId, sceneJson);
|
|
185
|
-
ctx.
|
|
618
|
+
clearInsertParamOverrides(ctx.insertParamOverrides, target);
|
|
619
|
+
ctx.syncMixer(resetInserts ? [target] : []);
|
|
186
620
|
}
|