@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
package/src/realtime_engine.ts
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
panLawCode,
|
|
3
|
+
panModeCode,
|
|
4
|
+
sendTimingCode,
|
|
5
|
+
sidechainSourceKindCode,
|
|
6
|
+
trackMonitorModeCode,
|
|
7
|
+
} from './codes';
|
|
2
8
|
import { ErrorCode, SonareError } from './errors';
|
|
3
9
|
import { getSonareModule } from './module_state';
|
|
4
|
-
import type {
|
|
5
|
-
|
|
10
|
+
import type {
|
|
11
|
+
Articulation,
|
|
12
|
+
ControllerBinding,
|
|
13
|
+
MpeDimension,
|
|
14
|
+
NoteTracking,
|
|
15
|
+
ProjectMidiCcBinding,
|
|
16
|
+
SynthPatch,
|
|
17
|
+
} from './project';
|
|
18
|
+
import { normalizeSynthInstrument } from './project_internal';
|
|
19
|
+
import type {
|
|
20
|
+
EqBand,
|
|
21
|
+
PanLawInput,
|
|
22
|
+
PanMode,
|
|
23
|
+
SendTiming,
|
|
24
|
+
SidechainSourceKind,
|
|
25
|
+
UmpWords,
|
|
26
|
+
} from './public_types';
|
|
6
27
|
import type {
|
|
7
28
|
WasmClipPageRequest,
|
|
8
29
|
WasmEngineAutomationPoint,
|
|
9
30
|
WasmEngineBounceOptions,
|
|
10
31
|
WasmEngineBounceResult,
|
|
32
|
+
WasmEngineBus,
|
|
11
33
|
WasmEngineCaptureStatus,
|
|
12
34
|
WasmEngineClip,
|
|
13
35
|
WasmEngineFreezeOptions,
|
|
@@ -23,6 +45,7 @@ import type {
|
|
|
23
45
|
WasmEngineTelemetry,
|
|
24
46
|
WasmEngineTempoSegment,
|
|
25
47
|
WasmEngineTimeSignatureSegment,
|
|
48
|
+
WasmEngineTrackSend,
|
|
26
49
|
WasmEngineTransportState,
|
|
27
50
|
WasmExternalMidiEvent,
|
|
28
51
|
WasmRealtimeEngine,
|
|
@@ -94,15 +117,37 @@ export interface EngineBus {
|
|
|
94
117
|
* to stereo.
|
|
95
118
|
*/
|
|
96
119
|
channelLayout?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Bus this bus's output sums into instead of the master mix (bus-to-bus
|
|
122
|
+
* routing); 0 or absent keeps it on the master mix.
|
|
123
|
+
*/
|
|
124
|
+
outputBusId?: number;
|
|
125
|
+
/**
|
|
126
|
+
* Sends to other buses, in the same shape as a track lane's sends. A
|
|
127
|
+
* pre-fader send taps before `gainDb`, a post-fader one after it.
|
|
128
|
+
*/
|
|
129
|
+
sends?: EngineTrackSend[];
|
|
97
130
|
}
|
|
98
131
|
|
|
99
132
|
export interface EngineMidiEvent {
|
|
100
|
-
|
|
133
|
+
/** Absolute render frame for this event. Default `0`. */
|
|
134
|
+
renderFrame?: number;
|
|
101
135
|
word0?: number;
|
|
102
136
|
word1?: number;
|
|
103
137
|
word2?: number;
|
|
104
138
|
word3?: number;
|
|
105
139
|
wordCount?: number;
|
|
140
|
+
/**
|
|
141
|
+
* Redundant with `word0`, which already carries the UMP group in bits 24..27.
|
|
142
|
+
* The engine reads the group from `word0` — the form that reaches a device or
|
|
143
|
+
* a file — so packing it there is sufficient and a value here that contradicts
|
|
144
|
+
* `word0` is ignored. Must still be in `[0, 15]`; anything else is rejected as
|
|
145
|
+
* a malformed event. Default `0`.
|
|
146
|
+
*
|
|
147
|
+
* Utility (`word0` type nibble `0x0`) and UMP Stream (`0xF`) messages have no
|
|
148
|
+
* group field — those bits are Reserved and `form`/`status` respectively — so
|
|
149
|
+
* they always read as group `0` and packing a group into them has no effect.
|
|
150
|
+
*/
|
|
106
151
|
group?: number;
|
|
107
152
|
sysexHandle?: number;
|
|
108
153
|
data0?: number;
|
|
@@ -119,6 +164,20 @@ export interface EngineMidiClipSchedule {
|
|
|
119
164
|
loop?: boolean;
|
|
120
165
|
loopLengthSamples?: number;
|
|
121
166
|
events: EngineMidiEvent[];
|
|
167
|
+
/**
|
|
168
|
+
* Linear gain applied to the destination instrument's rendered audio while
|
|
169
|
+
* this clip is the most recently started active clip on it. Absent defaults
|
|
170
|
+
* to `1` (unity).
|
|
171
|
+
*/
|
|
172
|
+
gain?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Linear fade lengths over the clip's full length (not per internal loop
|
|
175
|
+
* repeat). Absent defaults to `0` (no fade). `fadeOutSamples` above `0` is
|
|
176
|
+
* rejected when `lengthSamples` is absent or `<= 0` (open-ended): an
|
|
177
|
+
* open-ended clip has no end to fade out towards.
|
|
178
|
+
*/
|
|
179
|
+
fadeInSamples?: number;
|
|
180
|
+
fadeOutSamples?: number;
|
|
122
181
|
}
|
|
123
182
|
|
|
124
183
|
export const EXPECTED_ENGINE_ABI_VERSION = 3;
|
|
@@ -131,6 +190,76 @@ export interface MidiCcBindOptions {
|
|
|
131
190
|
maxValue?: number;
|
|
132
191
|
}
|
|
133
192
|
|
|
193
|
+
/** Request form of {@link RealtimeEngine.renderOffline}. */
|
|
194
|
+
export interface RenderOfflineRequest {
|
|
195
|
+
/** One buffer per output plane; their common length is the render span. */
|
|
196
|
+
channels: Float32Array[];
|
|
197
|
+
/** Render block size. Default `128`. */
|
|
198
|
+
blockSize?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Whether this call ends the timeline. `true` (the default, and what a
|
|
201
|
+
* one-shot bounce wants) releases every sounding note and flushes the PDC /
|
|
202
|
+
* alignment delay lines before returning. `false` renders one CHUNK of a
|
|
203
|
+
* longer timeline: a note held across the chunk boundary keeps sounding into
|
|
204
|
+
* the next call and the delay lines carry their history over, so consecutive
|
|
205
|
+
* chunks concatenate to exactly what one continuous render of the same span
|
|
206
|
+
* produces. Call {@link RealtimeEngine.finishOfflineRender} once after the
|
|
207
|
+
* last chunk.
|
|
208
|
+
*
|
|
209
|
+
* Sample-exact concatenation requires every chunk to use the same `blockSize`
|
|
210
|
+
* and a frame count that is a whole number of blocks: each call restarts the
|
|
211
|
+
* block grid at its own frame 0 and renders a short final block for the
|
|
212
|
+
* remainder, and the clip / automation / MIDI-clip snapshots are frozen once
|
|
213
|
+
* per block, so a chunk that ends mid-block shifts every later block
|
|
214
|
+
* boundary. Audio stays continuous either way; only bit-identity is lost.
|
|
215
|
+
*/
|
|
216
|
+
finalize?: boolean;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const UMP_WORD_MIN = -0x80000000;
|
|
220
|
+
const UMP_WORD_MAX = 0xffffffff;
|
|
221
|
+
|
|
222
|
+
// A word may be spelled `(0x4 << 28) | …`, which is a signed int once bit 31 is
|
|
223
|
+
// set, so the signed 32-bit range is accepted alongside the unsigned one.
|
|
224
|
+
function assertUmpWords(fnName: string, words: UmpWords): UmpWords {
|
|
225
|
+
if (!(words instanceof Uint32Array) && !Array.isArray(words)) {
|
|
226
|
+
throw new TypeError(`${fnName}: words must be a Uint32Array or a number array`);
|
|
227
|
+
}
|
|
228
|
+
if (words.length < 1 || words.length > 4) {
|
|
229
|
+
throw new RangeError(`${fnName}: words must hold 1 to 4 words`);
|
|
230
|
+
}
|
|
231
|
+
for (let i = 0; i < words.length; i++) {
|
|
232
|
+
const word = words[i];
|
|
233
|
+
if (
|
|
234
|
+
typeof word !== 'number' ||
|
|
235
|
+
!Number.isInteger(word) ||
|
|
236
|
+
word < UMP_WORD_MIN ||
|
|
237
|
+
word > UMP_WORD_MAX
|
|
238
|
+
) {
|
|
239
|
+
throw new RangeError(`${fnName}: words[${i}] must be an integer 32-bit word`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return words;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* One normalizer for both call forms, so the request object and the positional
|
|
247
|
+
* overload cannot drift in their defaults.
|
|
248
|
+
*/
|
|
249
|
+
function normalizeRenderOfflineRequest(
|
|
250
|
+
channelsOrRequest: Float32Array[] | RenderOfflineRequest,
|
|
251
|
+
blockSize: number,
|
|
252
|
+
): { channels: Float32Array[]; blockSize: number; finalize: boolean } {
|
|
253
|
+
const request = Array.isArray(channelsOrRequest)
|
|
254
|
+
? { channels: channelsOrRequest, blockSize }
|
|
255
|
+
: channelsOrRequest;
|
|
256
|
+
return {
|
|
257
|
+
channels: request.channels,
|
|
258
|
+
blockSize: request.blockSize ?? 128,
|
|
259
|
+
finalize: request.finalize ?? true,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
134
263
|
export interface EngineCapabilities {
|
|
135
264
|
engineAbiVersion: number;
|
|
136
265
|
expectedEngineAbiVersion: number;
|
|
@@ -162,6 +291,7 @@ export function engineCapabilities(): EngineCapabilities {
|
|
|
162
291
|
|
|
163
292
|
export class RealtimeEngine {
|
|
164
293
|
private native: WasmRealtimeEngine;
|
|
294
|
+
private released = false;
|
|
165
295
|
|
|
166
296
|
constructor(
|
|
167
297
|
sampleRate = 48000,
|
|
@@ -186,6 +316,15 @@ export class RealtimeEngine {
|
|
|
186
316
|
);
|
|
187
317
|
}
|
|
188
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Size the engine's queues and scratch for a sample rate and block size.
|
|
321
|
+
*
|
|
322
|
+
* `commandCapacity` must not exceed 65536 and `telemetryCapacity` must not
|
|
323
|
+
* exceed 16384; a larger value throws and leaves the engine untouched. The
|
|
324
|
+
* telemetry number is not a queue depth paid for one-for-one: the engine
|
|
325
|
+
* reserves that many meter records per metered lane, so its memory cost is
|
|
326
|
+
* far larger than the number given here.
|
|
327
|
+
*/
|
|
189
328
|
prepare(
|
|
190
329
|
sampleRate: number,
|
|
191
330
|
maxBlockSize: number,
|
|
@@ -249,12 +388,16 @@ export class RealtimeEngine {
|
|
|
249
388
|
* scheduled MIDI clips routed to that destination render through the synth.
|
|
250
389
|
* Unknown preset names throw. An object patch's `destinationId` is a JS
|
|
251
390
|
* binding convenience, not part of the NativeSynth patch itself.
|
|
391
|
+
*
|
|
392
|
+
* An `engineMode: 'sample'` patch also carries the {@link SampleBank} its
|
|
393
|
+
* keymap names. The synth takes a share of the bank, so it may be released
|
|
394
|
+
* right after this call; a sample patch bound without one renders silence.
|
|
252
395
|
*/
|
|
253
396
|
setSynthInstrument(
|
|
254
397
|
patch: SynthPatch | string = {},
|
|
255
398
|
destinationId = (typeof patch === 'object' ? patch.destinationId : undefined) ?? 0,
|
|
256
399
|
): void {
|
|
257
|
-
this.native.setSynthInstrument(destinationId, patch);
|
|
400
|
+
this.native.setSynthInstrument(destinationId, normalizeSynthInstrument(patch));
|
|
258
401
|
}
|
|
259
402
|
|
|
260
403
|
/**
|
|
@@ -282,6 +425,8 @@ export class RealtimeEngine {
|
|
|
282
425
|
gain?: number;
|
|
283
426
|
polyphony?: number;
|
|
284
427
|
preferModelForModeledFamilies?: boolean;
|
|
428
|
+
clearBankRig?: boolean;
|
|
429
|
+
gsEfxRealization?: 'modern' | 'classic';
|
|
285
430
|
} = {},
|
|
286
431
|
destinationId = config.destinationId ?? 0,
|
|
287
432
|
): void {
|
|
@@ -329,6 +474,135 @@ export class RealtimeEngine {
|
|
|
329
474
|
return this.native.midiCcBindingCount();
|
|
330
475
|
}
|
|
331
476
|
|
|
477
|
+
/**
|
|
478
|
+
* Replace a destination instrument's controller profile with a named preset
|
|
479
|
+
* (see {@link controllerProfileNames}). Installing a profile drops every
|
|
480
|
+
* channel's accumulated axis values: the new bindings say nothing about what
|
|
481
|
+
* the old ones had reached. An unknown name throws, and so does a destination
|
|
482
|
+
* with no instrument or one whose instrument holds no profile.
|
|
483
|
+
*/
|
|
484
|
+
setControllerProfile(destinationId: number, presetName: string): void {
|
|
485
|
+
this.native.setControllerProfile(destinationId, presetName);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** Add one {@link ControllerBinding} on top of the destination's current profile. */
|
|
489
|
+
bindController(destinationId: number, binding: ControllerBinding): void {
|
|
490
|
+
this.native.bindController(destinationId, binding);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Drop every binding of the destination's controller profile. The instrument
|
|
495
|
+
* keeps a profile; it resolves nothing until something is bound again.
|
|
496
|
+
*/
|
|
497
|
+
clearControllerBindings(destinationId: number): void {
|
|
498
|
+
this.native.clearControllerBindings(destinationId);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
controllerBindingCount(destinationId: number): number {
|
|
502
|
+
return this.native.controllerBindingCount(destinationId);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Whether note-on velocity is expression for this instrument. No fixed
|
|
507
|
+
* default is possible — a wind controller ships sending breath-derived
|
|
508
|
+
* velocity on one model and a constant on the next — so each preset states it
|
|
509
|
+
* and a host building its own profile sets it. When false the synth takes
|
|
510
|
+
* every note at full scale and the bound axes carry the dynamics alone.
|
|
511
|
+
*/
|
|
512
|
+
setControllerVelocityMeaningful(destinationId: number, meaningful: boolean): void {
|
|
513
|
+
this.native.setControllerVelocityMeaningful(destinationId, meaningful);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
controllerVelocityMeaningful(destinationId: number): boolean {
|
|
517
|
+
return this.native.controllerVelocityMeaningful(destinationId);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Say which note a value addressed to a whole MIDI channel belongs to when
|
|
522
|
+
* several are sounding on it, for one per-note dimension
|
|
523
|
+
* ({@link MPE_DIMENSIONS}, {@link NOTE_TRACKINGS}).
|
|
524
|
+
*
|
|
525
|
+
* Set per dimension because the useful answers differ: pressure following the
|
|
526
|
+
* newest note while bend reaches every one is a real configuration, not a
|
|
527
|
+
* mistake. MPE poses this question and declines to answer it, so this is a
|
|
528
|
+
* choice rather than a rule — and it is read only inside an MPE zone, and
|
|
529
|
+
* only while more than one note is sounding on the channel, which an MPE
|
|
530
|
+
* sender avoids by giving each note its own member channel.
|
|
531
|
+
*
|
|
532
|
+
* Both arguments are required and are a name or its ordinal; an unknown
|
|
533
|
+
* spelling is refused rather than resolved to a default, as are a destination
|
|
534
|
+
* with no instrument and one whose instrument holds no controller profile.
|
|
535
|
+
*/
|
|
536
|
+
setControllerNoteTracking(
|
|
537
|
+
destinationId: number,
|
|
538
|
+
dimension: MpeDimension | number,
|
|
539
|
+
tracking: NoteTracking | number,
|
|
540
|
+
): void {
|
|
541
|
+
this.native.setControllerNoteTracking(destinationId, dimension, tracking);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Read back {@link setControllerNoteTracking} for one dimension, as the
|
|
546
|
+
* canonical name.
|
|
547
|
+
*/
|
|
548
|
+
controllerNoteTracking(
|
|
549
|
+
destinationId: number,
|
|
550
|
+
dimension: MpeDimension | number,
|
|
551
|
+
): NoteTracking | number {
|
|
552
|
+
return this.native.controllerNoteTracking(destinationId, dimension);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Set how one MIDI channel (0–15) of a destination's instrument treats a
|
|
557
|
+
* note-on while another note on that channel is still held: `'poly'` takes a
|
|
558
|
+
* new voice each time, `'mono-retrigger'` stops and restarts the note (what
|
|
559
|
+
* GS MONO MODE and CC126 mean), `'mono-legato'` carries the sounding voice
|
|
560
|
+
* and only moves its pitch — a wind player's slur, which no MIDI message can
|
|
561
|
+
* reach by design.
|
|
562
|
+
*
|
|
563
|
+
* `'mono-legato'` is a request, not a guarantee: an engine whose exciter is
|
|
564
|
+
* spent at the onset — anything struck or plucked — and a target pitch below
|
|
565
|
+
* what the engine's delay line can hold both fall back to an ordinary note,
|
|
566
|
+
* which {@link legatoFallbackCount} counts. A channel outside [0,15] and an
|
|
567
|
+
* articulation outside the enum are refused rather than clamped, and so is a
|
|
568
|
+
* destination with no instrument or one whose instrument has no articulation
|
|
569
|
+
* of its own.
|
|
570
|
+
*/
|
|
571
|
+
setArticulation(
|
|
572
|
+
destinationId: number,
|
|
573
|
+
channel: number,
|
|
574
|
+
articulation: Articulation | number,
|
|
575
|
+
): void {
|
|
576
|
+
this.native.setArticulation(destinationId, channel, articulation);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Read back {@link setArticulation} as the canonical name. An ordinal this
|
|
581
|
+
* build cannot spell is handed back as the number, the way every other enum
|
|
582
|
+
* leaves this surface.
|
|
583
|
+
*/
|
|
584
|
+
articulation(destinationId: number, channel: number): Articulation | number {
|
|
585
|
+
return this.native.articulation(destinationId, channel);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* How many times a legato continuation was asked for on this destination and
|
|
590
|
+
* refused, so the note started a voice of its own instead. Counted rather
|
|
591
|
+
* than inferred: a refusal sounds like an ordinary note, so nothing in the
|
|
592
|
+
* audio separates "this engine declines legato" from "the mode was never
|
|
593
|
+
* set". Saturates at 4294967295 rather than wrapping — matching the C ABI, so
|
|
594
|
+
* the same phrase reports the same number on every surface — after which it
|
|
595
|
+
* reads as "at least this many".
|
|
596
|
+
*
|
|
597
|
+
* Throws on a destination with no instrument, and on one whose instrument has
|
|
598
|
+
* no articulation of its own — the same two refusals
|
|
599
|
+
* {@link setArticulation} keeps apart. Reporting 0 for the second would read
|
|
600
|
+
* as "every slur took", which is the reading this counter exists to prevent.
|
|
601
|
+
*/
|
|
602
|
+
legatoFallbackCount(destinationId: number): number {
|
|
603
|
+
return this.native.legatoFallbackCount(destinationId);
|
|
604
|
+
}
|
|
605
|
+
|
|
332
606
|
/** Install/replace a live non-destructive MIDI-FX insert for one destination. */
|
|
333
607
|
setMidiFx(destinationId: number, configJson: string): void {
|
|
334
608
|
this.native.setMidiFx(destinationId, configJson);
|
|
@@ -354,7 +628,10 @@ export class RealtimeEngine {
|
|
|
354
628
|
/**
|
|
355
629
|
* Route a destination's (track lane's) MIDI to the external output queue
|
|
356
630
|
* instead of the internal instrument rack, so the track plays an external
|
|
357
|
-
* device. Clearing it restores internal-synth playback.
|
|
631
|
+
* device. Clearing it restores internal-synth playback. Control-thread only.
|
|
632
|
+
* The change takes effect at the next processed block; switching a
|
|
633
|
+
* destination's route first releases its notes and resets its controllers
|
|
634
|
+
* through the old route, and drops its pending MIDI-FX events. Single writer.
|
|
358
635
|
*/
|
|
359
636
|
setMidiDestinationExternal(destinationId: number, external: boolean): void {
|
|
360
637
|
this.native.setMidiDestinationExternal(destinationId, external);
|
|
@@ -383,6 +660,12 @@ export class RealtimeEngine {
|
|
|
383
660
|
* block / animation frame. `maxRecords` caps the number of output events
|
|
384
661
|
* returned — the shared unit across every surface. Events past the cap stay
|
|
385
662
|
* queued for the next call (lossless); call again to drain the rest.
|
|
663
|
+
*
|
|
664
|
+
* One queued record lowers to at most 4 MIDI 1.0 messages (a MIDI 2.0
|
|
665
|
+
* registered or assignable controller becomes CC 101/100 or 99/98 plus Data
|
|
666
|
+
* Entry 6/38), so a positive `maxRecords` below 4 could never consume a record
|
|
667
|
+
* and is rejected with an `InvalidParameter` `SonareError` instead of
|
|
668
|
+
* returning nothing forever.
|
|
386
669
|
*/
|
|
387
670
|
drainExternalMidi(maxRecords = 1024): WasmExternalMidiEvent[] {
|
|
388
671
|
return this.native.drainExternalMidi(maxRecords);
|
|
@@ -398,7 +681,11 @@ export class RealtimeEngine {
|
|
|
398
681
|
}
|
|
399
682
|
|
|
400
683
|
externalMidiScratchRenderFrame(): number {
|
|
401
|
-
|
|
684
|
+
// embind marshals the int64 render frame as a BigInt; the declared `number`
|
|
685
|
+
// has to be a real number or the first consumer that does arithmetic on it
|
|
686
|
+
// dies with "Cannot mix BigInt". Same normalization as the telemetry, meter
|
|
687
|
+
// and scope scratch frames.
|
|
688
|
+
return Number(this.native.externalMidiScratchRenderFrame());
|
|
402
689
|
}
|
|
403
690
|
|
|
404
691
|
externalMidiScratchByteWord(): number {
|
|
@@ -443,6 +730,50 @@ export class RealtimeEngine {
|
|
|
443
730
|
this.native.pushMidiInputCc(group, channel, controller, value, portTimeSamples);
|
|
444
731
|
}
|
|
445
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Push a live MIDI pitch bend to the engine-owned MIDI input source.
|
|
735
|
+
*
|
|
736
|
+
* `bend14` is unsigned 14-bit with centre 8192 (0..16383) — the dimension is
|
|
737
|
+
* not 7-bit, so a value past 16383 is refused rather than narrowed. The input
|
|
738
|
+
* source must be enabled with {@link setMidiInputSource} first.
|
|
739
|
+
*/
|
|
740
|
+
pushMidiInputPitchBend(
|
|
741
|
+
group: number,
|
|
742
|
+
channel: number,
|
|
743
|
+
bend14: number,
|
|
744
|
+
portTimeSamples = 0,
|
|
745
|
+
): void {
|
|
746
|
+
this.native.pushMidiInputPitchBend(group, channel, bend14, portTimeSamples);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Push a live MIDI channel pressure to the engine-owned MIDI input source.
|
|
751
|
+
* `pressure` is 7-bit (0..127). Under MPE this is the member channel's
|
|
752
|
+
* per-note pressure.
|
|
753
|
+
*/
|
|
754
|
+
pushMidiInputChannelPressure(
|
|
755
|
+
group: number,
|
|
756
|
+
channel: number,
|
|
757
|
+
pressure: number,
|
|
758
|
+
portTimeSamples = 0,
|
|
759
|
+
): void {
|
|
760
|
+
this.native.pushMidiInputChannelPressure(group, channel, pressure, portTimeSamples);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Push a live MIDI polyphonic key pressure to the engine-owned MIDI input
|
|
765
|
+
* source. `note` and `pressure` are 7-bit (0..127).
|
|
766
|
+
*/
|
|
767
|
+
pushMidiInputPolyPressure(
|
|
768
|
+
group: number,
|
|
769
|
+
channel: number,
|
|
770
|
+
note: number,
|
|
771
|
+
pressure: number,
|
|
772
|
+
portTimeSamples = 0,
|
|
773
|
+
): void {
|
|
774
|
+
this.native.pushMidiInputPolyPressure(group, channel, note, pressure, portTimeSamples);
|
|
775
|
+
}
|
|
776
|
+
|
|
446
777
|
pushMidiNoteOn(
|
|
447
778
|
destinationId: number,
|
|
448
779
|
group: number,
|
|
@@ -482,16 +813,86 @@ export class RealtimeEngine {
|
|
|
482
813
|
this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
|
|
483
814
|
}
|
|
484
815
|
|
|
485
|
-
/**
|
|
486
|
-
|
|
487
|
-
|
|
816
|
+
/**
|
|
817
|
+
* Queue an immediate (live) MIDI pitch bend to a MIDI destination. `bend14`
|
|
818
|
+
* is unsigned 14-bit with centre 8192 (0..16383); `renderFrame` is the frame
|
|
819
|
+
* to fire at, or -1 for immediate. Mirrors the Node/Python/C-ABI
|
|
820
|
+
* `pushMidiPitchBend`.
|
|
821
|
+
*/
|
|
822
|
+
pushMidiPitchBend(
|
|
823
|
+
destinationId: number,
|
|
824
|
+
group: number,
|
|
825
|
+
channel: number,
|
|
826
|
+
bend14: number,
|
|
827
|
+
renderFrame = -1,
|
|
828
|
+
): void {
|
|
829
|
+
this.native.pushMidiPitchBend(destinationId, group, channel, bend14, renderFrame);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Queue an immediate (live) MIDI channel pressure to a MIDI destination.
|
|
834
|
+
* `pressure` is 7-bit (0..127); `renderFrame` is the frame to fire at, or -1
|
|
835
|
+
* for immediate. Mirrors the Node/Python/C-ABI `pushMidiChannelPressure`.
|
|
836
|
+
*/
|
|
837
|
+
pushMidiChannelPressure(
|
|
838
|
+
destinationId: number,
|
|
839
|
+
group: number,
|
|
840
|
+
channel: number,
|
|
841
|
+
pressure: number,
|
|
842
|
+
renderFrame = -1,
|
|
843
|
+
): void {
|
|
844
|
+
this.native.pushMidiChannelPressure(destinationId, group, channel, pressure, renderFrame);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Queue an immediate (live) MIDI polyphonic key pressure to a MIDI
|
|
849
|
+
* destination. `note` and `pressure` are 7-bit (0..127); `renderFrame` is the
|
|
850
|
+
* frame to fire at, or -1 for immediate. Mirrors the Node/Python/C-ABI
|
|
851
|
+
* `pushMidiPolyPressure`.
|
|
852
|
+
*/
|
|
853
|
+
pushMidiPolyPressure(
|
|
854
|
+
destinationId: number,
|
|
855
|
+
group: number,
|
|
856
|
+
channel: number,
|
|
857
|
+
note: number,
|
|
858
|
+
pressure: number,
|
|
859
|
+
renderFrame = -1,
|
|
860
|
+
): void {
|
|
861
|
+
this.native.pushMidiPolyPressure(destinationId, group, channel, note, pressure, renderFrame);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Queue an immediate (live) raw UMP message to a MIDI destination. `words` is
|
|
866
|
+
* 1 to 4 words, most significant first, and its length must match the message
|
|
867
|
+
* type of `words[0]`. MIDI 2.0 channel-voice messages (MT 0x4) arrive at full
|
|
868
|
+
* width; SysEx7 / data messages (MT 0x3 / 0x5) are refused, use
|
|
869
|
+
* {@link pushMidiSysex}. Throws when the slot ring or command queue is full
|
|
870
|
+
* (retry after a process block). `renderFrame` is the render-frame time to
|
|
871
|
+
* apply, or -1 for immediate. A bare number is accepted as a one-word
|
|
872
|
+
* message.
|
|
873
|
+
*/
|
|
874
|
+
pushMidiUmp(destinationId: number, words: UmpWords | number, renderFrame = -1): void {
|
|
875
|
+
const list = typeof words === 'number' ? [words] : words;
|
|
876
|
+
this.native.pushMidiUmp(destinationId, assertUmpWords('pushMidiUmp', list), renderFrame);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Push one raw UMP message (1 to 4 words) to the engine-owned MIDI input
|
|
881
|
+
* source. The message rules match {@link pushMidiUmp}. `portTimeSamples` is
|
|
882
|
+
* the port timestamp in samples.
|
|
883
|
+
*/
|
|
884
|
+
pushMidiInputUmp(words: UmpWords, portTimeSamples = 0): void {
|
|
885
|
+
this.native.pushMidiInputUmp(assertUmpWords('pushMidiInputUmp', words), portTimeSamples);
|
|
488
886
|
}
|
|
489
887
|
|
|
490
888
|
/**
|
|
491
889
|
* Queue an immediate (live) MIDI SysEx frame to a MIDI destination. `data` is
|
|
492
890
|
* the full message including the leading 0xF0 and trailing 0xF7 (1..512
|
|
493
|
-
* bytes). `renderFrame` is the frame to fire at, or -1 for immediate.
|
|
494
|
-
* the
|
|
891
|
+
* bytes). `renderFrame` is the frame to fire at, or -1 for immediate. Throws
|
|
892
|
+
* `InvalidParameter` when the destination instrument cannot prepare
|
|
893
|
+
* the SysEx (retrying cannot help), and `OutOfMemory` when the payload
|
|
894
|
+
* slots or the command queue are full (retry after a processed block).
|
|
895
|
+
* Mirrors the Node/Python/C-ABI `pushMidiSysex`.
|
|
495
896
|
*/
|
|
496
897
|
pushMidiSysex(destinationId: number, data: Uint8Array, renderFrame = -1): void {
|
|
497
898
|
this.native.pushMidiSysex(destinationId, data, renderFrame);
|
|
@@ -518,14 +919,34 @@ export class RealtimeEngine {
|
|
|
518
919
|
return this.native.getTransportState();
|
|
519
920
|
}
|
|
520
921
|
|
|
922
|
+
/** Queues an integrated-loudness reset; short-term and momentary windows are retained. */
|
|
923
|
+
resetMasterLoudnessMeter(renderFrame = -1): void {
|
|
924
|
+
this.native.resetMasterLoudnessMeter(renderFrame);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/** Reads the immutable factory value for a resolved insert parameter id. */
|
|
928
|
+
insertParameterConstructedValue(paramId: number): number {
|
|
929
|
+
return this.native.insertParameterConstructedValue(paramId);
|
|
930
|
+
}
|
|
931
|
+
|
|
521
932
|
play(renderFrame = -1): void {
|
|
522
933
|
this.native.play(renderFrame);
|
|
523
934
|
}
|
|
524
935
|
|
|
936
|
+
/**
|
|
937
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
938
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
939
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
940
|
+
*/
|
|
525
941
|
stop(renderFrame = -1): void {
|
|
526
942
|
this.native.stop(renderFrame);
|
|
527
943
|
}
|
|
528
944
|
|
|
945
|
+
/**
|
|
946
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
947
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
948
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
949
|
+
*/
|
|
529
950
|
seekSample(timelineSample: number, renderFrame = -1): void {
|
|
530
951
|
this.native.seekSample(timelineSample, renderFrame);
|
|
531
952
|
}
|
|
@@ -540,11 +961,26 @@ export class RealtimeEngine {
|
|
|
540
961
|
this.native.settleParameters();
|
|
541
962
|
}
|
|
542
963
|
|
|
964
|
+
/** Snap only insert automation slots after structural replay. */
|
|
965
|
+
settleInsertParameters(): void {
|
|
966
|
+
this.native.settleInsertParameters();
|
|
967
|
+
}
|
|
968
|
+
|
|
543
969
|
/** Drains queued commands on an offline/control-only engine immediately. */
|
|
544
970
|
flushControlCommands(): void {
|
|
545
971
|
this.native.flushControlCommands();
|
|
546
972
|
}
|
|
547
973
|
|
|
974
|
+
/** Applies commands already due on a control-only mirror, retaining future commands. */
|
|
975
|
+
applyCommandsDueNowPreservingFuture(): void {
|
|
976
|
+
this.native.applyCommandsDueNowPreservingFuture();
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
981
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
982
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
983
|
+
*/
|
|
548
984
|
seekPpq(ppq: number, renderFrame = -1): void {
|
|
549
985
|
this.native.seekPpq(ppq, renderFrame);
|
|
550
986
|
}
|
|
@@ -570,6 +1006,11 @@ export class RealtimeEngine {
|
|
|
570
1006
|
return Number(this.native.sampleAtPpq(ppq));
|
|
571
1007
|
}
|
|
572
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
1011
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
1012
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
1013
|
+
*/
|
|
573
1014
|
setLoop(startPpq: number, endPpq: number, enabled = true): void {
|
|
574
1015
|
this.native.setLoop(startPpq, endPpq, enabled);
|
|
575
1016
|
}
|
|
@@ -582,11 +1023,11 @@ export class RealtimeEngine {
|
|
|
582
1023
|
return this.native.parameterCount();
|
|
583
1024
|
}
|
|
584
1025
|
|
|
585
|
-
parameterInfoByIndex(index: number): EngineParameterInfo {
|
|
1026
|
+
parameterInfoByIndex(index: number): Required<EngineParameterInfo> {
|
|
586
1027
|
return this.native.parameterInfoByIndex(index);
|
|
587
1028
|
}
|
|
588
1029
|
|
|
589
|
-
parameterInfo(id: number): EngineParameterInfo {
|
|
1030
|
+
parameterInfo(id: number): Required<EngineParameterInfo> {
|
|
590
1031
|
return this.native.parameterInfo(id);
|
|
591
1032
|
}
|
|
592
1033
|
|
|
@@ -671,24 +1112,28 @@ export class RealtimeEngine {
|
|
|
671
1112
|
return this.native.clipCount();
|
|
672
1113
|
}
|
|
673
1114
|
|
|
1115
|
+
/**
|
|
1116
|
+
* Normalizes each send's pre/post tap point to the integer the native layer
|
|
1117
|
+
* reads (defaults to post-fader when omitted). Shared by track lanes and
|
|
1118
|
+
* buses, which carry the same send shape.
|
|
1119
|
+
*/
|
|
1120
|
+
private static normalizeSends(sends: EngineTrackSend[]): WasmEngineTrackSend[] {
|
|
1121
|
+
return sends.map((send) => ({
|
|
1122
|
+
...send,
|
|
1123
|
+
// Post-fader (0) is the default for an omitted sendTiming.
|
|
1124
|
+
sendTiming: send.sendTiming === undefined ? 0 : sendTimingCode(send.sendTiming),
|
|
1125
|
+
}));
|
|
1126
|
+
}
|
|
1127
|
+
|
|
674
1128
|
setTrackLanes(lanes: Array<number | EngineTrackLane>): void {
|
|
675
1129
|
this.native.setTrackLanes(
|
|
676
1130
|
lanes.map((lane) => {
|
|
677
1131
|
if (typeof lane === 'number') {
|
|
678
1132
|
return { trackId: lane };
|
|
679
1133
|
}
|
|
680
|
-
if (!lane.sends) {
|
|
681
|
-
return lane;
|
|
682
|
-
}
|
|
683
|
-
// Normalize each send's pre/post tap point to the integer the native
|
|
684
|
-
// layer reads (defaults to post-fader when omitted).
|
|
685
1134
|
return {
|
|
686
1135
|
...lane,
|
|
687
|
-
sends: lane.sends.
|
|
688
|
-
...send,
|
|
689
|
-
// Post-fader (0) is the default for an omitted sendTiming.
|
|
690
|
-
sendTiming: send.sendTiming === undefined ? 0 : sendTimingCode(send.sendTiming),
|
|
691
|
-
})),
|
|
1136
|
+
sends: lane.sends ? RealtimeEngine.normalizeSends(lane.sends) : undefined,
|
|
692
1137
|
};
|
|
693
1138
|
}),
|
|
694
1139
|
);
|
|
@@ -703,7 +1148,43 @@ export class RealtimeEngine {
|
|
|
703
1148
|
}
|
|
704
1149
|
|
|
705
1150
|
setTrackBuses(buses: EngineBus[]): void {
|
|
706
|
-
|
|
1151
|
+
// Array.isArray guards a caller-fabricated array-like (e.g. `{ length }`)
|
|
1152
|
+
// meant to probe the native array-length read: passing it through
|
|
1153
|
+
// unmodified lets that guard see the real (missing) length rather than
|
|
1154
|
+
// failing here on a `.map` that array-likes do not implement.
|
|
1155
|
+
this.native.setTrackBuses(
|
|
1156
|
+
Array.isArray(buses)
|
|
1157
|
+
? buses.map((bus) => ({
|
|
1158
|
+
...bus,
|
|
1159
|
+
sends: bus.sends ? RealtimeEngine.normalizeSends(bus.sends) : undefined,
|
|
1160
|
+
}))
|
|
1161
|
+
: (buses as WasmEngineBus[]),
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Keys one insert of a bus strip from a track lane or another bus
|
|
1167
|
+
* (ducking/sidechainRouter inserts). `sourceId` 0 removes the binding.
|
|
1168
|
+
*/
|
|
1169
|
+
setBusSidechain(
|
|
1170
|
+
busId: number,
|
|
1171
|
+
insertIndex: number,
|
|
1172
|
+
sourceKind: SidechainSourceKind | number,
|
|
1173
|
+
sourceId: number,
|
|
1174
|
+
): void {
|
|
1175
|
+
this.native.setBusSidechain(busId, insertIndex, sidechainSourceKindCode(sourceKind), sourceId);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Keys one insert of the master strip from a track lane or a bus. Same
|
|
1180
|
+
* source rules as {@link setBusSidechain}.
|
|
1181
|
+
*/
|
|
1182
|
+
setMasterSidechain(
|
|
1183
|
+
insertIndex: number,
|
|
1184
|
+
sourceKind: SidechainSourceKind | number,
|
|
1185
|
+
sourceId: number,
|
|
1186
|
+
): void {
|
|
1187
|
+
this.native.setMasterSidechain(insertIndex, sidechainSourceKindCode(sourceKind), sourceId);
|
|
707
1188
|
}
|
|
708
1189
|
|
|
709
1190
|
setBusStripJson(busId: number, sceneJson: string): void {
|
|
@@ -747,6 +1228,19 @@ export class RealtimeEngine {
|
|
|
747
1228
|
this.native.setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass);
|
|
748
1229
|
}
|
|
749
1230
|
|
|
1231
|
+
/** Bus-strip counterpart of {@link setTrackStripEqBand}. */
|
|
1232
|
+
setBusStripEqBand(busId: number, bandIndex: number, band: EqBand | string): void {
|
|
1233
|
+
this.native.setBusStripEqBandJson(
|
|
1234
|
+
busId,
|
|
1235
|
+
bandIndex,
|
|
1236
|
+
typeof band === 'string' ? band : JSON.stringify(band),
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
setBusStripEqBandJson(busId: number, bandIndex: number, bandJson: string): void {
|
|
1241
|
+
this.native.setBusStripEqBandJson(busId, bandIndex, bandJson);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
750
1244
|
setMasterStripJson(sceneJson: string): void {
|
|
751
1245
|
try {
|
|
752
1246
|
JSON.parse(sceneJson);
|
|
@@ -778,10 +1272,12 @@ export class RealtimeEngine {
|
|
|
778
1272
|
|
|
779
1273
|
/**
|
|
780
1274
|
* Changes one track-strip insert parameter in realtime, addressed by the
|
|
781
|
-
* processor's JSON-key parameter name
|
|
782
|
-
*
|
|
783
|
-
*
|
|
784
|
-
*
|
|
1275
|
+
* processor's JSON-key parameter name — one of the entries
|
|
1276
|
+
* {@link masteringInsertParamInfo} reports with a non-null `id`; a
|
|
1277
|
+
* construction-only entry (`id` null) takes effect only when the insert is
|
|
1278
|
+
* built. Applied at the next block head via the engine command queue; safe
|
|
1279
|
+
* during playback. Throws if the track, insert, or name is unknown, the
|
|
1280
|
+
* param is not realtime-safe, or the command queue is full.
|
|
785
1281
|
*/
|
|
786
1282
|
setTrackStripInsertParamByName(
|
|
787
1283
|
trackId: number,
|
|
@@ -792,11 +1288,43 @@ export class RealtimeEngine {
|
|
|
792
1288
|
this.native.setTrackStripInsertParamByName(trackId, insertIndex, paramName, value);
|
|
793
1289
|
}
|
|
794
1290
|
|
|
1291
|
+
/** Apply a live insert edit on this engine's owning thread without draining its command queue. */
|
|
1292
|
+
applyTrackStripInsertParamByNameNow(
|
|
1293
|
+
trackId: number,
|
|
1294
|
+
insertIndex: number,
|
|
1295
|
+
paramName: string,
|
|
1296
|
+
value: number,
|
|
1297
|
+
): boolean {
|
|
1298
|
+
return this.native.applyTrackStripInsertParamByNameNow(trackId, insertIndex, paramName, value);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
/** Restore a retained insert value exactly after a strip scene is replayed. */
|
|
1302
|
+
restoreTrackStripInsertParamByName(
|
|
1303
|
+
trackId: number,
|
|
1304
|
+
insertIndex: number,
|
|
1305
|
+
paramName: string,
|
|
1306
|
+
value: number,
|
|
1307
|
+
): void {
|
|
1308
|
+
this.native.restoreTrackStripInsertParamByName(trackId, insertIndex, paramName, value);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
795
1311
|
/** Master-strip counterpart of {@link setTrackStripInsertParamByName}. */
|
|
796
1312
|
setMasterStripInsertParamByName(insertIndex: number, paramName: string, value: number): void {
|
|
797
1313
|
this.native.setMasterStripInsertParamByName(insertIndex, paramName, value);
|
|
798
1314
|
}
|
|
799
1315
|
|
|
1316
|
+
applyMasterStripInsertParamByNameNow(
|
|
1317
|
+
insertIndex: number,
|
|
1318
|
+
paramName: string,
|
|
1319
|
+
value: number,
|
|
1320
|
+
): boolean {
|
|
1321
|
+
return this.native.applyMasterStripInsertParamByNameNow(insertIndex, paramName, value);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
restoreMasterStripInsertParamByName(insertIndex: number, paramName: string, value: number): void {
|
|
1325
|
+
this.native.restoreMasterStripInsertParamByName(insertIndex, paramName, value);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
800
1328
|
/** Bus-strip counterpart of {@link setTrackStripInsertParamByName}. */
|
|
801
1329
|
setBusStripInsertParamByName(
|
|
802
1330
|
busId: number,
|
|
@@ -807,6 +1335,42 @@ export class RealtimeEngine {
|
|
|
807
1335
|
this.native.setBusStripInsertParamByName(busId, insertIndex, paramName, value);
|
|
808
1336
|
}
|
|
809
1337
|
|
|
1338
|
+
applyBusStripInsertParamByNameNow(
|
|
1339
|
+
busId: number,
|
|
1340
|
+
insertIndex: number,
|
|
1341
|
+
paramName: string,
|
|
1342
|
+
value: number,
|
|
1343
|
+
): boolean {
|
|
1344
|
+
return this.native.applyBusStripInsertParamByNameNow(busId, insertIndex, paramName, value);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
restoreBusStripInsertParamByName(
|
|
1348
|
+
busId: number,
|
|
1349
|
+
insertIndex: number,
|
|
1350
|
+
paramName: string,
|
|
1351
|
+
value: number,
|
|
1352
|
+
): void {
|
|
1353
|
+
this.native.restoreBusStripInsertParamByName(busId, insertIndex, paramName, value);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* Forgets the remembered manual insert-parameter values of one track strip
|
|
1358
|
+
* and discards its queued insert edits. Call before {@link setTrackStripJson}
|
|
1359
|
+
* replaces the strip when its old values must not carry over; the setter
|
|
1360
|
+
* never does this itself, since a queued edit may already target the new chain.
|
|
1361
|
+
*/
|
|
1362
|
+
clearTrackInsertParameterBases(trackId: number): void {
|
|
1363
|
+
this.native.clearTrackInsertParameterBases(trackId);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
clearBusInsertParameterBases(busId: number): void {
|
|
1367
|
+
this.native.clearBusInsertParameterBases(busId);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
clearMasterInsertParameterBases(): void {
|
|
1371
|
+
this.native.clearMasterInsertParameterBases();
|
|
1372
|
+
}
|
|
1373
|
+
|
|
810
1374
|
/** Bus-strip counterpart of {@link setTrackStripInsertBypassed}. */
|
|
811
1375
|
setBusStripInsertBypassed(
|
|
812
1376
|
busId: number,
|
|
@@ -832,6 +1396,16 @@ export class RealtimeEngine {
|
|
|
832
1396
|
* stages of the offline mastering chain (`repair.*`, `loudness`, and the
|
|
833
1397
|
* match stages) have no insert form and no automation id: they buffer the
|
|
834
1398
|
* entire signal by construction and do not run on the realtime path.
|
|
1399
|
+
*
|
|
1400
|
+
* The returned id uses the track's current positional lane selector. When
|
|
1401
|
+
* `setTrackLanes` successfully changes lane order or membership, the engine
|
|
1402
|
+
* remaps already queued and published track automation by track id, but it
|
|
1403
|
+
* cannot update a numeric id retained by the caller. Re-resolve every track
|
|
1404
|
+
* insert id after such a topology change before passing it to
|
|
1405
|
+
* `setAutomationLane`, `setParameter`, or `setParameterSmoothed`. Use
|
|
1406
|
+
* `setTrackStripInsertParamByName` when the operation needs a stable track
|
|
1407
|
+
* identity. Master and bus insert ids are separate and are not invalidated by
|
|
1408
|
+
* track-lane changes.
|
|
835
1409
|
*/
|
|
836
1410
|
resolveTrackInsertAutomationId(trackId: number, insertIndex: number, paramName: string): number {
|
|
837
1411
|
return this.native.resolveTrackInsertAutomationId(trackId, insertIndex, paramName);
|
|
@@ -845,6 +1419,42 @@ export class RealtimeEngine {
|
|
|
845
1419
|
return this.native.resolveBusInsertAutomationId(busId, insertIndex, paramName);
|
|
846
1420
|
}
|
|
847
1421
|
|
|
1422
|
+
/**
|
|
1423
|
+
* Resolves a hosted instrument's continuous parameter (by its JSON-key name)
|
|
1424
|
+
* to the reserved automation id usable with `setAutomationLane` /
|
|
1425
|
+
* `setParameter`, so an instrument parameter is driven at audio-block
|
|
1426
|
+
* precision exactly like a strip insert. Returns `-1` when the destination
|
|
1427
|
+
* has no bound instrument, the instrument exposes no automatable parameters,
|
|
1428
|
+
* or the name is unknown.
|
|
1429
|
+
*
|
|
1430
|
+
* For the NativeSynth ({@link setSynthInstrument}) the names are the
|
|
1431
|
+
* continuous {@link SynthPatch} fields: `gain`, `busDrive`, `cutoffHz`,
|
|
1432
|
+
* `resonanceQ`, `drive`, `keyTrack`, `envToCutoffCents`, `velToCutoffCents`,
|
|
1433
|
+
* `ampAttackMs`, `ampDecayMs`, `ampSustain`, `ampReleaseMs`,
|
|
1434
|
+
* `filterAttackMs`, `filterDecayMs`, `filterSustain`, `filterReleaseMs`,
|
|
1435
|
+
* `lfoRateHz`, `lfoToPitchCents`, `lfo2RateHz`, `glideMs`, `bodyMix`,
|
|
1436
|
+
* `stereoSpread`, `detuneCents`, `driftCents`, `pitchOffsetCents`,
|
|
1437
|
+
* `hpCutoffHz`, `sampleHoldHz`, `bitDepth`.
|
|
1438
|
+
*
|
|
1439
|
+
* Structural fields (`preset`, `engineMode`, `waveform`, `filterModel`,
|
|
1440
|
+
* `unison`, `polyphony`, `body`, `modRoutings`) are not automatable and
|
|
1441
|
+
* return `-1`: they resize voice pools or swap DSP topology, which is not
|
|
1442
|
+
* audio-thread safe. Rebind the instrument with a new patch instead.
|
|
1443
|
+
*
|
|
1444
|
+
* `gain`, `busDrive`, `cutoffHz`, `resonanceQ`, `envToCutoffCents`,
|
|
1445
|
+
* `lfoToPitchCents` and `pitchOffsetCents` reach voices that are already
|
|
1446
|
+
* sounding from the next block; the rest are cached into per-voice state at
|
|
1447
|
+
* note-on and take effect from the next note, so a lane that moves one of
|
|
1448
|
+
* them under a held note looks inert until the next one speaks — that is the
|
|
1449
|
+
* behaviour, not a dropped write.
|
|
1450
|
+
*
|
|
1451
|
+
* The id survives an unbind/rebind of the same destination and applies
|
|
1452
|
+
* nothing while that destination is unbound.
|
|
1453
|
+
*/
|
|
1454
|
+
resolveInstrumentAutomationId(destinationId: number, paramName: string): number {
|
|
1455
|
+
return this.native.resolveInstrumentAutomationId(destinationId, paramName);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
848
1458
|
/** Sets a track lane strip's pan position in realtime (glitch-free). */
|
|
849
1459
|
setTrackStripPan(trackId: number, pan: number): void {
|
|
850
1460
|
this.native.setTrackStripPan(trackId, pan);
|
|
@@ -865,6 +1475,29 @@ export class RealtimeEngine {
|
|
|
865
1475
|
this.native.setTrackStripDualPan(trackId, leftPan, rightPan);
|
|
866
1476
|
}
|
|
867
1477
|
|
|
1478
|
+
/**
|
|
1479
|
+
* Sets a bus strip's output pan position in realtime (glitch-free). Throws
|
|
1480
|
+
* for an unknown bus or one wider than stereo.
|
|
1481
|
+
*/
|
|
1482
|
+
setBusStripPan(busId: number, pan: number): void {
|
|
1483
|
+
this.native.setBusStripPan(busId, pan);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
/** Sets a bus strip's pan law in realtime. */
|
|
1487
|
+
setBusStripPanLaw(busId: number, panLaw: PanLawInput): void {
|
|
1488
|
+
this.native.setBusStripPanLaw(busId, panLawCode(panLaw));
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/** Sets a bus strip's pan mode in realtime. */
|
|
1492
|
+
setBusStripPanMode(busId: number, panMode: PanMode | number): void {
|
|
1493
|
+
this.native.setBusStripPanMode(busId, panModeCode(panMode));
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/** Sets a bus strip's dual-pan left/right positions in realtime. */
|
|
1497
|
+
setBusStripDualPan(busId: number, leftPan: number, rightPan: number): void {
|
|
1498
|
+
this.native.setBusStripDualPan(busId, leftPan, rightPan);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
868
1501
|
/**
|
|
869
1502
|
* Sets a track lane strip's inter-channel alignment delay (whole samples).
|
|
870
1503
|
* Adjusts strip latency, so PDC and reported graph latency are refreshed.
|
|
@@ -919,6 +1552,57 @@ export class RealtimeEngine {
|
|
|
919
1552
|
return this.native.clipPageRequestOverflowCount();
|
|
920
1553
|
}
|
|
921
1554
|
|
|
1555
|
+
/** Cumulative warp-stretch requests dropped because the native queue was full. */
|
|
1556
|
+
warpStretchOverflowCount(): number {
|
|
1557
|
+
return this.native.warpStretchOverflowCount();
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/**
|
|
1561
|
+
* Sets the number of concurrent time-stretch voices. `voices` must be an
|
|
1562
|
+
* integer in `[0, 64]`; a non-integer, negative, or larger value throws and
|
|
1563
|
+
* leaves the capacity unchanged. Default is 8. Capacity 0 disables
|
|
1564
|
+
* time-stretch, so every warped clip plays resampled instead and none of
|
|
1565
|
+
* that counts toward {@link warpStretchOverflowCount}. A change applied
|
|
1566
|
+
* while the engine is running restarts the splice state of any clip
|
|
1567
|
+
* stretching through a voice at that moment. Control-thread only.
|
|
1568
|
+
*/
|
|
1569
|
+
setWarpVoiceCapacity(voices: number): void {
|
|
1570
|
+
this.native.setWarpVoiceCapacity(voices);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
/** Reads the current time-stretch voice capacity (default 8). */
|
|
1574
|
+
warpVoiceCapacity(): number {
|
|
1575
|
+
return this.native.warpVoiceCapacity();
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Sets the clip-page look-ahead window in timeline frames.
|
|
1580
|
+
*
|
|
1581
|
+
* The player reports the pages it is *about to* read that are not resident
|
|
1582
|
+
* yet, so a streaming host can service them before the audio thread reaches
|
|
1583
|
+
* them. Without look-ahead a page miss is only reported after the read
|
|
1584
|
+
* already produced silence, which costs one block of silence at every page
|
|
1585
|
+
* boundary the host has not primed — the reason a sliding-window streamer
|
|
1586
|
+
* cannot keep a live playhead fed from miss reports alone.
|
|
1587
|
+
*
|
|
1588
|
+
* Look-ahead requests drain through the same `popClipPageRequest` queue and
|
|
1589
|
+
* are queued *after* the block's genuine misses, so a host that keeps only
|
|
1590
|
+
* the newest request per clip (as {@link ClipPageStreamer} does) tracks the
|
|
1591
|
+
* look-ahead frontier.
|
|
1592
|
+
*
|
|
1593
|
+
* `prepare` defaults this to half a second at the engine's sample rate. `0`
|
|
1594
|
+
* disables the look-ahead. A clip whose pages are all resident produces no
|
|
1595
|
+
* requests at all, with or without look-ahead. Safe to call during playback.
|
|
1596
|
+
*/
|
|
1597
|
+
setClipPagePrefetchFrames(frames: number): void {
|
|
1598
|
+
this.native.setClipPagePrefetchFrames(frames);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
/** Current clip-page look-ahead window in timeline frames. */
|
|
1602
|
+
clipPagePrefetchFrames(): number {
|
|
1603
|
+
return this.native.clipPagePrefetchFrames();
|
|
1604
|
+
}
|
|
1605
|
+
|
|
922
1606
|
setCaptureBuffer(numChannels: number, capacityFrames: number): void {
|
|
923
1607
|
this.native.setCaptureBuffer(numChannels, capacityFrames);
|
|
924
1608
|
}
|
|
@@ -1027,14 +1711,52 @@ export class RealtimeEngine {
|
|
|
1027
1711
|
return this.native.processWithMonitor(channels);
|
|
1028
1712
|
}
|
|
1029
1713
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1714
|
+
/**
|
|
1715
|
+
* Render `channels` offline from the current transport position. Requesting
|
|
1716
|
+
* more planes than `prepare` reserved throws an `InvalidParameter`
|
|
1717
|
+
* `SonareError` rather than returning silence that reads as a finished render.
|
|
1718
|
+
*
|
|
1719
|
+
* Set `finalize: false` to render one chunk of a longer timeline; see
|
|
1720
|
+
* {@link RenderOfflineRequest.finalize} and {@link finishOfflineRender}.
|
|
1721
|
+
*/
|
|
1722
|
+
renderOffline(request: RenderOfflineRequest): Float32Array[];
|
|
1723
|
+
renderOffline(channels: Float32Array[], blockSize?: number): Float32Array[];
|
|
1724
|
+
renderOffline(
|
|
1725
|
+
channelsOrRequest: Float32Array[] | RenderOfflineRequest,
|
|
1726
|
+
blockSize = 128,
|
|
1727
|
+
): Float32Array[] {
|
|
1728
|
+
const request = normalizeRenderOfflineRequest(channelsOrRequest, blockSize);
|
|
1729
|
+
return this.native.renderOffline(request.channels, request.blockSize, request.finalize);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
/**
|
|
1733
|
+
* End a chunked offline render: release every note the sequencer still holds
|
|
1734
|
+
* and flush the PDC / alignment delay lines. Required after
|
|
1735
|
+
* `renderOffline({ finalize: false })`; the finalizing form does it itself.
|
|
1736
|
+
*
|
|
1737
|
+
* Skipping it leaves every note still sounding at the last chunk held. On an
|
|
1738
|
+
* engine-internal instrument the tail simply never releases; on a destination
|
|
1739
|
+
* marked external ({@link RealtimeEngine.setMidiDestinationExternal}) the
|
|
1740
|
+
* note-ons already left through the external MIDI queue, so the note-offs
|
|
1741
|
+
* emitted here are the only ones the receiving device will get and the notes
|
|
1742
|
+
* otherwise hang outside the engine.
|
|
1743
|
+
*/
|
|
1744
|
+
finishOfflineRender(): void {
|
|
1745
|
+
this.native.finishOfflineRender();
|
|
1032
1746
|
}
|
|
1033
1747
|
|
|
1748
|
+
/**
|
|
1749
|
+
* Bounce the timeline to an interleaved buffer. `numChannels` above the
|
|
1750
|
+
* prepared channel count throws an `InvalidParameter` `SonareError`.
|
|
1751
|
+
*/
|
|
1034
1752
|
bounceOffline(options: EngineBounceOptions): EngineBounceResult {
|
|
1035
1753
|
return this.native.bounceOffline(options);
|
|
1036
1754
|
}
|
|
1037
1755
|
|
|
1756
|
+
/**
|
|
1757
|
+
* Freeze the current graph to audio. `numChannels` above the prepared channel
|
|
1758
|
+
* count throws an `InvalidParameter` `SonareError`.
|
|
1759
|
+
*/
|
|
1038
1760
|
freezeOffline(options: EngineFreezeOptions): EngineFreezeResult {
|
|
1039
1761
|
return this.native.freezeOffline(options);
|
|
1040
1762
|
}
|
|
@@ -1084,6 +1806,12 @@ export class RealtimeEngine {
|
|
|
1084
1806
|
meterScratchRenderFrame(): number {
|
|
1085
1807
|
return Number(this.native.meterScratchRenderFrame());
|
|
1086
1808
|
}
|
|
1809
|
+
meterScratchInputPeakDbL(): number {
|
|
1810
|
+
return this.native.meterScratchInputPeakDbL();
|
|
1811
|
+
}
|
|
1812
|
+
meterScratchInputPeakDbR(): number {
|
|
1813
|
+
return this.native.meterScratchInputPeakDbR();
|
|
1814
|
+
}
|
|
1087
1815
|
meterScratchValue(field: number): number {
|
|
1088
1816
|
return this.native.meterScratchValue(field);
|
|
1089
1817
|
}
|
|
@@ -1095,9 +1823,10 @@ export class RealtimeEngine {
|
|
|
1095
1823
|
/**
|
|
1096
1824
|
* Drains pending meter telemetry as per-plane (wide) records for a surround
|
|
1097
1825
|
* target. Use this for a surround mix target; {@link drainMeterTelemetry}
|
|
1098
|
-
* stays the stereo fast path. The two share one queue
|
|
1099
|
-
* target
|
|
1100
|
-
* this wide drain is for an
|
|
1826
|
+
* stays the stereo fast path. The two share one queue and each consumes every
|
|
1827
|
+
* target's records, so an engine uses only one of them. The live AudioWorklet
|
|
1828
|
+
* path owns the queue via the stereo drain, so this wide drain is for an
|
|
1829
|
+
* offline (non-worklet) engine instance; per-plane
|
|
1101
1830
|
* surround meters are not delivered over the live worklet meter ring.
|
|
1102
1831
|
*/
|
|
1103
1832
|
drainMeterTelemetryWide(maxRecords = 1024): EngineMeterTelemetryWide[] {
|
|
@@ -1144,9 +1873,19 @@ export class RealtimeEngine {
|
|
|
1144
1873
|
return this.native.scopeScratchPointRight(index);
|
|
1145
1874
|
}
|
|
1146
1875
|
|
|
1876
|
+
/** Release the underlying WASM object. Idempotent, as the Node facade is. */
|
|
1147
1877
|
destroy(): void {
|
|
1878
|
+
if (this.released) {
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
this.released = true;
|
|
1148
1882
|
this.native.delete();
|
|
1149
1883
|
}
|
|
1884
|
+
|
|
1885
|
+
/** Alias for {@link destroy}, matching embind's own release method name. */
|
|
1886
|
+
delete(): void {
|
|
1887
|
+
this.destroy();
|
|
1888
|
+
}
|
|
1150
1889
|
}
|
|
1151
1890
|
|
|
1152
1891
|
export class ClipPageProvider {
|