@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
package/src/project_class.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BuiltinSynthBinding,
|
|
3
|
+
Sf2InstrumentConfig,
|
|
4
|
+
Sf2ProgramStatus,
|
|
5
|
+
SynthPatch,
|
|
6
|
+
} from './instrument_types';
|
|
1
7
|
import {
|
|
2
8
|
assertProjectMidiEvents,
|
|
9
|
+
normalizeSynthInstrument,
|
|
10
|
+
projectAutomationPointValue,
|
|
3
11
|
projectAutomationTargetKindValue,
|
|
4
12
|
projectLoopModeValue,
|
|
5
13
|
projectMidi1Event,
|
|
@@ -9,7 +17,6 @@ import {
|
|
|
9
17
|
type WasmProject,
|
|
10
18
|
} from './project_internal';
|
|
11
19
|
import type {
|
|
12
|
-
BuiltinSynthBinding,
|
|
13
20
|
ExternalSeparatedStemImportRequest,
|
|
14
21
|
ExternalSeparatedStemImportResult,
|
|
15
22
|
MidiCcLearnOptions,
|
|
@@ -43,17 +50,23 @@ import type {
|
|
|
43
50
|
ProjectNotePairValidation,
|
|
44
51
|
ProjectSource,
|
|
45
52
|
ProjectTempoCandidate,
|
|
53
|
+
ProjectTempoOptions,
|
|
46
54
|
ProjectTempoSegment,
|
|
47
55
|
ProjectTimeSignatureSegment,
|
|
48
56
|
ProjectTrack,
|
|
49
57
|
ProjectTrackDesc,
|
|
50
58
|
ProjectTrackKind,
|
|
59
|
+
ProjectTranscribeRequest,
|
|
51
60
|
ProjectWarpMapDesc,
|
|
52
61
|
ProjectWarpMode,
|
|
53
|
-
Sf2InstrumentConfig,
|
|
54
|
-
Sf2ProgramStatus,
|
|
55
|
-
SynthPatch,
|
|
56
62
|
} from './project_types';
|
|
63
|
+
import {
|
|
64
|
+
assertBoundedInteger,
|
|
65
|
+
assertNibble,
|
|
66
|
+
assertSampleRate,
|
|
67
|
+
assertSamples,
|
|
68
|
+
assertU7,
|
|
69
|
+
} from './validation';
|
|
57
70
|
|
|
58
71
|
/**
|
|
59
72
|
* Folds the positional and request call forms of `bakeMidiFx` into one shape,
|
|
@@ -112,6 +125,52 @@ function validateAssistSidecarModuleId(value: unknown): string {
|
|
|
112
125
|
return value;
|
|
113
126
|
}
|
|
114
127
|
|
|
128
|
+
const MIDI2_U16_MAX = 0xffff;
|
|
129
|
+
const MIDI2_U32_MAX = 0xffffffff;
|
|
130
|
+
|
|
131
|
+
// UMP MIDI-2.0 channel-voice packet (message type 0x4). Canonical layout is
|
|
132
|
+
// sonare::midi::make_midi2_* (C-ABI sonare_midi2_*); the golden vectors in
|
|
133
|
+
// midi2-ump.test.ts lock this copy against it.
|
|
134
|
+
function midi2Event(
|
|
135
|
+
fnName: string,
|
|
136
|
+
ppq: number,
|
|
137
|
+
group: number,
|
|
138
|
+
opcode: number,
|
|
139
|
+
channel: number,
|
|
140
|
+
byte2: number,
|
|
141
|
+
byte3: number,
|
|
142
|
+
word1: number,
|
|
143
|
+
): ProjectMidiEvent {
|
|
144
|
+
if (!Number.isFinite(ppq) || ppq < 0) {
|
|
145
|
+
throw new RangeError(`${fnName}: ppq must be a non-negative finite number`);
|
|
146
|
+
}
|
|
147
|
+
const g = assertNibble(fnName, group, 'group');
|
|
148
|
+
const ch = assertNibble(fnName, channel, 'channel');
|
|
149
|
+
const word0 =
|
|
150
|
+
((0x4 << 28) | (g << 24) | (opcode << 20) | (ch << 16) | (byte2 << 8) | byte3) >>> 0;
|
|
151
|
+
return { ppq, data0: word0, data1: word1 >>> 0 };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function midi2U32(fnName: string, value: number, argName: string): number {
|
|
155
|
+
assertBoundedInteger(fnName, value, argName, 0, MIDI2_U32_MAX);
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function midi2U16(fnName: string, value: number, argName: string): number {
|
|
160
|
+
assertBoundedInteger(fnName, value, argName, 0, MIDI2_U16_MAX);
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function midi2I32(fnName: string, value: number, argName: string): number {
|
|
165
|
+
assertBoundedInteger(fnName, value, argName, -0x80000000, 0x7fffffff);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function midi2Byte(fnName: string, value: number, argName: string): number {
|
|
170
|
+
assertBoundedInteger(fnName, value, argName, 0, 0xff);
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
|
|
115
174
|
/**
|
|
116
175
|
* Headless DAW project (control-thread-only arrangement model).
|
|
117
176
|
*
|
|
@@ -140,6 +199,7 @@ function validateAssistSidecarModuleId(value: unknown): string {
|
|
|
140
199
|
*/
|
|
141
200
|
export class Project {
|
|
142
201
|
private native: WasmProject;
|
|
202
|
+
private released = false;
|
|
143
203
|
|
|
144
204
|
constructor() {
|
|
145
205
|
this.native = new (projectModule().Project)();
|
|
@@ -204,6 +264,233 @@ export class Project {
|
|
|
204
264
|
return projectMidi1Event('Project.midiProgram', ppq, group, 0xc, channel, program, 0);
|
|
205
265
|
}
|
|
206
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Pack a MIDI 2.0 note-on event accepted by {@link setMidiEvents}.
|
|
269
|
+
* `velocity16` is the full 16-bit velocity (0 is a sounding note-on);
|
|
270
|
+
* `attributeType` 0 is none, 3 is pitch 7.9.
|
|
271
|
+
*/
|
|
272
|
+
static midi2NoteOn(
|
|
273
|
+
ppq: number,
|
|
274
|
+
group: number,
|
|
275
|
+
channel: number,
|
|
276
|
+
note: number,
|
|
277
|
+
velocity16: number,
|
|
278
|
+
attributeType = 0,
|
|
279
|
+
attributeData = 0,
|
|
280
|
+
): ProjectMidiEvent {
|
|
281
|
+
const fn = 'Project.midi2NoteOn';
|
|
282
|
+
const n = assertU7(fn, note, 'note');
|
|
283
|
+
const vel = midi2U16(fn, velocity16, 'velocity16');
|
|
284
|
+
const type = midi2Byte(fn, attributeType, 'attributeType');
|
|
285
|
+
const data = midi2U16(fn, attributeData, 'attributeData');
|
|
286
|
+
return midi2Event(fn, ppq, group, 0x9, channel, n, type, ((vel << 16) | data) >>> 0);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Pack a MIDI 2.0 note-off event (`velocity16` is the full 16-bit release velocity). */
|
|
290
|
+
static midi2NoteOff(
|
|
291
|
+
ppq: number,
|
|
292
|
+
group: number,
|
|
293
|
+
channel: number,
|
|
294
|
+
note: number,
|
|
295
|
+
velocity16 = 0,
|
|
296
|
+
): ProjectMidiEvent {
|
|
297
|
+
const fn = 'Project.midi2NoteOff';
|
|
298
|
+
const n = assertU7(fn, note, 'note');
|
|
299
|
+
const vel = midi2U16(fn, velocity16, 'velocity16');
|
|
300
|
+
return midi2Event(fn, ppq, group, 0x8, channel, n, 0, (vel << 16) >>> 0);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Pack a MIDI 2.0 control-change event (`value32` is the full 32-bit value). */
|
|
304
|
+
static midi2Cc(
|
|
305
|
+
ppq: number,
|
|
306
|
+
group: number,
|
|
307
|
+
channel: number,
|
|
308
|
+
controller: number,
|
|
309
|
+
value32: number,
|
|
310
|
+
): ProjectMidiEvent {
|
|
311
|
+
const fn = 'Project.midi2Cc';
|
|
312
|
+
const c = assertU7(fn, controller, 'controller');
|
|
313
|
+
return midi2Event(fn, ppq, group, 0xb, channel, c, 0, midi2U32(fn, value32, 'value32'));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Pack a MIDI 2.0 poly-pressure event (`pressure32` is the full 32-bit pressure). */
|
|
317
|
+
static midi2PolyPressure(
|
|
318
|
+
ppq: number,
|
|
319
|
+
group: number,
|
|
320
|
+
channel: number,
|
|
321
|
+
note: number,
|
|
322
|
+
pressure32: number,
|
|
323
|
+
): ProjectMidiEvent {
|
|
324
|
+
const fn = 'Project.midi2PolyPressure';
|
|
325
|
+
const n = assertU7(fn, note, 'note');
|
|
326
|
+
return midi2Event(fn, ppq, group, 0xa, channel, n, 0, midi2U32(fn, pressure32, 'pressure32'));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Pack a MIDI 2.0 channel-pressure event (`pressure32` is the full 32-bit pressure). */
|
|
330
|
+
static midi2ChannelPressure(
|
|
331
|
+
ppq: number,
|
|
332
|
+
group: number,
|
|
333
|
+
channel: number,
|
|
334
|
+
pressure32: number,
|
|
335
|
+
): ProjectMidiEvent {
|
|
336
|
+
const fn = 'Project.midi2ChannelPressure';
|
|
337
|
+
return midi2Event(fn, ppq, group, 0xd, channel, 0, 0, midi2U32(fn, pressure32, 'pressure32'));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Pack a MIDI 2.0 pitch-bend event (`bend32` is unsigned 32-bit, center = 0x80000000). */
|
|
341
|
+
static midi2PitchBend(
|
|
342
|
+
ppq: number,
|
|
343
|
+
group: number,
|
|
344
|
+
channel: number,
|
|
345
|
+
bend32: number,
|
|
346
|
+
): ProjectMidiEvent {
|
|
347
|
+
const fn = 'Project.midi2PitchBend';
|
|
348
|
+
return midi2Event(fn, ppq, group, 0xe, channel, 0, 0, midi2U32(fn, bend32, 'bend32'));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Pack a MIDI 2.0 program-change event. The bank travels in the same message
|
|
353
|
+
* and is applied only when `bankValid` is true.
|
|
354
|
+
*/
|
|
355
|
+
static midi2Program(
|
|
356
|
+
ppq: number,
|
|
357
|
+
group: number,
|
|
358
|
+
channel: number,
|
|
359
|
+
program: number,
|
|
360
|
+
bankValid = false,
|
|
361
|
+
bankMsb = 0,
|
|
362
|
+
bankLsb = 0,
|
|
363
|
+
): ProjectMidiEvent {
|
|
364
|
+
const fn = 'Project.midi2Program';
|
|
365
|
+
const p = assertU7(fn, program, 'program');
|
|
366
|
+
const msb = assertU7(fn, bankMsb, 'bankMsb');
|
|
367
|
+
const lsb = assertU7(fn, bankLsb, 'bankLsb');
|
|
368
|
+
const word1 = ((p << 24) | (msb << 8) | lsb) >>> 0;
|
|
369
|
+
return midi2Event(fn, ppq, group, 0xc, channel, 0, bankValid ? 1 : 0, word1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Pack a MIDI 2.0 registered controller (RPN) event. */
|
|
373
|
+
static midi2RegisteredController(
|
|
374
|
+
ppq: number,
|
|
375
|
+
group: number,
|
|
376
|
+
channel: number,
|
|
377
|
+
bank: number,
|
|
378
|
+
index: number,
|
|
379
|
+
value32: number,
|
|
380
|
+
): ProjectMidiEvent {
|
|
381
|
+
const fn = 'Project.midi2RegisteredController';
|
|
382
|
+
const b = assertU7(fn, bank, 'bank');
|
|
383
|
+
const i = assertU7(fn, index, 'index');
|
|
384
|
+
return midi2Event(fn, ppq, group, 0x2, channel, b, i, midi2U32(fn, value32, 'value32'));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Pack a MIDI 2.0 assignable controller (NRPN) event. */
|
|
388
|
+
static midi2AssignableController(
|
|
389
|
+
ppq: number,
|
|
390
|
+
group: number,
|
|
391
|
+
channel: number,
|
|
392
|
+
bank: number,
|
|
393
|
+
index: number,
|
|
394
|
+
value32: number,
|
|
395
|
+
): ProjectMidiEvent {
|
|
396
|
+
const fn = 'Project.midi2AssignableController';
|
|
397
|
+
const b = assertU7(fn, bank, 'bank');
|
|
398
|
+
const i = assertU7(fn, index, 'index');
|
|
399
|
+
return midi2Event(fn, ppq, group, 0x3, channel, b, i, midi2U32(fn, value32, 'value32'));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** Pack a MIDI 2.0 relative registered controller event (`delta32` is a signed change). */
|
|
403
|
+
static midi2RelativeRegisteredController(
|
|
404
|
+
ppq: number,
|
|
405
|
+
group: number,
|
|
406
|
+
channel: number,
|
|
407
|
+
bank: number,
|
|
408
|
+
index: number,
|
|
409
|
+
delta32: number,
|
|
410
|
+
): ProjectMidiEvent {
|
|
411
|
+
const fn = 'Project.midi2RelativeRegisteredController';
|
|
412
|
+
const b = assertU7(fn, bank, 'bank');
|
|
413
|
+
const i = assertU7(fn, index, 'index');
|
|
414
|
+
return midi2Event(fn, ppq, group, 0x4, channel, b, i, midi2I32(fn, delta32, 'delta32'));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Pack a MIDI 2.0 relative assignable controller event (`delta32` is a signed change). */
|
|
418
|
+
static midi2RelativeAssignableController(
|
|
419
|
+
ppq: number,
|
|
420
|
+
group: number,
|
|
421
|
+
channel: number,
|
|
422
|
+
bank: number,
|
|
423
|
+
index: number,
|
|
424
|
+
delta32: number,
|
|
425
|
+
): ProjectMidiEvent {
|
|
426
|
+
const fn = 'Project.midi2RelativeAssignableController';
|
|
427
|
+
const b = assertU7(fn, bank, 'bank');
|
|
428
|
+
const i = assertU7(fn, index, 'index');
|
|
429
|
+
return midi2Event(fn, ppq, group, 0x5, channel, b, i, midi2I32(fn, delta32, 'delta32'));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** Pack a MIDI 2.0 registered per-note controller event (`index` is 0..255). */
|
|
433
|
+
static midi2RegisteredPerNoteController(
|
|
434
|
+
ppq: number,
|
|
435
|
+
group: number,
|
|
436
|
+
channel: number,
|
|
437
|
+
note: number,
|
|
438
|
+
index: number,
|
|
439
|
+
value32: number,
|
|
440
|
+
): ProjectMidiEvent {
|
|
441
|
+
const fn = 'Project.midi2RegisteredPerNoteController';
|
|
442
|
+
const n = assertU7(fn, note, 'note');
|
|
443
|
+
const i = midi2Byte(fn, index, 'index');
|
|
444
|
+
return midi2Event(fn, ppq, group, 0x0, channel, n, i, midi2U32(fn, value32, 'value32'));
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** Pack a MIDI 2.0 assignable per-note controller event (`index` is 0..255). */
|
|
448
|
+
static midi2AssignablePerNoteController(
|
|
449
|
+
ppq: number,
|
|
450
|
+
group: number,
|
|
451
|
+
channel: number,
|
|
452
|
+
note: number,
|
|
453
|
+
index: number,
|
|
454
|
+
value32: number,
|
|
455
|
+
): ProjectMidiEvent {
|
|
456
|
+
const fn = 'Project.midi2AssignablePerNoteController';
|
|
457
|
+
const n = assertU7(fn, note, 'note');
|
|
458
|
+
const i = midi2Byte(fn, index, 'index');
|
|
459
|
+
return midi2Event(fn, ppq, group, 0x1, channel, n, i, midi2U32(fn, value32, 'value32'));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Pack a MIDI 2.0 per-note pitch-bend event (`bend32` is unsigned 32-bit, center = 0x80000000). */
|
|
463
|
+
static midi2PerNotePitchBend(
|
|
464
|
+
ppq: number,
|
|
465
|
+
group: number,
|
|
466
|
+
channel: number,
|
|
467
|
+
note: number,
|
|
468
|
+
bend32: number,
|
|
469
|
+
): ProjectMidiEvent {
|
|
470
|
+
const fn = 'Project.midi2PerNotePitchBend';
|
|
471
|
+
const n = assertU7(fn, note, 'note');
|
|
472
|
+
return midi2Event(fn, ppq, group, 0x6, channel, n, 0, midi2U32(fn, bend32, 'bend32'));
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Pack a MIDI 2.0 per-note management event. `detach` sets the D flag
|
|
477
|
+
* (detach per-note controllers from voices already sounding on `note`);
|
|
478
|
+
* `reset` sets the S flag (reset the note's per-note controllers).
|
|
479
|
+
*/
|
|
480
|
+
static midi2PerNoteManagement(
|
|
481
|
+
ppq: number,
|
|
482
|
+
group: number,
|
|
483
|
+
channel: number,
|
|
484
|
+
note: number,
|
|
485
|
+
detach = false,
|
|
486
|
+
reset = false,
|
|
487
|
+
): ProjectMidiEvent {
|
|
488
|
+
const fn = 'Project.midi2PerNoteManagement';
|
|
489
|
+
const n = assertU7(fn, note, 'note');
|
|
490
|
+
const flags = (detach ? 0x02 : 0) | (reset ? 0x01 : 0);
|
|
491
|
+
return midi2Event(fn, ppq, group, 0xf, channel, n, flags, 0);
|
|
492
|
+
}
|
|
493
|
+
|
|
207
494
|
/** Return the General MIDI instrument name for `program`, or `null` when out of range. */
|
|
208
495
|
static gmInstrumentName(program: number): string | null {
|
|
209
496
|
return projectModule().midiGmInstrumentName(program);
|
|
@@ -335,9 +622,7 @@ export class Project {
|
|
|
335
622
|
channel: number,
|
|
336
623
|
bend: number,
|
|
337
624
|
): ProjectMidiEvent {
|
|
338
|
-
|
|
339
|
-
throw new RangeError('Project.midiPitchBend: bend must be an integer in [0, 16383]');
|
|
340
|
-
}
|
|
625
|
+
assertBoundedInteger('Project.midiPitchBend', bend, 'bend', 0, 0x3fff);
|
|
341
626
|
return projectMidi1Event(
|
|
342
627
|
'Project.midiPitchBend',
|
|
343
628
|
ppq,
|
|
@@ -395,7 +680,11 @@ export class Project {
|
|
|
395
680
|
return this.native.toJson();
|
|
396
681
|
}
|
|
397
682
|
|
|
398
|
-
/**
|
|
683
|
+
/**
|
|
684
|
+
* Set the project sample rate in Hz. Must be in `[8000, 384000]`; anything
|
|
685
|
+
* outside that range throws. Applied through the edit history, so it is
|
|
686
|
+
* undoable.
|
|
687
|
+
*/
|
|
399
688
|
setSampleRate(sampleRate: number): void {
|
|
400
689
|
this.native.setSampleRate(sampleRate);
|
|
401
690
|
}
|
|
@@ -487,7 +776,24 @@ export class Project {
|
|
|
487
776
|
this.native.setTrackMidiDestination(trackId, destinationId);
|
|
488
777
|
}
|
|
489
778
|
|
|
490
|
-
/**
|
|
779
|
+
/**
|
|
780
|
+
* Set a track's linear playback gain (1.0 = unity; >= 0) via an undoable edit.
|
|
781
|
+
*
|
|
782
|
+
* The value reaches the track's audio and MIDI alike, but the stage it lands
|
|
783
|
+
* on follows the track's channel strip. A strip bound by this track alone
|
|
784
|
+
* (including one synthesized for an unbound track) carries the controls on its
|
|
785
|
+
* own fader and panner. A strip several tracks share processes their sum and
|
|
786
|
+
* carries none of them; each track applies its controls upstream instead — on
|
|
787
|
+
* its own clip schedules for audio, on its track lane for MIDI.
|
|
788
|
+
*
|
|
789
|
+
* A MIDI track's gain/pan on a shared strip ride the track lane, which is fed
|
|
790
|
+
* per source track only by an instrument that preserves source-track identity
|
|
791
|
+
* (see {@link setTrackMidiDestination}). An opaque host-callback instrument, or
|
|
792
|
+
* one reporting non-zero latency, renders one buffer per destination and has no
|
|
793
|
+
* per-track stage on a shared strip, so its gain/pan do not reach the bounce
|
|
794
|
+
* there; bind such an instrument to a track with an exclusive strip. Mute and
|
|
795
|
+
* solo are unaffected: a silenced MIDI track schedules no events at all.
|
|
796
|
+
*/
|
|
491
797
|
setTrackGain(trackId: number, gain: number): void {
|
|
492
798
|
this.native.setTrackGain(trackId, gain);
|
|
493
799
|
}
|
|
@@ -502,7 +808,17 @@ export class Project {
|
|
|
502
808
|
this.native.setTrackSolo(trackId, solo);
|
|
503
809
|
}
|
|
504
810
|
|
|
505
|
-
/**
|
|
811
|
+
/**
|
|
812
|
+
* Set a track's stereo balance in [-1, +1] (0 = center) via an undoable edit.
|
|
813
|
+
*
|
|
814
|
+
* See {@link setTrackGain} for which stage a track's controls land on. The pan
|
|
815
|
+
* law that shapes the balance belongs to that stage: the strip's configured law
|
|
816
|
+
* on a channel strip and on the clips of an audio track sharing a strip, and
|
|
817
|
+
* the track lane's law for a MIDI track sharing a strip (the law of whatever
|
|
818
|
+
* strip the host bound to that lane, or a linear balance when none is bound).
|
|
819
|
+
* Every law is normalized so a centered track stays at unity and only the away
|
|
820
|
+
* channel is attenuated, so the difference is a taper, not a level offset.
|
|
821
|
+
*/
|
|
506
822
|
setTrackPan(trackId: number, pan: number): void {
|
|
507
823
|
this.native.setTrackPan(trackId, pan);
|
|
508
824
|
}
|
|
@@ -543,7 +859,18 @@ export class Project {
|
|
|
543
859
|
this.native.setMaxHistoryBytes(bytes);
|
|
544
860
|
}
|
|
545
861
|
|
|
546
|
-
/**
|
|
862
|
+
/**
|
|
863
|
+
* Replace a MIDI clip's entire event list.
|
|
864
|
+
*
|
|
865
|
+
* @remarks
|
|
866
|
+
* Drops the clip's SysEx, which {@link importSmf} and {@link exportSmf} both
|
|
867
|
+
* keep. A clip's SysEx payloads sit beside the event list and are reached by
|
|
868
|
+
* a handle {@link ProjectMidiEvent} does not carry, so replacing the list
|
|
869
|
+
* leaves nothing referring to them: a GS setup block that survives an import
|
|
870
|
+
* and an export byte for byte is gone after one call here. Nothing reads the
|
|
871
|
+
* handles back either, so a caller that must keep the setup edits the
|
|
872
|
+
* exported file rather than the event list.
|
|
873
|
+
*/
|
|
547
874
|
setMidiEvents(
|
|
548
875
|
clipId: number,
|
|
549
876
|
events: ReadonlyArray<ProjectMidiEvent | readonly [number, number, number]>,
|
|
@@ -561,8 +888,15 @@ export class Project {
|
|
|
561
888
|
return this.native.importSmf(data);
|
|
562
889
|
}
|
|
563
890
|
|
|
564
|
-
/**
|
|
565
|
-
|
|
891
|
+
/**
|
|
892
|
+
* Export the project's tempo map + MIDI clips to an SMF byte buffer.
|
|
893
|
+
*
|
|
894
|
+
* @remarks
|
|
895
|
+
* The buffer owns a plain `ArrayBuffer`, which is what the `Blob` / `File`
|
|
896
|
+
* constructors accept — so `new Blob([project.exportSmf()])` compiles without
|
|
897
|
+
* a copy through `new Uint8Array(...)` first.
|
|
898
|
+
*/
|
|
899
|
+
exportSmf(): Uint8Array<ArrayBuffer> {
|
|
566
900
|
return this.native.exportSmf();
|
|
567
901
|
}
|
|
568
902
|
|
|
@@ -580,8 +914,12 @@ export class Project {
|
|
|
580
914
|
* Export the project's tempo map + MIDI clips to a MIDI 2.0 Clip File
|
|
581
915
|
* (`SMF2CLIP`) byte buffer. MIDI 2.0-only events are written without loss —
|
|
582
916
|
* prefer this over {@link exportSmf} when MIDI 2.0 fidelity matters.
|
|
917
|
+
*
|
|
918
|
+
* @remarks
|
|
919
|
+
* As with {@link exportSmf}, the buffer owns a plain `ArrayBuffer` and goes
|
|
920
|
+
* straight into a `Blob`.
|
|
583
921
|
*/
|
|
584
|
-
exportClipFile(): Uint8Array {
|
|
922
|
+
exportClipFile(): Uint8Array<ArrayBuffer> {
|
|
585
923
|
return this.native.exportClipFile();
|
|
586
924
|
}
|
|
587
925
|
|
|
@@ -653,19 +991,62 @@ export class Project {
|
|
|
653
991
|
return this.native.validateMidiNotes(clipId);
|
|
654
992
|
}
|
|
655
993
|
|
|
994
|
+
/**
|
|
995
|
+
* Transcribe mono audio straight into a MIDI clip's event list, **replacing**
|
|
996
|
+
* whatever it held — exactly as {@link setMidiEvents} does.
|
|
997
|
+
*
|
|
998
|
+
* The PPQ grid is this project's own tempo map, which is why there is no
|
|
999
|
+
* `tempoBpm` field: a project whose tempo was installed by {@link autoTempo}
|
|
1000
|
+
* transcribes onto that map rather than onto a second, separately detected
|
|
1001
|
+
* tempo. Use the standalone `transcribe` when you want events without a
|
|
1002
|
+
* project.
|
|
1003
|
+
*
|
|
1004
|
+
* Quantizing, tempo detection and key/chord annotation are not done here —
|
|
1005
|
+
* see `transcribe` for what each belongs to.
|
|
1006
|
+
*
|
|
1007
|
+
* @returns the number of notes written (half the events)
|
|
1008
|
+
* @throws {RangeError} on empty `samples`, a non-finite sample, or a
|
|
1009
|
+
* `sampleRate` outside `[8000, 384000]`
|
|
1010
|
+
* @throws {SonareError} `InvalidParameter` when `clipId` is unknown or not a
|
|
1011
|
+
* MIDI clip, or on an option outside its domain; `NotSupported` when the
|
|
1012
|
+
* library was built without the pitch editor
|
|
1013
|
+
*/
|
|
1014
|
+
transcribeToClip(request: ProjectTranscribeRequest): number {
|
|
1015
|
+
assertSamples('Project.transcribeToClip', request.samples, true);
|
|
1016
|
+
assertSampleRate('Project.transcribeToClip', request.sampleRate);
|
|
1017
|
+
return this.native.transcribeToClip(
|
|
1018
|
+
request.clipId,
|
|
1019
|
+
request.samples,
|
|
1020
|
+
request.sampleRate,
|
|
1021
|
+
request,
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
656
1025
|
/** Return ranked tempo-octave and detected-meter candidates without editing. */
|
|
657
|
-
analyzeTempo(
|
|
658
|
-
|
|
1026
|
+
analyzeTempo(
|
|
1027
|
+
audio: Float32Array,
|
|
1028
|
+
sampleRate: number,
|
|
1029
|
+
options?: ProjectTempoOptions,
|
|
1030
|
+
): ProjectTempoCandidate[] {
|
|
1031
|
+
return this.native.analyzeTempo(audio, sampleRate, options);
|
|
659
1032
|
}
|
|
660
1033
|
|
|
661
|
-
/**
|
|
1034
|
+
/**
|
|
1035
|
+
* Detect and install a ranked tempo candidate; optionally apply detected meter.
|
|
1036
|
+
*
|
|
1037
|
+
* @remarks
|
|
1038
|
+
* `candidateIndex` indexes the ranking {@link analyzeTempo} produced, so pair
|
|
1039
|
+
* the two on the same `options`. Read the installed map back with
|
|
1040
|
+
* {@link tempoSegmentCount} and {@link tempoSegmentByIndex}.
|
|
1041
|
+
*/
|
|
662
1042
|
autoTempo(
|
|
663
1043
|
audio: Float32Array,
|
|
664
1044
|
sampleRate: number,
|
|
665
1045
|
candidateIndex = 0,
|
|
666
1046
|
applyTimeSignatures = false,
|
|
1047
|
+
options?: ProjectTempoOptions,
|
|
667
1048
|
): number {
|
|
668
|
-
return this.native.autoTempo(audio, sampleRate, candidateIndex, applyTimeSignatures);
|
|
1049
|
+
return this.native.autoTempo(audio, sampleRate, candidateIndex, applyTimeSignatures, options);
|
|
669
1050
|
}
|
|
670
1051
|
|
|
671
1052
|
/** Snap to a bar (`division=0`), beat (`1`), or beat subdivision (`2+`). */
|
|
@@ -727,9 +1108,9 @@ export class Project {
|
|
|
727
1108
|
|
|
728
1109
|
/**
|
|
729
1110
|
* Compile + render the project offline, routing MIDI tracks through the
|
|
730
|
-
* patch-driven NativeSynth — the full synthesizer (
|
|
731
|
-
*
|
|
732
|
-
*
|
|
1111
|
+
* patch-driven NativeSynth — the full synthesizer (every
|
|
1112
|
+
* {@link SynthEngineMode} engine plus the realism layer; the modes are
|
|
1113
|
+
* enumerated by {@link SYNTH_ENGINE_MODES}). Pass a {@link SynthPatch}, a preset-name
|
|
733
1114
|
* string (`'saw-lead'` / `'va:saw-lead'`; see {@link synthPresetNames}), or
|
|
734
1115
|
* an array of either; each object entry may carry `destinationId` (default
|
|
735
1116
|
* 0) and `useGmPrograms` (default `false`) binding conveniences, neither of
|
|
@@ -740,12 +1121,19 @@ export class Project {
|
|
|
740
1121
|
* both create one default binding. Use an explicitly empty array `[]` (or
|
|
741
1122
|
* runtime `null`) for zero bindings. Unknown preset names throw.
|
|
742
1123
|
* Deterministic for a fixed project + options + patch.
|
|
1124
|
+
*
|
|
1125
|
+
* An `engineMode: 'sample'` patch reads its PCM from the {@link SampleBank}
|
|
1126
|
+
* passed as `sampleBank`; the bank must still be alive when the bounce runs,
|
|
1127
|
+
* and one bound without a bank renders silence.
|
|
743
1128
|
*/
|
|
744
1129
|
bounceWithSynthInstrument(
|
|
745
1130
|
instrument: SynthPatch | string | ReadonlyArray<SynthPatch | string> = {},
|
|
746
1131
|
options: ProjectBounceOptions = {},
|
|
747
1132
|
): Float32Array {
|
|
748
|
-
|
|
1133
|
+
const normalized = Array.isArray(instrument)
|
|
1134
|
+
? instrument.map((entry) => normalizeSynthInstrument(entry))
|
|
1135
|
+
: normalizeSynthInstrument(instrument);
|
|
1136
|
+
return this.native.bounceWithSynthInstrument(normalized, options);
|
|
749
1137
|
}
|
|
750
1138
|
|
|
751
1139
|
/**
|
|
@@ -895,7 +1283,10 @@ export class Project {
|
|
|
895
1283
|
if (desc.targetParamId === 0) {
|
|
896
1284
|
throw new RangeError('project automation lane targetParamId must be non-zero');
|
|
897
1285
|
}
|
|
898
|
-
const nativeDesc: ProjectAutomationLaneDesc = {
|
|
1286
|
+
const nativeDesc: ProjectAutomationLaneDesc = {
|
|
1287
|
+
...desc,
|
|
1288
|
+
points: desc.points.map(projectAutomationPointValue),
|
|
1289
|
+
};
|
|
899
1290
|
if (Object.keys(desc).includes('targetKind')) {
|
|
900
1291
|
nativeDesc.targetKind = projectAutomationTargetKindValue(
|
|
901
1292
|
desc.targetKind as ProjectAutomationTargetKind,
|
|
@@ -913,7 +1304,10 @@ export class Project {
|
|
|
913
1304
|
if (desc.targetParamId === 0) {
|
|
914
1305
|
throw new RangeError('project automation lane targetParamId must be non-zero');
|
|
915
1306
|
}
|
|
916
|
-
const nativeDesc: ProjectAutomationLaneDesc = {
|
|
1307
|
+
const nativeDesc: ProjectAutomationLaneDesc = {
|
|
1308
|
+
...desc,
|
|
1309
|
+
points: desc.points.map(projectAutomationPointValue),
|
|
1310
|
+
};
|
|
917
1311
|
if (Object.keys(desc).includes('targetKind')) {
|
|
918
1312
|
nativeDesc.targetKind = projectAutomationTargetKindValue(
|
|
919
1313
|
desc.targetKind as ProjectAutomationTargetKind,
|
|
@@ -1097,6 +1491,28 @@ export class Project {
|
|
|
1097
1491
|
return this.native.tempoSegmentCount();
|
|
1098
1492
|
}
|
|
1099
1493
|
|
|
1494
|
+
/**
|
|
1495
|
+
* Reads a tempo segment by index, in stored order.
|
|
1496
|
+
*
|
|
1497
|
+
* @param index - Zero-based index below {@link tempoSegmentCount}
|
|
1498
|
+
* @returns The segment, in the shape {@link setTempoSegments} accepts
|
|
1499
|
+
* @throws When the index is at or past the count
|
|
1500
|
+
*/
|
|
1501
|
+
tempoSegmentByIndex(index: number): ProjectTempoSegment {
|
|
1502
|
+
return this.native.tempoSegmentByIndex(index);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* Reads a time-signature segment by index, in stored order.
|
|
1507
|
+
*
|
|
1508
|
+
* @param index - Zero-based index below {@link timeSignatureCount}
|
|
1509
|
+
* @returns The segment, in the shape {@link setTimeSignatures} accepts
|
|
1510
|
+
* @throws When the index is at or past the count
|
|
1511
|
+
*/
|
|
1512
|
+
timeSignatureByIndex(index: number): ProjectTimeSignatureSegment {
|
|
1513
|
+
return this.native.timeSignatureByIndex(index);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1100
1516
|
/** Number of time-signature segments on the project. */
|
|
1101
1517
|
timeSignatureCount(): number {
|
|
1102
1518
|
return this.native.timeSignatureCount();
|
|
@@ -1114,15 +1530,22 @@ export class Project {
|
|
|
1114
1530
|
|
|
1115
1531
|
/**
|
|
1116
1532
|
* Compile diagnostics produced by the most recent bounce on this project
|
|
1117
|
-
* (e.g. MIDI clips rendering silently without a bound instrument).
|
|
1118
|
-
* bounce has run, the result is empty
|
|
1533
|
+
* (e.g. MIDI clips rendering silently without a bound instrument). On a
|
|
1534
|
+
* project no bounce has ever run on, the result is empty in full:
|
|
1535
|
+
* `hasTimeline` is `false` and `diagnostics` is empty. A failed bounce is
|
|
1536
|
+
* distinguishable from that state, because a bounce only loses its timeline
|
|
1537
|
+
* through an error diagnostic and so always reports at least one.
|
|
1119
1538
|
*/
|
|
1120
1539
|
lastBounceCompileResult(): ProjectCompileResult {
|
|
1121
1540
|
return this.native.lastBounceCompileResult();
|
|
1122
1541
|
}
|
|
1123
1542
|
|
|
1124
|
-
/** Release the underlying WASM object.
|
|
1543
|
+
/** Release the underlying WASM object. Idempotent, as the Node facade is. */
|
|
1125
1544
|
delete(): void {
|
|
1545
|
+
if (this.released) {
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
this.released = true;
|
|
1126
1549
|
this.native.delete();
|
|
1127
1550
|
}
|
|
1128
1551
|
|