@libraz/libsonare 1.8.1 → 1.8.2
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 +5 -5
- package/dist/analysis.js +2 -0
- package/dist/analysis.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1927 -140
- package/dist/index.js.map +1 -1
- package/dist/instrument_types.d.ts +27 -3
- package/dist/instrument_types.d.ts.map +1 -1
- package/dist/mastering_core.d.ts +3 -2
- package/dist/mastering_core.d.ts.map +1 -1
- package/dist/mixer.d.ts +2 -2
- package/dist/project.d.ts +5 -4
- package/dist/project.d.ts.map +1 -1
- package/dist/project_class.d.ts +57 -3
- package/dist/project_class.d.ts.map +1 -1
- package/dist/project_internal.d.ts +35 -1
- package/dist/project_internal.d.ts.map +1 -1
- package/dist/project_types.d.ts +10 -1
- package/dist/project_types.d.ts.map +1 -1
- package/dist/public_types.d.ts +1 -0
- package/dist/public_types.d.ts.map +1 -1
- package/dist/public_types_mastering.d.ts +1 -1
- package/dist/public_types_mastering.d.ts.map +1 -1
- package/dist/public_types_vocal_edit.d.ts +250 -0
- package/dist/public_types_vocal_edit.d.ts.map +1 -0
- package/dist/public_types_vocal_project.d.ts +63 -0
- package/dist/public_types_vocal_project.d.ts.map +1 -0
- package/dist/realtime_engine.d.ts +57 -10
- package/dist/realtime_engine.d.ts.map +1 -1
- package/dist/repair_dereverb.d.ts +1 -0
- package/dist/repair_dereverb.d.ts.map +1 -1
- package/dist/repair_noise.d.ts +1 -0
- package/dist/repair_noise.d.ts.map +1 -1
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.d.ts +53 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/vocal_edit.d.ts +131 -0
- package/dist/vocal_edit.d.ts.map +1 -0
- package/dist/vocal_edit_worker.d.ts +51 -0
- package/dist/vocal_edit_worker.d.ts.map +1 -0
- package/dist/vocal_edit_worker.js +1462 -0
- package/dist/vocal_edit_worker.js.map +1 -0
- package/dist/vocal_edit_worker_client.d.ts +118 -0
- package/dist/vocal_edit_worker_client.d.ts.map +1 -0
- package/dist/vocal_edit_worker_protocol.d.ts +139 -0
- package/dist/vocal_edit_worker_protocol.d.ts.map +1 -0
- package/dist/vocal_project.d.ts +17 -0
- package/dist/vocal_project.d.ts.map +1 -0
- package/dist/web_midi.d.ts +4 -0
- package/dist/web_midi.d.ts.map +1 -1
- package/dist/worker.js.map +1 -1
- package/dist/worklet/engine-mixer-facade.d.ts +2 -1
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -1
- package/dist/worklet/engine-node.d.ts +8 -0
- package/dist/worklet/engine-node.d.ts.map +1 -1
- package/dist/worklet/engine-processor.d.ts +2 -1
- package/dist/worklet/engine-processor.d.ts.map +1 -1
- package/dist/worklet/engine-register.d.ts.map +1 -1
- package/dist/worklet/engine-strips.d.ts +4 -2
- package/dist/worklet/engine-strips.d.ts.map +1 -1
- package/dist/worklet/engine.d.ts +15 -3
- package/dist/worklet/engine.d.ts.map +1 -1
- package/dist/worklet/guards.d.ts +3 -1
- package/dist/worklet/guards.d.ts.map +1 -1
- package/dist/worklet/messages.d.ts +50 -5
- package/dist/worklet/messages.d.ts.map +1 -1
- package/dist/worklet/protocol.d.ts +10 -0
- package/dist/worklet/protocol.d.ts.map +1 -1
- package/dist/worklet.d.ts +1 -1
- package/dist/worklet.d.ts.map +1 -1
- package/dist/worklet.js +223 -16
- package/dist/worklet.js.map +1 -1
- package/package.json +6 -1
- package/src/index.ts +33 -0
- package/src/instrument_types.ts +29 -3
- package/src/mastering_core.ts +3 -2
- package/src/mixer.ts +2 -2
- package/src/project.ts +8 -1
- package/src/project_class.ts +136 -1
- package/src/project_internal.ts +90 -0
- package/src/project_types.ts +11 -1
- package/src/public_types.ts +1 -0
- package/src/public_types_mastering.ts +2 -0
- package/src/public_types_vocal_edit.ts +289 -0
- package/src/public_types_vocal_project.ts +69 -0
- package/src/realtime_engine.ts +86 -9
- package/src/repair_dereverb.ts +1 -0
- package/src/repair_noise.ts +1 -0
- package/src/sonare.js.d.ts +53 -0
- package/src/vocal_edit.ts +885 -0
- package/src/vocal_edit_worker.ts +832 -0
- package/src/vocal_edit_worker_client.ts +812 -0
- package/src/vocal_edit_worker_protocol.ts +206 -0
- package/src/vocal_project.ts +327 -0
- package/src/web_midi.ts +100 -5
- package/src/worklet/engine-mixer-facade.ts +2 -1
- package/src/worklet/engine-node.ts +47 -0
- package/src/worklet/engine-processor.ts +46 -1
- package/src/worklet/engine-register.ts +3 -0
- package/src/worklet/engine-strips.ts +31 -4
- package/src/worklet/engine.ts +27 -3
- package/src/worklet/guards.ts +26 -0
- package/src/worklet/messages.ts +59 -2
- package/src/worklet/protocol.ts +10 -0
- package/src/worklet.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libraz/libsonare",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "yarn@4.18.0",
|
|
6
6
|
"description": "Audio analysis, mastering, mixing, and MIDI synthesis in WebAssembly",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"types": "./dist/worker.d.ts",
|
|
24
24
|
"import": "./dist/worker.js"
|
|
25
25
|
},
|
|
26
|
+
"./vocal-edit-worker": {
|
|
27
|
+
"types": "./dist/vocal_edit_worker.d.ts",
|
|
28
|
+
"import": "./dist/vocal_edit_worker.js"
|
|
29
|
+
},
|
|
26
30
|
"./wasm": "./dist/sonare.wasm",
|
|
27
31
|
"./schemas/realtime-voice-changer-preset.schema.json": "./dist/schemas/realtime-voice-changer-preset.schema.json",
|
|
28
32
|
"./schemas/realtime-voice-changer-preset-pack.schema.json": "./dist/schemas/realtime-voice-changer-preset-pack.schema.json",
|
|
@@ -60,6 +64,7 @@
|
|
|
60
64
|
"test:browser": "node scripts/audio-worklet-smoke.mjs",
|
|
61
65
|
"test:browser:worker": "node scripts/offline-worker-smoke.mjs",
|
|
62
66
|
"test:browser:boundary": "node scripts/boundary-smoke.mjs",
|
|
67
|
+
"test:browser:vocal-worker": "node scripts/vocal-edit-worker-smoke.mjs",
|
|
63
68
|
"test:watch": "vitest",
|
|
64
69
|
"prepublishOnly": "yarn clean && cp ../../LICENSE LICENSE && cp ../../NOTICE NOTICE && yarn build && yarn lint && yarn test && yarn test:types"
|
|
65
70
|
},
|
package/src/index.ts
CHANGED
|
@@ -546,6 +546,9 @@ export type {
|
|
|
546
546
|
MidiCcLearnOptions,
|
|
547
547
|
MpeDimension,
|
|
548
548
|
NoteTracking,
|
|
549
|
+
PartRig,
|
|
550
|
+
PartRigInsert,
|
|
551
|
+
PartRigMode,
|
|
549
552
|
ProjectAssistSidecar,
|
|
550
553
|
ProjectAssistSidecarInput,
|
|
551
554
|
ProjectAutomationCurve,
|
|
@@ -560,6 +563,7 @@ export type {
|
|
|
560
563
|
ProjectClipFade,
|
|
561
564
|
ProjectClipTake,
|
|
562
565
|
ProjectCompileResult,
|
|
566
|
+
ProjectCompileTimelineResult,
|
|
563
567
|
ProjectFadeCurve,
|
|
564
568
|
ProjectKeySegment,
|
|
565
569
|
ProjectLoopMode,
|
|
@@ -617,10 +621,13 @@ export {
|
|
|
617
621
|
MarkerKind,
|
|
618
622
|
MPE_DIMENSIONS,
|
|
619
623
|
NOTE_TRACKINGS,
|
|
624
|
+
PART_RIG_ALL_PARTS,
|
|
625
|
+
PART_RIG_MODES,
|
|
620
626
|
PROJECT_AUTOMATION_TARGET_OPAQUE,
|
|
621
627
|
PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,
|
|
622
628
|
PROJECT_AUTOMATION_TARGET_TRACK_PAN,
|
|
623
629
|
Project,
|
|
630
|
+
ProjectTimeline,
|
|
624
631
|
projectAbiVersion,
|
|
625
632
|
SAMPLE_KEY_TRACKS,
|
|
626
633
|
SAMPLE_LOOP_MODES,
|
|
@@ -835,6 +842,7 @@ export {
|
|
|
835
842
|
PitchClass,
|
|
836
843
|
SectionType,
|
|
837
844
|
} from './public_types';
|
|
845
|
+
export type * from './public_types_vocal_edit';
|
|
838
846
|
export type {
|
|
839
847
|
AnalyzeBpmRequest,
|
|
840
848
|
AnalyzeDynamicsRequest,
|
|
@@ -959,6 +967,29 @@ export {
|
|
|
959
967
|
export type { TranscribeRequest } from './transcribe';
|
|
960
968
|
export { transcribe } from './transcribe';
|
|
961
969
|
export type { ValidateOptions } from './validation';
|
|
970
|
+
export {
|
|
971
|
+
createVocalEditSession,
|
|
972
|
+
restoreVocalEditSession,
|
|
973
|
+
VocalEditDraft,
|
|
974
|
+
VocalEditSession,
|
|
975
|
+
VocalRenderJob,
|
|
976
|
+
VocalRenderSnapshot,
|
|
977
|
+
vocalEditApiVersion,
|
|
978
|
+
vocalEditAvailable,
|
|
979
|
+
} from './vocal_edit';
|
|
980
|
+
export type {
|
|
981
|
+
VocalEditWorker,
|
|
982
|
+
VocalEditWorkerCallOptions,
|
|
983
|
+
VocalEditWorkerClientOptions,
|
|
984
|
+
VocalEditWorkerTransferOptions,
|
|
985
|
+
} from './vocal_edit_worker_client';
|
|
986
|
+
export {
|
|
987
|
+
VocalEditWorkerClient,
|
|
988
|
+
VocalEditWorkerSession,
|
|
989
|
+
VocalEditWorkerStaleResultError,
|
|
990
|
+
VocalEditWorkerTask,
|
|
991
|
+
} from './vocal_edit_worker_client';
|
|
992
|
+
export type * from './vocal_edit_worker_protocol';
|
|
962
993
|
export type {
|
|
963
994
|
BindWebMidiOptions,
|
|
964
995
|
WebMidiBinding,
|
|
@@ -1154,3 +1185,5 @@ export function realtimeVoiceChangerPresetConfig(
|
|
|
1154
1185
|
// ============================================================================
|
|
1155
1186
|
|
|
1156
1187
|
export { PitchClass as Pitch } from './public_types';
|
|
1188
|
+
|
|
1189
|
+
export type * from './public_types_vocal_project';
|
package/src/instrument_types.ts
CHANGED
|
@@ -228,6 +228,16 @@ export const CONTROLLER_AXES = [
|
|
|
228
228
|
*/
|
|
229
229
|
export const ARTICULATIONS = ['poly', 'mono-retrigger', 'mono-legato'] as const;
|
|
230
230
|
|
|
231
|
+
/**
|
|
232
|
+
* How a part's signal path is built. `'bank'` keeps whatever the instrument's
|
|
233
|
+
* own bank/program selection resolves to, `'none'` bypasses the rig stage, and
|
|
234
|
+
* `'chain'` replaces it with an explicit insert chain.
|
|
235
|
+
*/
|
|
236
|
+
export const PART_RIG_MODES = ['bank', 'none', 'chain'] as const;
|
|
237
|
+
|
|
238
|
+
/** The `part` value that addresses a destination's default instead of one part (0-15). */
|
|
239
|
+
export const PART_RIG_ALL_PARTS = 0xff;
|
|
240
|
+
|
|
231
241
|
/** The three dimensions MPE carries per note ({@link RealtimeEngine.setControllerNoteTracking}). */
|
|
232
242
|
export const MPE_DIMENSIONS = ['bend', 'pressure', 'timbre'] as const;
|
|
233
243
|
|
|
@@ -380,6 +390,23 @@ export type ControllerAxis = (typeof CONTROLLER_AXES)[number];
|
|
|
380
390
|
/** Per-channel note-overlap rule ({@link RealtimeEngine.setArticulation}). */
|
|
381
391
|
export type Articulation = (typeof ARTICULATIONS)[number];
|
|
382
392
|
|
|
393
|
+
/** How a part's rig is built ({@link PART_RIG_MODES}). */
|
|
394
|
+
export type PartRigMode = (typeof PART_RIG_MODES)[number];
|
|
395
|
+
|
|
396
|
+
/** One stage of a `'chain'` part rig: a processor name and its parameters. */
|
|
397
|
+
export interface PartRigInsert {
|
|
398
|
+
processor: string;
|
|
399
|
+
/** Processor parameters, as an object or an already-serialized JSON object string. */
|
|
400
|
+
params?: Record<string, unknown> | string;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** A part rig as stored on a project ({@link Project.getPartRig}). */
|
|
404
|
+
export interface PartRig {
|
|
405
|
+
mode: PartRigMode;
|
|
406
|
+
/** Present for `'chain'` only; `params` is the parsed parameter object. */
|
|
407
|
+
inserts?: { processor: string; params: Record<string, unknown> }[];
|
|
408
|
+
}
|
|
409
|
+
|
|
383
410
|
/** One per-note MPE dimension ({@link MPE_DIMENSIONS}). */
|
|
384
411
|
export type MpeDimension = (typeof MPE_DIMENSIONS)[number];
|
|
385
412
|
|
|
@@ -582,9 +609,8 @@ export interface SynthPatch {
|
|
|
582
609
|
* whose per-note kit patch replaces this whole section and never reads it.
|
|
583
610
|
*
|
|
584
611
|
* Also automatable under this same name through
|
|
585
|
-
* {@link RealtimeEngine.resolveInstrumentAutomationId}; it
|
|
586
|
-
*
|
|
587
|
-
* next note.
|
|
612
|
+
* {@link RealtimeEngine.resolveInstrumentAutomationId}; it reaches
|
|
613
|
+
* already-sounding voices from the next processed block.
|
|
588
614
|
*/
|
|
589
615
|
pitchOffsetCents?: number;
|
|
590
616
|
ampAttackMs?: number;
|
package/src/mastering_core.ts
CHANGED
|
@@ -924,11 +924,12 @@ export function masteringAssistantSuggestChainStereo(
|
|
|
924
924
|
/**
|
|
925
925
|
* Mastering assistant profile of a stereo pair, as shared JSON.
|
|
926
926
|
*
|
|
927
|
-
*
|
|
927
|
+
* The `loudness` block is measured from the two channels: integrated LUFS
|
|
928
928
|
* and LRA come from the channel-summed program and the true peak is the larger
|
|
929
929
|
* of the two. The spectral, dynamics and tempo fields describe shape and timing
|
|
930
930
|
* rather than absolute level and are measured on the downmix, which keeps them
|
|
931
|
-
* comparable with {@link masteringAudioProfile}.
|
|
931
|
+
* comparable with {@link masteringAudioProfile}. Defect detectors run on each
|
|
932
|
+
* channel and their results are aggregated.
|
|
932
933
|
*/
|
|
933
934
|
export function masteringAudioProfileStereo(request: MasteringStereoParamsRequest): string {
|
|
934
935
|
return requireModule().masteringAudioProfileStereo(
|
package/src/mixer.ts
CHANGED
|
@@ -504,8 +504,8 @@ export class Mixer {
|
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
/**
|
|
507
|
-
* Set a per-strip channel delay in samples
|
|
508
|
-
*
|
|
507
|
+
* Set a per-strip channel delay in samples, moving the strip later relative to
|
|
508
|
+
* the others. It is not latency: latency compensation does not undo it.
|
|
509
509
|
*/
|
|
510
510
|
setChannelDelaySamples(stripIndex: number, delaySamples: number): void {
|
|
511
511
|
this.mixer.setChannelDelaySamples(stripIndex, delaySamples);
|
package/src/project.ts
CHANGED
|
@@ -8,6 +8,9 @@ export type {
|
|
|
8
8
|
ControllerInput,
|
|
9
9
|
MpeDimension,
|
|
10
10
|
NoteTracking,
|
|
11
|
+
PartRig,
|
|
12
|
+
PartRigInsert,
|
|
13
|
+
PartRigMode,
|
|
11
14
|
SampleDesc,
|
|
12
15
|
SampleDescLoopMode,
|
|
13
16
|
SampleKeyTrack,
|
|
@@ -35,6 +38,8 @@ export {
|
|
|
35
38
|
CONTROLLER_INPUTS,
|
|
36
39
|
MPE_DIMENSIONS,
|
|
37
40
|
NOTE_TRACKINGS,
|
|
41
|
+
PART_RIG_ALL_PARTS,
|
|
42
|
+
PART_RIG_MODES,
|
|
38
43
|
SAMPLE_KEY_TRACKS,
|
|
39
44
|
SAMPLE_LOOP_MODES,
|
|
40
45
|
SYNTH_BODY_TYPES,
|
|
@@ -46,7 +51,7 @@ export {
|
|
|
46
51
|
SYNTH_OSC_WAVEFORMS,
|
|
47
52
|
SYNTH_RETRIGGERS,
|
|
48
53
|
} from './instrument_types';
|
|
49
|
-
export { Project } from './project_class';
|
|
54
|
+
export { Project, ProjectTimeline } from './project_class';
|
|
50
55
|
export {
|
|
51
56
|
controllerProfileNames,
|
|
52
57
|
projectAbiVersion,
|
|
@@ -79,6 +84,7 @@ export type {
|
|
|
79
84
|
ProjectClipFade,
|
|
80
85
|
ProjectClipTake,
|
|
81
86
|
ProjectCompileResult,
|
|
87
|
+
ProjectCompileTimelineResult,
|
|
82
88
|
ProjectDeserializeResult,
|
|
83
89
|
ProjectDiagnostic,
|
|
84
90
|
ProjectFadeCurve,
|
|
@@ -121,4 +127,5 @@ export {
|
|
|
121
127
|
PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,
|
|
122
128
|
PROJECT_AUTOMATION_TARGET_TRACK_PAN,
|
|
123
129
|
} from './project_types';
|
|
130
|
+
export type * from './public_types_vocal_project';
|
|
124
131
|
export { SampleBank } from './sample_bank';
|
package/src/project_class.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BuiltinSynthBinding,
|
|
3
|
+
PartRig,
|
|
4
|
+
PartRigInsert,
|
|
5
|
+
PartRigMode,
|
|
3
6
|
Sf2InstrumentConfig,
|
|
4
7
|
Sf2ProgramStatus,
|
|
5
8
|
SynthPatch,
|
|
@@ -7,6 +10,8 @@ import type {
|
|
|
7
10
|
import {
|
|
8
11
|
assertProjectMidiEvents,
|
|
9
12
|
normalizeSynthInstrument,
|
|
13
|
+
partRigFromNative,
|
|
14
|
+
partRigInsertsJson,
|
|
10
15
|
projectAutomationPointValue,
|
|
11
16
|
projectAutomationTargetKindValue,
|
|
12
17
|
projectLoopModeValue,
|
|
@@ -14,7 +19,10 @@ import {
|
|
|
14
19
|
projectModule,
|
|
15
20
|
projectTrackKindValue,
|
|
16
21
|
projectWarpModeValue,
|
|
22
|
+
registerProjectTimeline,
|
|
23
|
+
unregisterProjectTimeline,
|
|
17
24
|
type WasmProject,
|
|
25
|
+
type WasmProjectTimeline,
|
|
18
26
|
} from './project_internal';
|
|
19
27
|
import type {
|
|
20
28
|
ExternalSeparatedStemImportRequest,
|
|
@@ -33,6 +41,7 @@ import type {
|
|
|
33
41
|
ProjectClipFade,
|
|
34
42
|
ProjectClipTake,
|
|
35
43
|
ProjectCompileResult,
|
|
44
|
+
ProjectCompileTimelineResult,
|
|
36
45
|
ProjectDeserializeResult,
|
|
37
46
|
ProjectKeySegment,
|
|
38
47
|
ProjectLoopMode,
|
|
@@ -60,6 +69,13 @@ import type {
|
|
|
60
69
|
ProjectWarpMapDesc,
|
|
61
70
|
ProjectWarpMode,
|
|
62
71
|
} from './project_types';
|
|
72
|
+
import type {
|
|
73
|
+
ProjectVocalEditApplyRequest,
|
|
74
|
+
ProjectVocalEditApplyResult,
|
|
75
|
+
ProjectVocalEditDependency,
|
|
76
|
+
ProjectVocalOriginalSource,
|
|
77
|
+
ProjectVocalRehydrateItem,
|
|
78
|
+
} from './public_types_vocal_project';
|
|
63
79
|
import {
|
|
64
80
|
assertBoundedInteger,
|
|
65
81
|
assertNibble,
|
|
@@ -67,6 +83,11 @@ import {
|
|
|
67
83
|
assertSamples,
|
|
68
84
|
assertU7,
|
|
69
85
|
} from './validation';
|
|
86
|
+
import {
|
|
87
|
+
projectApplyVocalEdit,
|
|
88
|
+
projectGetVocalEditDependencies,
|
|
89
|
+
projectRehydrateVocalEdits,
|
|
90
|
+
} from './vocal_project';
|
|
70
91
|
|
|
71
92
|
/**
|
|
72
93
|
* Folds the positional and request call forms of `bakeMidiFx` into one shape,
|
|
@@ -171,6 +192,47 @@ function midi2Byte(fnName: string, value: number, argName: string): number {
|
|
|
171
192
|
return value;
|
|
172
193
|
}
|
|
173
194
|
|
|
195
|
+
/**
|
|
196
|
+
* An immutable compiled snapshot of a {@link Project}, produced by
|
|
197
|
+
* {@link Project.compileTimeline} and installed into a stopped realtime engine
|
|
198
|
+
* with `RealtimeEngine.applyProjectTimeline`.
|
|
199
|
+
*
|
|
200
|
+
* An engine keeps its own reference after an apply, so {@link dispose} may be
|
|
201
|
+
* called right afterwards. The embind handle is not garbage-collected; release
|
|
202
|
+
* it when no further apply needs it.
|
|
203
|
+
*/
|
|
204
|
+
export class ProjectTimeline {
|
|
205
|
+
private native: WasmProjectTimeline | null;
|
|
206
|
+
|
|
207
|
+
/** @internal */
|
|
208
|
+
constructor(native: WasmProjectTimeline) {
|
|
209
|
+
this.native = native;
|
|
210
|
+
registerProjectTimeline(this, native);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Identity an engine names this timeline by, so no raw pointer crosses into JS.
|
|
215
|
+
*
|
|
216
|
+
* @internal
|
|
217
|
+
*/
|
|
218
|
+
get nativeId(): number {
|
|
219
|
+
if (this.native === null) {
|
|
220
|
+
throw new TypeError('ProjectTimeline is disposed');
|
|
221
|
+
}
|
|
222
|
+
return this.native.id;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Release the underlying WASM object. Idempotent. */
|
|
226
|
+
dispose(): void {
|
|
227
|
+
if (this.native === null) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
unregisterProjectTimeline(this);
|
|
231
|
+
this.native.delete();
|
|
232
|
+
this.native = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
174
236
|
/**
|
|
175
237
|
* Headless DAW project (control-thread-only arrangement model).
|
|
176
238
|
*
|
|
@@ -199,7 +261,33 @@ function midi2Byte(fnName: string, value: number, argName: string): number {
|
|
|
199
261
|
*/
|
|
200
262
|
export class Project {
|
|
201
263
|
private native: WasmProject;
|
|
264
|
+
|
|
265
|
+
applyVocalEdit(request: ProjectVocalEditApplyRequest): ProjectVocalEditApplyResult {
|
|
266
|
+
return projectApplyVocalEdit(this.native, request);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getVocalEditDependencies(): ProjectVocalEditDependency[] {
|
|
270
|
+
return projectGetVocalEditDependencies(this.native);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
rehydrateVocalEdits(
|
|
274
|
+
originals: readonly ProjectVocalOriginalSource[],
|
|
275
|
+
cancel?: () => boolean,
|
|
276
|
+
): ProjectVocalRehydrateItem[] {
|
|
277
|
+
this.activeVocalRehydrateCalls += 1;
|
|
278
|
+
try {
|
|
279
|
+
return projectRehydrateVocalEdits(this.native, originals, cancel);
|
|
280
|
+
} finally {
|
|
281
|
+
this.activeVocalRehydrateCalls -= 1;
|
|
282
|
+
if (this.activeVocalRehydrateCalls === 0 && this.deleteRequested) {
|
|
283
|
+
this.native.delete();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
202
288
|
private released = false;
|
|
289
|
+
private deleteRequested = false;
|
|
290
|
+
private activeVocalRehydrateCalls = 0;
|
|
203
291
|
|
|
204
292
|
constructor() {
|
|
205
293
|
this.native = new (projectModule().Project)();
|
|
@@ -798,6 +886,34 @@ export class Project {
|
|
|
798
886
|
this.native.setTrackGain(trackId, gain);
|
|
799
887
|
}
|
|
800
888
|
|
|
889
|
+
/**
|
|
890
|
+
* Set the rig of one part (0-15), or of the destination's default when `part`
|
|
891
|
+
* is {@link PART_RIG_ALL_PARTS}, on MIDI destination `destinationId`, via an
|
|
892
|
+
* undoable edit. `'chain'` takes 1-8 `inserts` and is the only mode that does;
|
|
893
|
+
* a destination no track references is stored and read back all the same.
|
|
894
|
+
* Refused: a malformed insert document (invalid format), an out-of-range part,
|
|
895
|
+
* an unknown mode or processor, or inserts on a non-chain mode (invalid
|
|
896
|
+
* parameter), and an insert chain in a build without mastering.
|
|
897
|
+
*/
|
|
898
|
+
setPartRig(
|
|
899
|
+
destinationId: number,
|
|
900
|
+
part: number,
|
|
901
|
+
mode: PartRigMode | number,
|
|
902
|
+
inserts?: PartRigInsert[],
|
|
903
|
+
): void {
|
|
904
|
+
this.native.setPartRig(destinationId, part, mode, partRigInsertsJson(inserts));
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/** The stored rig for `(destinationId, part)`, or null when none is stored. */
|
|
908
|
+
getPartRig(destinationId: number, part: number): PartRig | null {
|
|
909
|
+
return partRigFromNative(this.native.getPartRig(destinationId, part));
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/** Remove the stored rig for `(destinationId, part)` via an undoable edit (no-op when absent). */
|
|
913
|
+
clearPartRig(destinationId: number, part: number): void {
|
|
914
|
+
this.native.clearPartRig(destinationId, part);
|
|
915
|
+
}
|
|
916
|
+
|
|
801
917
|
/** Set a track's mute flag via an undoable edit (a muted track is silent). */
|
|
802
918
|
setTrackMute(trackId: number, mute: boolean): void {
|
|
803
919
|
this.native.setTrackMute(trackId, mute);
|
|
@@ -1059,6 +1175,17 @@ export class Project {
|
|
|
1059
1175
|
return this.native.compile();
|
|
1060
1176
|
}
|
|
1061
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* Compile the project and keep the resulting timeline. The result is
|
|
1180
|
+
* {@link compile}'s plus `timeline`: a {@link ProjectTimeline} to install with
|
|
1181
|
+
* `RealtimeEngine.applyProjectTimeline`, or `null` when an error diagnostic
|
|
1182
|
+
* means nothing compiled.
|
|
1183
|
+
*/
|
|
1184
|
+
compileTimeline(): ProjectCompileTimelineResult {
|
|
1185
|
+
const { timeline, ...result } = this.native.compileTimeline();
|
|
1186
|
+
return { ...result, timeline: timeline === null ? null : new ProjectTimeline(timeline) };
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1062
1189
|
/**
|
|
1063
1190
|
* Compile + render the project offline to interleaved float audio. MIDI
|
|
1064
1191
|
* tracks render silently here (no instrument is bound) — use
|
|
@@ -1540,12 +1667,20 @@ export class Project {
|
|
|
1540
1667
|
return this.native.lastBounceCompileResult();
|
|
1541
1668
|
}
|
|
1542
1669
|
|
|
1543
|
-
/**
|
|
1670
|
+
/**
|
|
1671
|
+
* Release the underlying WASM object. Idempotent, as the Node facade is.
|
|
1672
|
+
* Called from a rehydrate cancel callback, the release happens when the
|
|
1673
|
+
* outermost {@link rehydrateVocalEdits} call returns.
|
|
1674
|
+
*/
|
|
1544
1675
|
delete(): void {
|
|
1545
1676
|
if (this.released) {
|
|
1546
1677
|
return;
|
|
1547
1678
|
}
|
|
1548
1679
|
this.released = true;
|
|
1680
|
+
if (this.activeVocalRehydrateCalls !== 0) {
|
|
1681
|
+
this.deleteRequested = true;
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1549
1684
|
this.native.delete();
|
|
1550
1685
|
}
|
|
1551
1686
|
|
package/src/project_internal.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { projectAutomationCurveCode, resolveEnumOrdinal } from './codes';
|
|
2
2
|
import type {
|
|
3
3
|
BuiltinSynthBinding,
|
|
4
|
+
PartRig,
|
|
5
|
+
PartRigInsert,
|
|
6
|
+
PartRigMode,
|
|
4
7
|
SampleDesc,
|
|
5
8
|
SampleZoneDesc,
|
|
6
9
|
Sf2InstrumentConfig,
|
|
@@ -77,6 +80,38 @@ export interface WasmSampleBank {
|
|
|
77
80
|
delete: () => void;
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
// Embind handle for the C++ `ProjectTimelineWasm` class. Registered next to the
|
|
84
|
+
// project, so a build without arrangement support has neither.
|
|
85
|
+
export interface WasmProjectTimeline {
|
|
86
|
+
readonly id: number;
|
|
87
|
+
delete: () => void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const projectTimelineHandles = new WeakMap<object, WasmProjectTimeline>();
|
|
91
|
+
|
|
92
|
+
/** Internal: registers the facade object whose identity may cross to the engine. */
|
|
93
|
+
export function registerProjectTimeline(owner: object, native: WasmProjectTimeline): void {
|
|
94
|
+
projectTimelineHandles.set(owner, native);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Internal: removes a disposed facade from the identity registry. */
|
|
98
|
+
export function unregisterProjectTimeline(owner: object): void {
|
|
99
|
+
projectTimelineHandles.delete(owner);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Internal: resolves only a timeline facade created by this module. */
|
|
103
|
+
export function projectTimelineNativeId(owner: unknown): number | undefined {
|
|
104
|
+
if (owner === null || (typeof owner !== 'object' && typeof owner !== 'function')) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return projectTimelineHandles.get(owner)?.id;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** `compileTimeline` as the embind layer returns it, before the facade wraps the handle. */
|
|
111
|
+
export type NativeProjectCompileTimelineResult = ProjectCompileResult & {
|
|
112
|
+
timeline: WasmProjectTimeline | null;
|
|
113
|
+
};
|
|
114
|
+
|
|
80
115
|
/**
|
|
81
116
|
* Swaps a facade {@link SampleBank} in a synth patch descriptor for the id the
|
|
82
117
|
* embind layer looks the native bank up by, leaving every other field alone.
|
|
@@ -114,12 +149,55 @@ export function normalizeSynthInstrument(patch: unknown): NativeSynthBinding | s
|
|
|
114
149
|
return { ...rest, sampleBankId: sampleBank.nativeId };
|
|
115
150
|
}
|
|
116
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Serializes a part rig's inserts into the JSON array the native layer reads
|
|
154
|
+
* (`params` always a JSON object string), or undefined when none were given.
|
|
155
|
+
*/
|
|
156
|
+
export function partRigInsertsJson(inserts: PartRigInsert[] | undefined): string | undefined {
|
|
157
|
+
if (inserts === undefined || inserts === null) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
if (!Array.isArray(inserts)) {
|
|
161
|
+
throw new TypeError('inserts must be an array');
|
|
162
|
+
}
|
|
163
|
+
return JSON.stringify(
|
|
164
|
+
inserts.map((insert) => {
|
|
165
|
+
const { processor, params } = insert;
|
|
166
|
+
return params === undefined
|
|
167
|
+
? { processor }
|
|
168
|
+
: { processor, params: typeof params === 'string' ? params : JSON.stringify(params) };
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Reads a native `{ mode, insertsJson }` part rig back into the public shape. */
|
|
174
|
+
export function partRigFromNative(
|
|
175
|
+
native: { mode: PartRig['mode']; insertsJson: string | null } | null,
|
|
176
|
+
): PartRig | null {
|
|
177
|
+
if (native === null) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
if (native.insertsJson === null) {
|
|
181
|
+
return { mode: native.mode };
|
|
182
|
+
}
|
|
183
|
+
const inserts = (JSON.parse(native.insertsJson) as { processor: string; params: string }[]).map(
|
|
184
|
+
({ processor, params }) => ({
|
|
185
|
+
processor,
|
|
186
|
+
params: JSON.parse(params) as Record<string, unknown>,
|
|
187
|
+
}),
|
|
188
|
+
);
|
|
189
|
+
return { mode: native.mode, inserts };
|
|
190
|
+
}
|
|
191
|
+
|
|
117
192
|
// Embind handle for the C++ `ProjectWasm` class. `SonareModule` describes the
|
|
118
193
|
// raw module's free functions and does not carry bound-class handles, so the
|
|
119
194
|
// module is narrowed through this shape here — which is also where the
|
|
120
195
|
// arrangement surface is probed for, since a build without arrangement support
|
|
121
196
|
// registers neither the class nor its free functions.
|
|
122
197
|
export interface WasmProject {
|
|
198
|
+
applyVocalEdit: (request: unknown) => unknown;
|
|
199
|
+
getVocalEditDependencies: () => unknown;
|
|
200
|
+
rehydrateVocalEdits: (originals: unknown, cancel?: unknown) => unknown;
|
|
123
201
|
toJson: () => string;
|
|
124
202
|
setSampleRate: (sampleRate: number) => void;
|
|
125
203
|
addTrack: (desc: { kind?: number | string; name?: string }) => number;
|
|
@@ -140,6 +218,17 @@ export interface WasmProject {
|
|
|
140
218
|
setTrackMute: (trackId: number, mute: boolean) => void;
|
|
141
219
|
setTrackSolo: (trackId: number, solo: boolean) => void;
|
|
142
220
|
setTrackPan: (trackId: number, pan: number) => void;
|
|
221
|
+
setPartRig: (
|
|
222
|
+
destinationId: number,
|
|
223
|
+
part: number,
|
|
224
|
+
mode: PartRigMode | number,
|
|
225
|
+
insertsJson: string | undefined,
|
|
226
|
+
) => void;
|
|
227
|
+
getPartRig: (
|
|
228
|
+
destinationId: number,
|
|
229
|
+
part: number,
|
|
230
|
+
) => { mode: PartRigMode; insertsJson: string | null } | null;
|
|
231
|
+
clearPartRig: (destinationId: number, part: number) => void;
|
|
143
232
|
undo: () => void;
|
|
144
233
|
redo: () => void;
|
|
145
234
|
clearHistory: () => void;
|
|
@@ -186,6 +275,7 @@ export interface WasmProject {
|
|
|
186
275
|
) => number;
|
|
187
276
|
snapToGrid: (ppq: number, strength: number, division: number) => number;
|
|
188
277
|
compile: () => ProjectCompileResult;
|
|
278
|
+
compileTimeline: () => NativeProjectCompileTimelineResult;
|
|
189
279
|
bounce: (options: ProjectBounceOptions) => Float32Array;
|
|
190
280
|
bounceWithBuiltinInstrument: (
|
|
191
281
|
bindings: BuiltinSynthBinding | ReadonlyArray<BuiltinSynthBinding> | undefined,
|
package/src/project_types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Type-only, so the erased import adds no runtime edge to the codes module.
|
|
2
2
|
import type { PROJECT_AUTOMATION_CURVE_VALUES } from './codes';
|
|
3
|
-
import type { Project } from './project_class';
|
|
3
|
+
import type { Project, ProjectTimeline } from './project_class';
|
|
4
4
|
|
|
5
5
|
// ============================================================================
|
|
6
6
|
// Headless DAW Project
|
|
@@ -721,6 +721,16 @@ export interface ProjectCompileResult {
|
|
|
721
721
|
diagnostics: ProjectDiagnostic[];
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
+
/** Result of {@link Project.compileTimeline}: the compile diagnostics plus the timeline they produced. */
|
|
725
|
+
export interface ProjectCompileTimelineResult extends ProjectCompileResult {
|
|
726
|
+
/**
|
|
727
|
+
* The compiled timeline, or `null` when compilation produced none (an error
|
|
728
|
+
* diagnostic; read {@link ProjectCompileResult.diagnostics}). Release it with
|
|
729
|
+
* {@link ProjectTimeline.dispose}.
|
|
730
|
+
*/
|
|
731
|
+
timeline: ProjectTimeline | null;
|
|
732
|
+
}
|
|
733
|
+
|
|
724
734
|
export interface ProjectDeserializeResult {
|
|
725
735
|
project: Project;
|
|
726
736
|
diagnostics: string;
|
package/src/public_types.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface SonareCapabilities {
|
|
|
41
41
|
arrangement: boolean;
|
|
42
42
|
acousticSim: boolean;
|
|
43
43
|
pitchEditor: boolean;
|
|
44
|
+
vocalEdit: boolean;
|
|
44
45
|
voiceChanger: boolean;
|
|
45
46
|
/** True when the playback renderer (upmix, binaural, speaker output) is compiled in. */
|
|
46
47
|
playback: boolean;
|
|
@@ -132,9 +132,11 @@ export const SOLO_PROCESSORS = [
|
|
|
132
132
|
'repair.trimSilence',
|
|
133
133
|
'saturation.ampSim',
|
|
134
134
|
'saturation.bitcrusher',
|
|
135
|
+
'saturation.distortion',
|
|
135
136
|
'saturation.exciter',
|
|
136
137
|
'saturation.hardClipper',
|
|
137
138
|
'saturation.multibandExciter',
|
|
139
|
+
'saturation.overdrive',
|
|
138
140
|
'saturation.softClipper',
|
|
139
141
|
'saturation.tape',
|
|
140
142
|
'saturation.transformer',
|