@libraz/libsonare 1.6.0 → 1.7.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/README.md +2 -2
- package/dist/analysis.d.ts +88 -9
- package/dist/analysis.js +152 -42
- package/dist/analysis.js.map +1 -1
- package/dist/index.d.ts +129 -24
- package/dist/index.js +455 -140
- package/dist/index.js.map +1 -1
- package/dist/schemas/realtime-voice-changer-preset.schema.json +2 -2
- package/dist/sonare-analysis.js +1 -1
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worker.js +56 -29
- package/dist/worker.js.map +1 -1
- package/dist/worklet.d.ts +62 -10
- package/dist/worklet.js +193 -42
- package/dist/worklet.js.map +1 -1
- package/package.json +3 -3
- package/src/analysis_helpers.ts +34 -29
- package/src/audio.ts +7 -2
- package/src/codes.ts +47 -11
- package/src/effects_transform.ts +179 -10
- package/src/feature_music.ts +8 -1
- package/src/feature_spectral.ts +64 -2
- package/src/feature_spectrogram.ts +44 -3
- package/src/index.ts +21 -3
- package/src/mixer.ts +3 -3
- package/src/project.ts +6 -0
- package/src/project_class.ts +143 -16
- package/src/project_internal.ts +14 -5
- package/src/project_types.ts +45 -1
- package/src/public_types_mixing.ts +16 -0
- package/src/public_types_realtime.ts +23 -5
- package/src/quick_analysis.ts +21 -3
- package/src/realtime_engine.ts +14 -3
- package/src/sonare.js.d.ts +64 -0
- package/src/stream_analyzer.ts +6 -1
- package/src/web_midi.ts +10 -7
- package/src/worklet/engine-node.ts +54 -19
- package/src/worklet/engine-parameter-facade.ts +30 -1
- package/src/worklet/engine-processor.ts +52 -20
- package/src/worklet/engine-register.ts +1 -1
- package/src/worklet/engine-strips.ts +2 -2
- package/src/worklet/engine.ts +10 -0
- package/src/worklet/guards.ts +99 -7
- package/src/worklet/messages.ts +41 -1
- package/src/worklet/protocol.ts +4 -0
|
@@ -113,6 +113,8 @@ export interface TrimRequest extends GuardedOptions {
|
|
|
113
113
|
samples: Float32Array;
|
|
114
114
|
sampleRate: number;
|
|
115
115
|
thresholdDb?: number;
|
|
116
|
+
frameLength?: number;
|
|
117
|
+
hopLength?: number;
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
function validateSpectrogramSamples(
|
|
@@ -183,19 +185,58 @@ export function trim(
|
|
|
183
185
|
thresholdDb?: number,
|
|
184
186
|
options?: GuardedOptions,
|
|
185
187
|
): Float32Array;
|
|
188
|
+
export function trim(
|
|
189
|
+
samples: Float32Array,
|
|
190
|
+
sampleRate: number,
|
|
191
|
+
thresholdDb?: number,
|
|
192
|
+
frameLength?: number,
|
|
193
|
+
hopLength?: number,
|
|
194
|
+
options?: GuardedOptions,
|
|
195
|
+
): Float32Array;
|
|
186
196
|
export function trim(
|
|
187
197
|
samples: Float32Array | TrimRequest,
|
|
188
198
|
sampleRate = 22050,
|
|
189
199
|
thresholdDb = -60.0,
|
|
200
|
+
frameLengthOrOptions?: number | GuardedOptions,
|
|
201
|
+
hopLength?: number,
|
|
190
202
|
options: GuardedOptions = {},
|
|
191
203
|
): Float32Array {
|
|
192
204
|
if (!(samples instanceof Float32Array)) {
|
|
193
205
|
const r = samples;
|
|
194
|
-
return trim(r.samples, r.sampleRate, r.thresholdDb, r);
|
|
206
|
+
return trim(r.samples, r.sampleRate, r.thresholdDb, r.frameLength, r.hopLength, r);
|
|
207
|
+
}
|
|
208
|
+
if (frameLengthOrOptions === null) {
|
|
209
|
+
throw new TypeError('trim: frameLength must be an integer or options object');
|
|
195
210
|
}
|
|
196
|
-
|
|
211
|
+
if (
|
|
212
|
+
frameLengthOrOptions !== undefined &&
|
|
213
|
+
typeof frameLengthOrOptions !== 'number' &&
|
|
214
|
+
typeof frameLengthOrOptions !== 'object'
|
|
215
|
+
) {
|
|
216
|
+
throw new TypeError('trim: frameLength must be an integer or options object');
|
|
217
|
+
}
|
|
218
|
+
const positionalOptions =
|
|
219
|
+
typeof frameLengthOrOptions === 'object' && frameLengthOrOptions !== null
|
|
220
|
+
? frameLengthOrOptions
|
|
221
|
+
: options;
|
|
222
|
+
const positionalFrameLength =
|
|
223
|
+
typeof frameLengthOrOptions === 'number' ? frameLengthOrOptions : undefined;
|
|
224
|
+
const resolvedFrameLength = positionalFrameLength ?? 2048;
|
|
225
|
+
const resolvedHopLength = hopLength === undefined ? 512 : hopLength;
|
|
226
|
+
validateSpectrogramSamples('trim', samples, sampleRate, positionalOptions);
|
|
197
227
|
assertFiniteScalar('trim', thresholdDb, 'thresholdDb');
|
|
198
|
-
|
|
228
|
+
assertPositiveInteger('trim', resolvedFrameLength, 'frameLength');
|
|
229
|
+
assertPositiveInteger('trim', resolvedHopLength, 'hopLength');
|
|
230
|
+
if (resolvedFrameLength > 2 ** 31 - 1 || resolvedHopLength > 2 ** 31 - 1) {
|
|
231
|
+
throw new RangeError('trim: frameLength and hopLength must fit in a signed 32-bit integer');
|
|
232
|
+
}
|
|
233
|
+
return requireModule().trimEx(
|
|
234
|
+
samples,
|
|
235
|
+
sampleRate,
|
|
236
|
+
thresholdDb,
|
|
237
|
+
resolvedFrameLength,
|
|
238
|
+
resolvedHopLength,
|
|
239
|
+
);
|
|
199
240
|
}
|
|
200
241
|
|
|
201
242
|
// ============================================================================
|
package/src/index.ts
CHANGED
|
@@ -146,6 +146,7 @@ export {
|
|
|
146
146
|
export type {
|
|
147
147
|
HarmonicRequest,
|
|
148
148
|
HpssRequest,
|
|
149
|
+
NormalizeMode,
|
|
149
150
|
NormalizeRequest,
|
|
150
151
|
NoteMoveRequest,
|
|
151
152
|
NoteStretchRequest,
|
|
@@ -410,9 +411,11 @@ export type {
|
|
|
410
411
|
ExternalSeparatedStemImportResult,
|
|
411
412
|
MidiCcLearnOptions,
|
|
412
413
|
ProjectAssistSidecar,
|
|
414
|
+
ProjectAssistSidecarInput,
|
|
413
415
|
ProjectAutomationCurve,
|
|
414
416
|
ProjectAutomationLaneDesc,
|
|
415
417
|
ProjectAutomationPoint,
|
|
418
|
+
ProjectAutomationTargetKind,
|
|
416
419
|
ProjectBounceOptions,
|
|
417
420
|
ProjectChordSymbol,
|
|
418
421
|
ProjectClip,
|
|
@@ -451,9 +454,13 @@ export type {
|
|
|
451
454
|
SynthPatch,
|
|
452
455
|
} from './project';
|
|
453
456
|
export {
|
|
457
|
+
AutomationTargetKind,
|
|
454
458
|
BUILTIN_SYNTH_WAVEFORMS,
|
|
455
459
|
EXPECTED_PROJECT_ABI_VERSION,
|
|
456
460
|
MarkerKind,
|
|
461
|
+
PROJECT_AUTOMATION_TARGET_OPAQUE,
|
|
462
|
+
PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,
|
|
463
|
+
PROJECT_AUTOMATION_TARGET_TRACK_PAN,
|
|
457
464
|
Project,
|
|
458
465
|
projectAbiVersion,
|
|
459
466
|
SYNTH_BODY_TYPES,
|
|
@@ -525,6 +532,8 @@ export type {
|
|
|
525
532
|
PairAnalysis,
|
|
526
533
|
PairProcessor,
|
|
527
534
|
PanLaw,
|
|
535
|
+
PanLawInput,
|
|
536
|
+
PanLawName,
|
|
528
537
|
PanMode,
|
|
529
538
|
PitchCorrectOptions,
|
|
530
539
|
PitchResult,
|
|
@@ -636,10 +645,12 @@ export type {
|
|
|
636
645
|
EngineTempoSegment,
|
|
637
646
|
EngineTimeSignatureSegment,
|
|
638
647
|
EngineTrackLane,
|
|
648
|
+
EngineTrackMonitorMode,
|
|
639
649
|
EngineTrackSend,
|
|
640
650
|
EngineTransportState,
|
|
641
651
|
ExternalMidiEvent,
|
|
642
652
|
MidiCcBindOptions,
|
|
653
|
+
TrackMonitorMode,
|
|
643
654
|
} from './realtime_engine';
|
|
644
655
|
export {
|
|
645
656
|
ClipPageProvider,
|
|
@@ -840,13 +851,20 @@ function resolveVoicePresetOrdinal(preset: VoicePresetId | number): number {
|
|
|
840
851
|
|
|
841
852
|
/**
|
|
842
853
|
* Map a voice-character preset ordinal (or canonical id) to its canonical id
|
|
843
|
-
* string (e.g. `'bright-idol'`).
|
|
854
|
+
* string (e.g. `'bright-idol'`). Unknown numeric ordinals return `null`;
|
|
855
|
+
* unknown preset ids throw.
|
|
844
856
|
*/
|
|
845
|
-
export function voiceCharacterPresetId(preset: VoicePresetId | number):
|
|
857
|
+
export function voiceCharacterPresetId(preset: VoicePresetId | number): VoicePresetId | null {
|
|
846
858
|
if (!module) {
|
|
847
859
|
throw new Error('Module not initialized. Call init() first.');
|
|
848
860
|
}
|
|
849
|
-
|
|
861
|
+
if (
|
|
862
|
+
typeof preset === 'number' &&
|
|
863
|
+
(!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length)
|
|
864
|
+
) {
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
return module.voiceCharacterPresetId(resolveVoicePresetOrdinal(preset)) as VoicePresetId;
|
|
850
868
|
}
|
|
851
869
|
|
|
852
870
|
/**
|
package/src/mixer.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
MeterTap,
|
|
13
13
|
MixerProcessResult,
|
|
14
14
|
MixMeterSnapshot,
|
|
15
|
-
|
|
15
|
+
PanLawInput,
|
|
16
16
|
PanMode,
|
|
17
17
|
SendTiming,
|
|
18
18
|
SurroundPan,
|
|
@@ -336,8 +336,8 @@ export class Mixer {
|
|
|
336
336
|
this.mixer.setPolarityInvert(stripIndex, invertLeft, invertRight);
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
/** Set the strip's pan law. */
|
|
340
|
-
setPanLaw(stripIndex: number, panLaw:
|
|
339
|
+
/** Set the strip's pan law (a {@link PanLawName} alias or raw C ABI ordinal). */
|
|
340
|
+
setPanLaw(stripIndex: number, panLaw: PanLawInput): void {
|
|
341
341
|
this.mixer.setPanLaw(stripIndex, panLawCode(panLaw));
|
|
342
342
|
}
|
|
343
343
|
|
package/src/project.ts
CHANGED
|
@@ -15,9 +15,11 @@ export type {
|
|
|
15
15
|
ExternalSeparatedStemImportResult,
|
|
16
16
|
MidiCcLearnOptions,
|
|
17
17
|
ProjectAssistSidecar,
|
|
18
|
+
ProjectAssistSidecarInput,
|
|
18
19
|
ProjectAutomationCurve,
|
|
19
20
|
ProjectAutomationLaneDesc,
|
|
20
21
|
ProjectAutomationPoint,
|
|
22
|
+
ProjectAutomationTargetKind,
|
|
21
23
|
ProjectBounceOptions,
|
|
22
24
|
ProjectChordSymbol,
|
|
23
25
|
ProjectClip,
|
|
@@ -65,9 +67,13 @@ export type {
|
|
|
65
67
|
SynthPatch,
|
|
66
68
|
} from './project_types';
|
|
67
69
|
export {
|
|
70
|
+
AutomationTargetKind,
|
|
68
71
|
BUILTIN_SYNTH_WAVEFORMS,
|
|
69
72
|
EXPECTED_PROJECT_ABI_VERSION,
|
|
70
73
|
MarkerKind,
|
|
74
|
+
PROJECT_AUTOMATION_TARGET_OPAQUE,
|
|
75
|
+
PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,
|
|
76
|
+
PROJECT_AUTOMATION_TARGET_TRACK_PAN,
|
|
71
77
|
SYNTH_BODY_TYPES,
|
|
72
78
|
SYNTH_ENGINE_MODES,
|
|
73
79
|
SYNTH_FILTER_MODELS,
|
package/src/project_class.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertProjectMidiEvents,
|
|
3
|
+
projectAutomationTargetKindValue,
|
|
3
4
|
projectLoopModeValue,
|
|
4
5
|
projectMidi1Event,
|
|
5
6
|
projectModule,
|
|
@@ -13,8 +14,10 @@ import type {
|
|
|
13
14
|
ExternalSeparatedStemImportResult,
|
|
14
15
|
MidiCcLearnOptions,
|
|
15
16
|
ProjectAssistSidecar,
|
|
17
|
+
ProjectAssistSidecarInput,
|
|
16
18
|
ProjectAutomationLaneDesc,
|
|
17
19
|
ProjectAutomationPoint,
|
|
20
|
+
ProjectAutomationTargetKind,
|
|
18
21
|
ProjectBounceOptions,
|
|
19
22
|
ProjectChordSymbol,
|
|
20
23
|
ProjectClip,
|
|
@@ -49,6 +52,41 @@ import type {
|
|
|
49
52
|
SynthPatch,
|
|
50
53
|
} from './project_types';
|
|
51
54
|
|
|
55
|
+
function validateAssistSidecarUint32(value: unknown, field: string): number {
|
|
56
|
+
if (
|
|
57
|
+
typeof value !== 'number' ||
|
|
58
|
+
!Number.isSafeInteger(value) ||
|
|
59
|
+
value < 0 ||
|
|
60
|
+
value > 0xffff_ffff
|
|
61
|
+
) {
|
|
62
|
+
throw new RangeError(`Project.setAssistSidecar: ${field} must be a uint32`);
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function validateAssistSidecarPpq(value: unknown, field: string): number {
|
|
68
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
|
|
69
|
+
throw new RangeError(
|
|
70
|
+
`Project.setAssistSidecar: ${field} must be a finite, non-negative number`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateAssistSidecarPayload(value: unknown): Uint8Array {
|
|
77
|
+
if (!(value instanceof Uint8Array)) {
|
|
78
|
+
throw new TypeError('Project.setAssistSidecar: payload must be a Uint8Array');
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function validateAssistSidecarModuleId(value: unknown): string {
|
|
84
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
85
|
+
throw new TypeError('Project.setAssistSidecar: moduleId must be a non-empty string');
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
|
|
52
90
|
/**
|
|
53
91
|
* Headless DAW project (control-thread-only arrangement model).
|
|
54
92
|
*
|
|
@@ -82,6 +120,11 @@ export class Project {
|
|
|
82
120
|
this.native = new (projectModule().Project)();
|
|
83
121
|
}
|
|
84
122
|
|
|
123
|
+
/** Create a new empty project. */
|
|
124
|
+
static create(): Project {
|
|
125
|
+
return new Project();
|
|
126
|
+
}
|
|
127
|
+
|
|
85
128
|
/** Pack a MIDI 1.0 note-on event accepted by {@link setMidiEvents}. */
|
|
86
129
|
static midiNoteOn(
|
|
87
130
|
ppq: number,
|
|
@@ -462,6 +505,19 @@ export class Project {
|
|
|
462
505
|
this.native.setMaxUndoDepth(depth);
|
|
463
506
|
}
|
|
464
507
|
|
|
508
|
+
/** Set the combined undo/redo history byte cap. Zero disables retention. */
|
|
509
|
+
setMaxHistoryBytes(bytes: number): void {
|
|
510
|
+
if (typeof bytes !== 'number') {
|
|
511
|
+
throw new TypeError('Project.setMaxHistoryBytes: bytes must be a number');
|
|
512
|
+
}
|
|
513
|
+
if (!Number.isFinite(bytes) || !Number.isInteger(bytes) || bytes < 0 || bytes > 0xffff_ffff) {
|
|
514
|
+
throw new RangeError(
|
|
515
|
+
'Project.setMaxHistoryBytes: bytes must be a finite integer in the uint32 range',
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
this.native.setMaxHistoryBytes(bytes);
|
|
519
|
+
}
|
|
520
|
+
|
|
465
521
|
/** Replace a MIDI clip's entire event list. */
|
|
466
522
|
setMidiEvents(
|
|
467
523
|
clipId: number,
|
|
@@ -625,8 +681,11 @@ export class Project {
|
|
|
625
681
|
* Karplus-Strong / modal / additive / percussion / extended-waveguide-piano
|
|
626
682
|
* engines plus the realism layer). Pass a {@link SynthPatch}, a preset-name
|
|
627
683
|
* string (`'saw-lead'` / `'va:saw-lead'`; see {@link synthPresetNames}), or
|
|
628
|
-
* an array of either; each object entry may carry
|
|
629
|
-
*
|
|
684
|
+
* an array of either; each object entry may carry `destinationId` (default
|
|
685
|
+
* 0) and `useGmPrograms` (default `false`) binding conveniences, neither of
|
|
686
|
+
* which is part of the NativeSynth patch itself. When enabled, MIDI program
|
|
687
|
+
* changes select the corresponding General MIDI voice while the patch remains
|
|
688
|
+
* the fallback.
|
|
630
689
|
* Because the parameter defaults to `{}`, omission and explicit `undefined`
|
|
631
690
|
* both create one default binding. Use an explicitly empty array `[]` (or
|
|
632
691
|
* runtime `null`) for zero bindings. Unknown preset names throw.
|
|
@@ -722,6 +781,11 @@ export class Project {
|
|
|
722
781
|
this.native.setSourceAudio(sourceId, audio, channels, sampleRate);
|
|
723
782
|
}
|
|
724
783
|
|
|
784
|
+
/** Replace an audio source's metadata strings as one undoable edit. */
|
|
785
|
+
setAudioSourceMetadata(sourceId: number, contentHash: string, externalStemRole: string): void {
|
|
786
|
+
this.native.setAudioSourceMetadata(sourceId, contentHash, externalStemRole);
|
|
787
|
+
}
|
|
788
|
+
|
|
725
789
|
/** Replace a clip's take list and active take id (undoable). */
|
|
726
790
|
setClipTakes(clipId: number, takes: ReadonlyArray<ProjectClipTake>, activeTakeId = 0): void {
|
|
727
791
|
this.native.setClipTakes(clipId, takes, activeTakeId);
|
|
@@ -778,10 +842,16 @@ export class Project {
|
|
|
778
842
|
|
|
779
843
|
/** Append an automation lane; returns its stable target parameter id (undoable). */
|
|
780
844
|
addAutomationLane(trackId: number, desc: ProjectAutomationLaneDesc): number {
|
|
781
|
-
|
|
782
|
-
targetParamId
|
|
783
|
-
|
|
784
|
-
}
|
|
845
|
+
if (desc.targetParamId === 0) {
|
|
846
|
+
throw new RangeError('project automation lane targetParamId must be non-zero');
|
|
847
|
+
}
|
|
848
|
+
const nativeDesc: ProjectAutomationLaneDesc = { ...desc };
|
|
849
|
+
if (Object.keys(desc).includes('targetKind')) {
|
|
850
|
+
nativeDesc.targetKind = projectAutomationTargetKindValue(
|
|
851
|
+
desc.targetKind as ProjectAutomationTargetKind,
|
|
852
|
+
) as ProjectAutomationTargetKind;
|
|
853
|
+
}
|
|
854
|
+
return this.native.addAutomationLane(trackId, nativeDesc);
|
|
785
855
|
}
|
|
786
856
|
|
|
787
857
|
/** Replace the lane identified by its stable target parameter id (undoable). */
|
|
@@ -790,10 +860,16 @@ export class Project {
|
|
|
790
860
|
targetParamId: number,
|
|
791
861
|
desc: ProjectAutomationLaneDesc,
|
|
792
862
|
): void {
|
|
793
|
-
|
|
794
|
-
targetParamId
|
|
795
|
-
|
|
796
|
-
}
|
|
863
|
+
if (desc.targetParamId === 0) {
|
|
864
|
+
throw new RangeError('project automation lane targetParamId must be non-zero');
|
|
865
|
+
}
|
|
866
|
+
const nativeDesc: ProjectAutomationLaneDesc = { ...desc };
|
|
867
|
+
if (Object.keys(desc).includes('targetKind')) {
|
|
868
|
+
nativeDesc.targetKind = projectAutomationTargetKindValue(
|
|
869
|
+
desc.targetKind as ProjectAutomationTargetKind,
|
|
870
|
+
) as ProjectAutomationTargetKind;
|
|
871
|
+
}
|
|
872
|
+
this.native.editAutomationLane(trackId, targetParamId, nativeDesc);
|
|
797
873
|
}
|
|
798
874
|
|
|
799
875
|
/** Remove the lane identified by its stable target parameter id (undoable). */
|
|
@@ -811,7 +887,14 @@ export class Project {
|
|
|
811
887
|
this.native.annotateChords(chords);
|
|
812
888
|
}
|
|
813
889
|
|
|
814
|
-
/**
|
|
890
|
+
/**
|
|
891
|
+
* Add or update an opaque assist sidecar via an undoable edit.
|
|
892
|
+
*
|
|
893
|
+
* The descriptor form is the canonical API and matches the Node binding;
|
|
894
|
+
* the positional form remains available for compatibility with the original
|
|
895
|
+
* WASM facade.
|
|
896
|
+
*/
|
|
897
|
+
setAssistSidecar(sidecar: ProjectAssistSidecarInput): void;
|
|
815
898
|
setAssistSidecar(
|
|
816
899
|
moduleId: string,
|
|
817
900
|
schemaVersion: number,
|
|
@@ -819,14 +902,52 @@ export class Project {
|
|
|
819
902
|
regionStartPpq: number,
|
|
820
903
|
regionEndPpq: number,
|
|
821
904
|
payload: Uint8Array,
|
|
905
|
+
): void;
|
|
906
|
+
setAssistSidecar(
|
|
907
|
+
sidecarOrModuleId: ProjectAssistSidecarInput | string,
|
|
908
|
+
schemaVersion?: number,
|
|
909
|
+
targetTrackId?: number,
|
|
910
|
+
regionStartPpq?: number,
|
|
911
|
+
regionEndPpq?: number,
|
|
912
|
+
payload?: Uint8Array,
|
|
822
913
|
): void {
|
|
914
|
+
if (typeof sidecarOrModuleId === 'string') {
|
|
915
|
+
if (
|
|
916
|
+
schemaVersion === undefined ||
|
|
917
|
+
targetTrackId === undefined ||
|
|
918
|
+
regionStartPpq === undefined ||
|
|
919
|
+
regionEndPpq === undefined ||
|
|
920
|
+
payload === undefined
|
|
921
|
+
) {
|
|
922
|
+
throw new TypeError('Project.setAssistSidecar: positional form requires six arguments');
|
|
923
|
+
}
|
|
924
|
+
this.native.setAssistSidecar(
|
|
925
|
+
validateAssistSidecarModuleId(sidecarOrModuleId),
|
|
926
|
+
validateAssistSidecarUint32(schemaVersion, 'schemaVersion'),
|
|
927
|
+
validateAssistSidecarUint32(targetTrackId, 'targetTrackId'),
|
|
928
|
+
validateAssistSidecarPpq(regionStartPpq, 'regionStartPpq'),
|
|
929
|
+
validateAssistSidecarPpq(regionEndPpq, 'regionEndPpq'),
|
|
930
|
+
validateAssistSidecarPayload(payload),
|
|
931
|
+
);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (
|
|
936
|
+
sidecarOrModuleId === null ||
|
|
937
|
+
typeof sidecarOrModuleId !== 'object' ||
|
|
938
|
+
Array.isArray(sidecarOrModuleId)
|
|
939
|
+
) {
|
|
940
|
+
throw new TypeError('Project.setAssistSidecar: expected a sidecar descriptor object');
|
|
941
|
+
}
|
|
942
|
+
const sidecar = sidecarOrModuleId;
|
|
943
|
+
const moduleId = validateAssistSidecarModuleId(sidecar.moduleId);
|
|
823
944
|
this.native.setAssistSidecar(
|
|
824
945
|
moduleId,
|
|
825
|
-
schemaVersion,
|
|
826
|
-
targetTrackId,
|
|
827
|
-
regionStartPpq,
|
|
828
|
-
regionEndPpq,
|
|
829
|
-
payload,
|
|
946
|
+
validateAssistSidecarUint32(sidecar.schemaVersion ?? 0, 'schemaVersion'),
|
|
947
|
+
validateAssistSidecarUint32(sidecar.targetTrackId ?? 0, 'targetTrackId'),
|
|
948
|
+
validateAssistSidecarPpq(sidecar.regionStartPpq ?? 0, 'regionStartPpq'),
|
|
949
|
+
validateAssistSidecarPpq(sidecar.regionEndPpq ?? 0, 'regionEndPpq'),
|
|
950
|
+
validateAssistSidecarPayload(sidecar.payload ?? new Uint8Array()),
|
|
830
951
|
);
|
|
831
952
|
}
|
|
832
953
|
|
|
@@ -840,6 +961,12 @@ export class Project {
|
|
|
840
961
|
return this.native.getAssistSidecar(index);
|
|
841
962
|
}
|
|
842
963
|
|
|
964
|
+
/** Read every stored assist sidecar in the same order as the index getter. */
|
|
965
|
+
assistSidecars(): ProjectAssistSidecar[] {
|
|
966
|
+
const count = this.assistSidecarCount();
|
|
967
|
+
return Array.from({ length: count }, (_, index) => this.getAssistSidecar(index));
|
|
968
|
+
}
|
|
969
|
+
|
|
843
970
|
/** Set the project's clip-overlap policy (SonareProjectOverlapPolicy ordinal). */
|
|
844
971
|
setOverlapPolicy(policy: number): void {
|
|
845
972
|
this.native.setOverlapPolicy(policy);
|
package/src/project_internal.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { getSonareModule } from './module_state';
|
|
|
3
3
|
import type {
|
|
4
4
|
BuiltinSynthBinding,
|
|
5
5
|
ProjectAssistSidecar,
|
|
6
|
+
ProjectAutomationLaneDesc,
|
|
6
7
|
ProjectAutomationPoint,
|
|
8
|
+
ProjectAutomationTargetKind,
|
|
7
9
|
ProjectBounceOptions,
|
|
8
10
|
ProjectChordSymbol,
|
|
9
11
|
ProjectClip,
|
|
@@ -65,6 +67,7 @@ export interface WasmProject {
|
|
|
65
67
|
redo: () => void;
|
|
66
68
|
clearHistory: () => void;
|
|
67
69
|
setMaxUndoDepth: (depth: number) => void;
|
|
70
|
+
setMaxHistoryBytes: (bytes: number) => void;
|
|
68
71
|
setMidiEvents: (
|
|
69
72
|
clipId: number,
|
|
70
73
|
events: ReadonlyArray<ProjectMidiEvent | readonly [number, number, number]>,
|
|
@@ -120,6 +123,7 @@ export interface WasmProject {
|
|
|
120
123
|
channels: number,
|
|
121
124
|
sampleRate: number,
|
|
122
125
|
) => void;
|
|
126
|
+
setAudioSourceMetadata: (sourceId: number, contentHash: string, externalStemRole: string) => void;
|
|
123
127
|
setClipTakes: (
|
|
124
128
|
clipId: number,
|
|
125
129
|
takes: ReadonlyArray<ProjectClipTake>,
|
|
@@ -137,14 +141,11 @@ export interface WasmProject {
|
|
|
137
141
|
removeTrack: (trackId: number) => void;
|
|
138
142
|
renameTrack: (trackId: number, name: string) => void;
|
|
139
143
|
setTrackRoute: (trackId: number, channelStripRef: string, outputTarget: string) => void;
|
|
140
|
-
addAutomationLane: (
|
|
141
|
-
trackId: number,
|
|
142
|
-
desc: { targetParamId: number; points: ReadonlyArray<ProjectAutomationPoint> },
|
|
143
|
-
) => number;
|
|
144
|
+
addAutomationLane: (trackId: number, desc: ProjectAutomationLaneDesc) => number;
|
|
144
145
|
editAutomationLane: (
|
|
145
146
|
trackId: number,
|
|
146
147
|
targetParamId: number,
|
|
147
|
-
desc:
|
|
148
|
+
desc: ProjectAutomationLaneDesc,
|
|
148
149
|
) => void;
|
|
149
150
|
removeAutomationLane: (trackId: number, targetParamId: number) => void;
|
|
150
151
|
annotateKeys: (keys: ReadonlyArray<ProjectKeySegment>) => void;
|
|
@@ -325,6 +326,14 @@ export function projectTrackKindValue(kind: ProjectTrackKind | undefined): numbe
|
|
|
325
326
|
return resolveEnumOrdinal(kind ?? 'audio', { audio: 0, midi: 1, aux: 2 }, 'project track kind');
|
|
326
327
|
}
|
|
327
328
|
|
|
329
|
+
export function projectAutomationTargetKindValue(kind: ProjectAutomationTargetKind): number {
|
|
330
|
+
return resolveEnumOrdinal(
|
|
331
|
+
kind,
|
|
332
|
+
{ opaque: 0, 'track-fader-db': 1, 'track-pan': 2 },
|
|
333
|
+
'project automation target kind',
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
328
337
|
export function projectWarpModeValue(mode: ProjectWarpMode | undefined): number {
|
|
329
338
|
return resolveEnumOrdinal(
|
|
330
339
|
mode ?? 'off',
|
package/src/project_types.ts
CHANGED
|
@@ -110,6 +110,10 @@ export interface ProjectSource {
|
|
|
110
110
|
storageHandleId: number;
|
|
111
111
|
sampleRateHint: number;
|
|
112
112
|
nameOrUri: string;
|
|
113
|
+
/** Owning content hash for audio sources; empty for MIDI sources. */
|
|
114
|
+
contentHash: string;
|
|
115
|
+
/** External source-separation role for audio sources; empty for MIDI sources. */
|
|
116
|
+
externalStemRole: string;
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
/** Names accepted by the minimal built-in oscillator synth. */
|
|
@@ -314,6 +318,8 @@ export interface SynthPatch {
|
|
|
314
318
|
* `(destination_id, patch)` bindings instead. Defaults to `0`.
|
|
315
319
|
*/
|
|
316
320
|
destinationId?: number;
|
|
321
|
+
/** Resolve MIDI channels from incoming GM bank/program changes; defaults to false. */
|
|
322
|
+
useGmPrograms?: boolean;
|
|
317
323
|
/** Base preset name (see {@link synthPresetNames}); omit for the init patch. */
|
|
318
324
|
preset?: string;
|
|
319
325
|
engineMode?: SynthEngineMode | number;
|
|
@@ -448,12 +454,34 @@ export interface ProjectAutomationPoint {
|
|
|
448
454
|
curve?: ProjectAutomationCurve;
|
|
449
455
|
}
|
|
450
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Persistent target classification for an automation lane.
|
|
459
|
+
*
|
|
460
|
+
* The numeric ordinals mirror `SonareAutomationTargetKind`; the string names
|
|
461
|
+
* are the public WASM spellings accepted by the project facade.
|
|
462
|
+
*/
|
|
463
|
+
export const AutomationTargetKind = {
|
|
464
|
+
opaque: 0,
|
|
465
|
+
trackFaderDb: 1,
|
|
466
|
+
trackPan: 2,
|
|
467
|
+
} as const;
|
|
468
|
+
|
|
469
|
+
/** Accepted automation target kind name or ABI ordinal. */
|
|
470
|
+
export type ProjectAutomationTargetKind = 'opaque' | 'track-fader-db' | 'track-pan' | 0 | 1 | 2;
|
|
471
|
+
|
|
472
|
+
/** Numeric aliases matching the C-ABI enum names. */
|
|
473
|
+
export const PROJECT_AUTOMATION_TARGET_OPAQUE = AutomationTargetKind.opaque;
|
|
474
|
+
export const PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB = AutomationTargetKind.trackFaderDb;
|
|
475
|
+
export const PROJECT_AUTOMATION_TARGET_TRACK_PAN = AutomationTargetKind.trackPan;
|
|
476
|
+
|
|
451
477
|
/** Automation-lane descriptor for {@link Project.addAutomationLane}. */
|
|
452
478
|
export interface ProjectAutomationLaneDesc {
|
|
453
|
-
/** Host-defined id of the parameter the lane drives. */
|
|
479
|
+
/** Host-defined, non-zero id of the parameter the lane drives (zero is reserved). */
|
|
454
480
|
targetParamId: number;
|
|
455
481
|
/** Breakpoints (stored verbatim). */
|
|
456
482
|
points: ReadonlyArray<ProjectAutomationPoint>;
|
|
483
|
+
/** Optional persistent target classification; omission retains the legacy opaque route. */
|
|
484
|
+
targetKind?: ProjectAutomationTargetKind;
|
|
457
485
|
}
|
|
458
486
|
|
|
459
487
|
/** One tempo segment for {@link Project.setTempoSegments}. */
|
|
@@ -515,6 +543,22 @@ export interface ProjectChordSymbol {
|
|
|
515
543
|
modulationBoundary?: boolean;
|
|
516
544
|
}
|
|
517
545
|
|
|
546
|
+
/** Descriptor accepted by {@link Project.setAssistSidecar}. */
|
|
547
|
+
export interface ProjectAssistSidecarInput {
|
|
548
|
+
/** Non-empty module id key. */
|
|
549
|
+
moduleId: string;
|
|
550
|
+
/** Module-defined schema version. Defaults to `0`. */
|
|
551
|
+
schemaVersion?: number;
|
|
552
|
+
/** Target track id (`0` = project scope). Defaults to `0`. */
|
|
553
|
+
targetTrackId?: number;
|
|
554
|
+
/** Region start in PPQ. Defaults to `0`. */
|
|
555
|
+
regionStartPpq?: number;
|
|
556
|
+
/** Region end in PPQ. Defaults to `0`. */
|
|
557
|
+
regionEndPpq?: number;
|
|
558
|
+
/** Opaque module-owned payload bytes. Defaults to an empty payload. */
|
|
559
|
+
payload?: Uint8Array;
|
|
560
|
+
}
|
|
561
|
+
|
|
518
562
|
/** Assist sidecar snapshot returned by {@link Project.getAssistSidecar}. */
|
|
519
563
|
export interface ProjectAssistSidecar {
|
|
520
564
|
moduleId: string;
|
|
@@ -90,6 +90,22 @@ export type AutomationCurve = 'linear' | 'exponential' | 'hold' | 's-curve';
|
|
|
90
90
|
*/
|
|
91
91
|
export type PanLaw = 'const3dB' | 'const4.5dB' | 'const6dB' | 'linear0dB';
|
|
92
92
|
|
|
93
|
+
/** Accepted pan-law name aliases for mixer and realtime-engine inputs. */
|
|
94
|
+
export type PanLawName =
|
|
95
|
+
| PanLaw
|
|
96
|
+
| 'const-3db'
|
|
97
|
+
| '-3db'
|
|
98
|
+
| 'const-4.5db'
|
|
99
|
+
| '-4.5db'
|
|
100
|
+
| 'const-6db'
|
|
101
|
+
| '-6db'
|
|
102
|
+
| 'linear-0db'
|
|
103
|
+
| 'linear'
|
|
104
|
+
| '0db';
|
|
105
|
+
|
|
106
|
+
/** Pan-law name or raw C ABI ordinal. */
|
|
107
|
+
export type PanLawInput = PanLawName | number;
|
|
108
|
+
|
|
93
109
|
/**
|
|
94
110
|
* Meter tap point for reading a strip's meter snapshot
|
|
95
111
|
* (see {@link Mixer.meterTap} and {@link Mixer.stripMeter}).
|
|
@@ -105,15 +105,33 @@ export type VoicePresetId =
|
|
|
105
105
|
| 'robot-mascot'
|
|
106
106
|
| 'dark-villain';
|
|
107
107
|
|
|
108
|
-
export
|
|
108
|
+
export type VoicePresetCategory =
|
|
109
|
+
| 'monitor'
|
|
110
|
+
| 'bright'
|
|
111
|
+
| 'soft'
|
|
112
|
+
| 'deep'
|
|
113
|
+
| 'robot'
|
|
114
|
+
| 'dark'
|
|
115
|
+
| 'custom';
|
|
116
|
+
|
|
117
|
+
export interface RealtimeVoiceChangerPresetMetadata {
|
|
109
118
|
schemaVersion: 1;
|
|
110
|
-
id
|
|
111
|
-
name
|
|
119
|
+
id: string;
|
|
120
|
+
name: string;
|
|
112
121
|
description?: string;
|
|
113
|
-
|
|
114
|
-
dsp?: Record<string, unknown>;
|
|
122
|
+
category: VoicePresetCategory;
|
|
115
123
|
}
|
|
116
124
|
|
|
125
|
+
export type RealtimeVoiceChangerPreset =
|
|
126
|
+
| (RealtimeVoiceChangerPresetMetadata & {
|
|
127
|
+
dsp: Record<string, unknown>;
|
|
128
|
+
macros?: never;
|
|
129
|
+
})
|
|
130
|
+
| (RealtimeVoiceChangerPresetMetadata & {
|
|
131
|
+
macros: Record<string, number>;
|
|
132
|
+
dsp?: never;
|
|
133
|
+
});
|
|
134
|
+
|
|
117
135
|
export type RealtimeVoiceChangerConfigInput = VoicePresetId | RealtimeVoiceChangerPreset;
|
|
118
136
|
|
|
119
137
|
/**
|