@libraz/libsonare 1.5.5 → 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 +109 -20
- package/dist/analysis.d.ts +5809 -0
- package/dist/analysis.js +2574 -0
- package/dist/analysis.js.map +1 -0
- package/dist/index.d.ts +884 -55
- package/dist/index.js +1302 -292
- package/dist/index.js.map +1 -1
- package/dist/schemas/realtime-voice-changer-preset-pack.schema.json +27 -0
- package/dist/schemas/realtime-voice-changer-preset.schema.json +140 -0
- package/dist/sonare-analysis.js +2 -0
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worker.d.ts +65 -0
- package/dist/worker.js +734 -0
- package/dist/worker.js.map +1 -0
- package/dist/worklet.d.ts +628 -88
- package/dist/worklet.js +1816 -266
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -11
- package/src/_chain_config.ts +5 -3
- package/src/analysis.ts +137 -0
- package/src/analysis_helpers.ts +40 -29
- package/src/audio.ts +7 -2
- package/src/clip_page_streamer.ts +62 -8
- package/src/codes.ts +87 -64
- package/src/effects_mastering.ts +1 -0
- package/src/effects_transform.ts +179 -10
- package/src/errors.ts +1 -0
- package/src/feature_core.ts +140 -2
- package/src/feature_music.ts +25 -3
- package/src/feature_pitch.ts +70 -1
- package/src/feature_spectral.ts +295 -7
- package/src/feature_spectrogram.ts +203 -3
- package/src/features.ts +16 -1
- package/src/index.ts +120 -8
- package/src/mastering_chain.ts +20 -8
- package/src/mastering_core.ts +5 -0
- package/src/mastering_dynamics.ts +7 -1
- package/src/metering.ts +6 -1
- package/src/mixer.ts +3 -3
- package/src/opfs_clip_pages.ts +26 -1
- package/src/project.ts +13 -0
- package/src/project_class.ts +204 -23
- package/src/project_internal.ts +38 -34
- package/src/project_types.ts +114 -11
- package/src/public_types.ts +68 -0
- package/src/public_types_mastering.ts +22 -0
- package/src/public_types_mixing.ts +27 -2
- package/src/public_types_music.ts +9 -0
- package/src/public_types_realtime.ts +23 -5
- package/src/public_types_spectral.ts +33 -0
- package/src/quick_analysis.ts +46 -10
- package/src/realtime_engine.ts +167 -6
- package/src/realtime_voice_changer.ts +51 -77
- package/src/sonare-analysis.js.d.ts +8 -0
- package/src/sonare.js.d.ts +340 -6
- package/src/stream_analyzer.ts +6 -1
- package/src/streaming_processors.ts +15 -0
- package/src/web_midi.ts +46 -11
- package/src/worker.ts +196 -0
- package/src/worker_client.ts +352 -0
- package/src/worker_protocol.ts +59 -0
- package/src/worklet/engine-automation.ts +2 -1
- package/src/worklet/engine-capture-facade.ts +13 -4
- package/src/worklet/engine-clips.ts +12 -3
- package/src/worklet/engine-node.ts +264 -21
- package/src/worklet/engine-offline.ts +7 -2
- package/src/worklet/engine-parameter-facade.ts +55 -5
- package/src/worklet/engine-processor.ts +435 -62
- package/src/worklet/engine-register.ts +9 -1
- package/src/worklet/engine-strips.ts +19 -3
- package/src/worklet/engine-sync.ts +2 -6
- package/src/worklet/engine-tempo-facade.ts +8 -6
- package/src/worklet/engine.ts +390 -13
- package/src/worklet/guards.ts +121 -8
- package/src/worklet/messages.ts +166 -8
- package/src/worklet/protocol.ts +305 -17
- package/src/worklet/voice-changer-processor.ts +12 -15
- package/src/worklet.ts +20 -1
package/src/public_types.ts
CHANGED
|
@@ -4,3 +4,71 @@ export * from './public_types_mixing';
|
|
|
4
4
|
export * from './public_types_music';
|
|
5
5
|
export * from './public_types_realtime';
|
|
6
6
|
export * from './public_types_spectral';
|
|
7
|
+
|
|
8
|
+
/** Runtime capabilities reported by the loaded libsonare build. */
|
|
9
|
+
export interface SonareCapabilities {
|
|
10
|
+
version: string;
|
|
11
|
+
abi: {
|
|
12
|
+
project: number;
|
|
13
|
+
engine: number;
|
|
14
|
+
};
|
|
15
|
+
platform: string;
|
|
16
|
+
features: {
|
|
17
|
+
mastering: boolean;
|
|
18
|
+
mixing: boolean;
|
|
19
|
+
fx: boolean;
|
|
20
|
+
ffmpeg: boolean;
|
|
21
|
+
};
|
|
22
|
+
decode: {
|
|
23
|
+
builtin: string[];
|
|
24
|
+
ffmpeg: string[];
|
|
25
|
+
};
|
|
26
|
+
simd: string;
|
|
27
|
+
hardwareConcurrency: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** One parameter descriptor in the cross-surface capability catalog. */
|
|
31
|
+
export interface CapabilityCatalogParameter {
|
|
32
|
+
name: string;
|
|
33
|
+
id: number;
|
|
34
|
+
rtSafe: boolean;
|
|
35
|
+
type: 'boolean' | 'number';
|
|
36
|
+
min: number | null;
|
|
37
|
+
max: number | null;
|
|
38
|
+
default: boolean | number | null;
|
|
39
|
+
unit: string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** One named mastering processor and its host-facing capabilities. */
|
|
43
|
+
export interface CapabilityCatalogProcessor {
|
|
44
|
+
id: string;
|
|
45
|
+
kind: 'realtime' | 'offline' | 'pair';
|
|
46
|
+
realtimeInsertable: boolean;
|
|
47
|
+
stereoOnly: boolean;
|
|
48
|
+
latencySamples: number;
|
|
49
|
+
tailSamples: number;
|
|
50
|
+
/** Coarse realtime work estimate, or null when the processor is not an insert. */
|
|
51
|
+
realtimeCost: 'low' | 'moderate' | 'high' | null;
|
|
52
|
+
channelPolicy: 'multichannel' | 'stereoPairOnly' | 'perChannel' | 'passthrough';
|
|
53
|
+
category: string;
|
|
54
|
+
params: CapabilityCatalogParameter[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Built-in preset names grouped by feature family. */
|
|
58
|
+
export interface CapabilityCatalogPresets {
|
|
59
|
+
mastering: string[];
|
|
60
|
+
synth: string[];
|
|
61
|
+
mixingScene: string[];
|
|
62
|
+
voiceChanger: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Complete runtime catalog exposed by {@link capabilityCatalog}. */
|
|
66
|
+
export interface CapabilityCatalog {
|
|
67
|
+
version: string;
|
|
68
|
+
abi: SonareCapabilities['abi'];
|
|
69
|
+
processors: CapabilityCatalogProcessor[];
|
|
70
|
+
presets: CapabilityCatalogPresets;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Synchronous progress callback for offline operations. Its return value is ignored. */
|
|
74
|
+
export type ProgressCallback = (progress: number, stage: string) => void;
|
|
@@ -394,6 +394,26 @@ export interface StageGainReduction {
|
|
|
394
394
|
gainReductionDb: number;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
+
/** Existing EBU R128 measurements captured before or after mastering. */
|
|
398
|
+
export interface MasteringLoudnessSummary {
|
|
399
|
+
integratedLufs: number;
|
|
400
|
+
maxMomentaryLufs: number;
|
|
401
|
+
maxShortTermLufs: number;
|
|
402
|
+
truePeakDbtp: number;
|
|
403
|
+
loudnessRange: number;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Compact explanation of how an offline mastering chain changed a program. */
|
|
407
|
+
export interface MasteringReport {
|
|
408
|
+
before: MasteringLoudnessSummary;
|
|
409
|
+
after: MasteringLoudnessSummary;
|
|
410
|
+
appliedGainDb: number;
|
|
411
|
+
maxGainReductionDb: number;
|
|
412
|
+
loudnessTargetLimited: boolean;
|
|
413
|
+
/** 32 logarithmically-spaced after-minus-before spectral energy deltas (dB). */
|
|
414
|
+
bandEnergyDeltaDb: Float32Array;
|
|
415
|
+
}
|
|
416
|
+
|
|
397
417
|
export interface MasteringChainResult {
|
|
398
418
|
/** Latency-compensated offline output; no separate latency field is reported. */
|
|
399
419
|
samples: Float32Array;
|
|
@@ -414,6 +434,7 @@ export interface MasteringChainResult {
|
|
|
414
434
|
loudnessTargetLimited: boolean;
|
|
415
435
|
/** Per-stage gain reductions for the dynamics/maximizer stages (a subset of `stages`). */
|
|
416
436
|
stageGainReductions: StageGainReduction[];
|
|
437
|
+
report: MasteringReport;
|
|
417
438
|
}
|
|
418
439
|
|
|
419
440
|
export interface MasteringChainStereoResult {
|
|
@@ -429,6 +450,7 @@ export interface MasteringChainStereoResult {
|
|
|
429
450
|
outputLra: number;
|
|
430
451
|
loudnessTargetLimited: boolean;
|
|
431
452
|
stageGainReductions: StageGainReduction[];
|
|
453
|
+
report: MasteringReport;
|
|
432
454
|
}
|
|
433
455
|
|
|
434
456
|
/**
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
export type PanMode =
|
|
1
|
+
export type PanMode =
|
|
2
|
+
| 'balance'
|
|
3
|
+
| 'pan'
|
|
4
|
+
| 'stereoPan'
|
|
5
|
+
| 'stereo-pan'
|
|
6
|
+
| 'dualPan'
|
|
7
|
+
| 'dual-pan'
|
|
8
|
+
| number;
|
|
2
9
|
|
|
3
10
|
/**
|
|
4
11
|
* Surround pan position for a strip feeding a >2-channel bus. Phase 1 honors
|
|
@@ -77,10 +84,28 @@ export type AutomationCurve = 'linear' | 'exponential' | 'hold' | 's-curve';
|
|
|
77
84
|
|
|
78
85
|
/**
|
|
79
86
|
* Pan law applied when computing left/right gains from a pan position
|
|
80
|
-
* (see {@link Mixer.setPanLaw}).
|
|
87
|
+
* (see {@link Mixer.setPanLaw}). On mono strips it changes the centre gain;
|
|
88
|
+
* on stereo Balance strips it changes only the far-channel taper, while centre
|
|
89
|
+
* remains unity. Maps to the underlying integer code.
|
|
81
90
|
*/
|
|
82
91
|
export type PanLaw = 'const3dB' | 'const4.5dB' | 'const6dB' | 'linear0dB';
|
|
83
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
|
+
|
|
84
109
|
/**
|
|
85
110
|
* Meter tap point for reading a strip's meter snapshot
|
|
86
111
|
* (see {@link Mixer.meterTap} and {@link Mixer.stripMeter}).
|
|
@@ -315,6 +315,13 @@ export interface TimeSignature {
|
|
|
315
315
|
confidence: number;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/** Existing tempo-estimator hypothesis retained by unified analysis. */
|
|
319
|
+
export interface BpmHypothesis {
|
|
320
|
+
value: number;
|
|
321
|
+
confidence: number;
|
|
322
|
+
relation: 'primary' | 'half' | 'double' | 'other';
|
|
323
|
+
}
|
|
324
|
+
|
|
318
325
|
/**
|
|
319
326
|
* Rhythm features
|
|
320
327
|
*/
|
|
@@ -343,8 +350,10 @@ export interface MelodyContour {
|
|
|
343
350
|
export interface AnalysisResult {
|
|
344
351
|
bpm: number;
|
|
345
352
|
bpmConfidence: number;
|
|
353
|
+
bpmCandidates: BpmHypothesis[];
|
|
346
354
|
key: Key;
|
|
347
355
|
timeSignature: TimeSignature;
|
|
356
|
+
timeSignatureCandidates: TimeSignature[];
|
|
348
357
|
beatTimes: Float32Array;
|
|
349
358
|
beats: Beat[];
|
|
350
359
|
chords: Chord[];
|
|
@@ -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
|
/**
|
|
@@ -182,6 +182,39 @@ export interface PitchResult {
|
|
|
182
182
|
meanF0: number;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/** Per-bin pitch candidates and peak magnitudes from spectral piptrack. */
|
|
186
|
+
export interface PiptrackResult {
|
|
187
|
+
nBins: number;
|
|
188
|
+
nFrames: number;
|
|
189
|
+
pitches: Float32Array;
|
|
190
|
+
magnitudes: Float32Array;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Magnitude and reassigned time/frequency coordinates for every STFT bin. */
|
|
194
|
+
export interface ReassignedSpectrogramResult {
|
|
195
|
+
nBins: number;
|
|
196
|
+
nFrames: number;
|
|
197
|
+
magnitude: Float32Array;
|
|
198
|
+
times: Float32Array;
|
|
199
|
+
frequencies: Float32Array;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Row-major matrix returned by librosa.segment-compatible APIs. */
|
|
203
|
+
export interface SegmentMatrix {
|
|
204
|
+
rows: number;
|
|
205
|
+
cols: number;
|
|
206
|
+
values: Float32Array;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** One stable monophonic note region segmented from an F0 track. */
|
|
210
|
+
export interface NoteSegment {
|
|
211
|
+
frameStart: number;
|
|
212
|
+
frameEnd: number;
|
|
213
|
+
startSeconds: number;
|
|
214
|
+
endSeconds: number;
|
|
215
|
+
medianCents: number;
|
|
216
|
+
}
|
|
217
|
+
|
|
185
218
|
/**
|
|
186
219
|
* Loudness measurement result (EBU R128 / ITU-R BS.1770)
|
|
187
220
|
*/
|
package/src/quick_analysis.ts
CHANGED
|
@@ -29,7 +29,12 @@ import type {
|
|
|
29
29
|
import { Mode, PitchClass } from './public_types';
|
|
30
30
|
import type { ProgressCallback, WasmAcousticResult } from './sonare.js';
|
|
31
31
|
import type { ValidateOptions } from './validation';
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
assertFiniteScalar,
|
|
34
|
+
assertNonNegativeInteger,
|
|
35
|
+
assertSampleRate,
|
|
36
|
+
assertSamples,
|
|
37
|
+
} from './validation';
|
|
33
38
|
|
|
34
39
|
function requireModule() {
|
|
35
40
|
return getSonareModule();
|
|
@@ -43,12 +48,29 @@ export interface SamplesRequest extends GuardedOptions {
|
|
|
43
48
|
sampleRate?: number;
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
/** Peak-picking configuration for {@link detectOnsets}. */
|
|
52
|
+
export interface OnsetDetectOptions {
|
|
53
|
+
nFft?: number;
|
|
54
|
+
hopLength?: number;
|
|
55
|
+
threshold?: number;
|
|
56
|
+
preMax?: number;
|
|
57
|
+
postMax?: number;
|
|
58
|
+
preAvg?: number;
|
|
59
|
+
postAvg?: number;
|
|
60
|
+
delta?: number;
|
|
61
|
+
wait?: number;
|
|
62
|
+
backtrack?: boolean;
|
|
63
|
+
backtrackRange?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface DetectOnsetsRequest extends SamplesRequest, OnsetDetectOptions {}
|
|
66
|
+
|
|
46
67
|
/** Canonical request form for key detection functions. */
|
|
47
68
|
export interface DetectKeyRequest extends KeyDetectionOptions, SamplesRequest {}
|
|
48
69
|
|
|
49
70
|
/** Canonical request form for analysis with synchronous progress reporting. */
|
|
50
71
|
export interface AnalyzeWithProgressRequest extends SamplesRequest {
|
|
51
|
-
onProgress
|
|
72
|
+
onProgress?: ProgressCallback;
|
|
73
|
+
cancel?: () => boolean;
|
|
52
74
|
}
|
|
53
75
|
|
|
54
76
|
/** Canonical request form for chord detection. */
|
|
@@ -64,6 +86,7 @@ export interface ChordFunctionalAnalysisRequest extends DetectChordsRequest {
|
|
|
64
86
|
/** Canonical request form for impulse-response analysis. */
|
|
65
87
|
export interface AnalyzeImpulseResponseRequest extends SamplesRequest {
|
|
66
88
|
nOctaveBands?: number;
|
|
89
|
+
minDecayDb?: number;
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
/** Canonical request form for acoustic analysis. */
|
|
@@ -207,20 +230,20 @@ export function detectKeyCandidates(
|
|
|
207
230
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
208
231
|
* @returns Array of onset times in seconds
|
|
209
232
|
*/
|
|
210
|
-
export function detectOnsets(request:
|
|
233
|
+
export function detectOnsets(request: DetectOnsetsRequest): Float32Array;
|
|
211
234
|
export function detectOnsets(
|
|
212
235
|
samples: Float32Array,
|
|
213
236
|
sampleRate?: number,
|
|
214
|
-
options?: GuardedOptions,
|
|
237
|
+
options?: OnsetDetectOptions & GuardedOptions,
|
|
215
238
|
): Float32Array;
|
|
216
239
|
export function detectOnsets(
|
|
217
|
-
samples: Float32Array |
|
|
240
|
+
samples: Float32Array | DetectOnsetsRequest,
|
|
218
241
|
sampleRate = 22050,
|
|
219
|
-
options: GuardedOptions = {},
|
|
242
|
+
options: OnsetDetectOptions & GuardedOptions = {},
|
|
220
243
|
): Float32Array {
|
|
221
244
|
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
222
245
|
validateAnalysisInput('detectOnsets', request.samples, request.sampleRate ?? 22050, request);
|
|
223
|
-
return requireModule().detectOnsets(request.samples, request.sampleRate ?? 22050);
|
|
246
|
+
return requireModule().detectOnsets(request.samples, request.sampleRate ?? 22050, request);
|
|
224
247
|
}
|
|
225
248
|
|
|
226
249
|
/**
|
|
@@ -418,23 +441,35 @@ export function analyzeImpulseResponse(
|
|
|
418
441
|
samples: Float32Array,
|
|
419
442
|
sampleRate?: number,
|
|
420
443
|
nOctaveBands?: number,
|
|
444
|
+
minDecayDb?: number,
|
|
421
445
|
): AcousticResult;
|
|
422
446
|
export function analyzeImpulseResponse(
|
|
423
447
|
samples: Float32Array | AnalyzeImpulseResponseRequest,
|
|
424
448
|
sampleRate = 48000,
|
|
425
449
|
nOctaveBands = 6,
|
|
450
|
+
minDecayDb?: number,
|
|
426
451
|
): AcousticResult {
|
|
427
|
-
const request =
|
|
452
|
+
const request =
|
|
453
|
+
samples instanceof Float32Array ? { samples, sampleRate, nOctaveBands, minDecayDb } : samples;
|
|
454
|
+
if (request.minDecayDb === null) {
|
|
455
|
+
throw new TypeError('analyzeImpulseResponse: minDecayDb must be a finite number');
|
|
456
|
+
}
|
|
457
|
+
const resolvedMinDecayDb = request.minDecayDb === undefined ? 30.0 : request.minDecayDb;
|
|
458
|
+
assertFiniteScalar('analyzeImpulseResponse', resolvedMinDecayDb, 'minDecayDb');
|
|
459
|
+
if (resolvedMinDecayDb <= 0) {
|
|
460
|
+
throw new RangeError('analyzeImpulseResponse: minDecayDb must be greater than zero');
|
|
461
|
+
}
|
|
428
462
|
validateAnalysisInput(
|
|
429
463
|
'analyzeImpulseResponse',
|
|
430
464
|
request.samples,
|
|
431
465
|
request.sampleRate ?? 48000,
|
|
432
466
|
request,
|
|
433
467
|
);
|
|
434
|
-
const result: WasmAcousticResult = requireModule().
|
|
468
|
+
const result: WasmAcousticResult = requireModule().analyzeImpulseResponseEx(
|
|
435
469
|
request.samples,
|
|
436
470
|
request.sampleRate ?? 48000,
|
|
437
471
|
request.nOctaveBands ?? 6,
|
|
472
|
+
resolvedMinDecayDb,
|
|
438
473
|
);
|
|
439
474
|
return result;
|
|
440
475
|
}
|
|
@@ -559,7 +594,8 @@ export function analyzeWithProgress(
|
|
|
559
594
|
const result = requireModule().analyzeWithProgress(
|
|
560
595
|
request.samples,
|
|
561
596
|
request.sampleRate ?? 22050,
|
|
562
|
-
request.onProgress,
|
|
597
|
+
request.onProgress ?? (() => {}),
|
|
598
|
+
request.cancel ?? (() => false),
|
|
563
599
|
);
|
|
564
600
|
return convertAnalysisResult(result);
|
|
565
601
|
}
|
package/src/realtime_engine.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { panLawCode, panModeCode, sendTimingCode } from './codes';
|
|
1
|
+
import { panLawCode, panModeCode, sendTimingCode, trackMonitorModeCode } from './codes';
|
|
2
2
|
import { ErrorCode, SonareError } from './errors';
|
|
3
3
|
import { getSonareModule } from './module_state';
|
|
4
4
|
import type { ProjectMidiCcBinding, SynthPatch } from './project';
|
|
5
|
-
import type { EqBand,
|
|
5
|
+
import type { EqBand, PanLawInput, PanMode, SendTiming } from './public_types';
|
|
6
6
|
import type {
|
|
7
7
|
WasmClipPageRequest,
|
|
8
8
|
WasmEngineAutomationPoint,
|
|
@@ -38,6 +38,7 @@ export type EngineMarker = WasmEngineMarker;
|
|
|
38
38
|
export type EngineMetronomeConfig = WasmEngineMetronomeConfig;
|
|
39
39
|
export type EngineGraphSpec = WasmEngineGraphSpec;
|
|
40
40
|
export type EngineCaptureStatus = WasmEngineCaptureStatus;
|
|
41
|
+
export type EngineCaptureSource = EngineCaptureStatus['source'] | number;
|
|
41
42
|
export type EngineBounceOptions = WasmEngineBounceOptions;
|
|
42
43
|
export type EngineBounceResult = WasmEngineBounceResult;
|
|
43
44
|
export type EngineFreezeOptions = WasmEngineFreezeOptions;
|
|
@@ -77,6 +78,12 @@ export interface EngineTrackLane {
|
|
|
77
78
|
sourceChannelLayout?: number;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
/** Per-track cue/monitor tap mode: off, pre-fader listen, or after-fader listen. */
|
|
82
|
+
export type EngineTrackMonitorMode = 'off' | 'pfl' | 'afl' | 0 | 1 | 2;
|
|
83
|
+
|
|
84
|
+
/** Short alias for {@link EngineTrackMonitorMode}. */
|
|
85
|
+
export type TrackMonitorMode = EngineTrackMonitorMode;
|
|
86
|
+
|
|
80
87
|
export interface EngineBus {
|
|
81
88
|
busId: number;
|
|
82
89
|
gainDb?: number;
|
|
@@ -161,6 +168,7 @@ export class RealtimeEngine {
|
|
|
161
168
|
maxBlockSize = 128,
|
|
162
169
|
commandCapacity = 1024,
|
|
163
170
|
telemetryCapacity = 1024,
|
|
171
|
+
maxChannels = 64,
|
|
164
172
|
) {
|
|
165
173
|
const module = getSonareModule();
|
|
166
174
|
const capabilities = engineCapabilities();
|
|
@@ -174,6 +182,7 @@ export class RealtimeEngine {
|
|
|
174
182
|
maxBlockSize,
|
|
175
183
|
commandCapacity,
|
|
176
184
|
telemetryCapacity,
|
|
185
|
+
maxChannels,
|
|
177
186
|
);
|
|
178
187
|
}
|
|
179
188
|
|
|
@@ -182,8 +191,15 @@ export class RealtimeEngine {
|
|
|
182
191
|
maxBlockSize: number,
|
|
183
192
|
commandCapacity = 1024,
|
|
184
193
|
telemetryCapacity = 1024,
|
|
194
|
+
maxChannels = 64,
|
|
185
195
|
): void {
|
|
186
|
-
this.native.
|
|
196
|
+
this.native.prepareWithChannels(
|
|
197
|
+
sampleRate,
|
|
198
|
+
maxBlockSize,
|
|
199
|
+
commandCapacity,
|
|
200
|
+
telemetryCapacity,
|
|
201
|
+
maxChannels,
|
|
202
|
+
);
|
|
187
203
|
}
|
|
188
204
|
|
|
189
205
|
/** Queue a sample-accurate parameter change (engine kSetParam). */
|
|
@@ -209,6 +225,11 @@ export class RealtimeEngine {
|
|
|
209
225
|
this.native.setSoloMute(laneIndex, solo, mute, renderFrame);
|
|
210
226
|
}
|
|
211
227
|
|
|
228
|
+
/** Queue a per-track PFL/AFL monitor tap mode change. */
|
|
229
|
+
setTrackMonitorMode(laneIndex: number, mode: EngineTrackMonitorMode, renderFrame = -1): void {
|
|
230
|
+
this.native.setTrackMonitorMode(laneIndex, trackMonitorModeCode(mode), renderFrame);
|
|
231
|
+
}
|
|
232
|
+
|
|
212
233
|
setMidiClips(clips: readonly EngineMidiClipSchedule[]): void {
|
|
213
234
|
this.native.setMidiClips(clips);
|
|
214
235
|
}
|
|
@@ -256,7 +277,12 @@ export class RealtimeEngine {
|
|
|
256
277
|
* synthesizer GM fallback bank (the data-free floor).
|
|
257
278
|
*/
|
|
258
279
|
setSf2Instrument(
|
|
259
|
-
config: {
|
|
280
|
+
config: {
|
|
281
|
+
destinationId?: number;
|
|
282
|
+
gain?: number;
|
|
283
|
+
polyphony?: number;
|
|
284
|
+
preferModelForModeledFamilies?: boolean;
|
|
285
|
+
} = {},
|
|
260
286
|
destinationId = config.destinationId ?? 0,
|
|
261
287
|
): void {
|
|
262
288
|
this.native.setSf2Instrument(destinationId, config);
|
|
@@ -347,6 +373,10 @@ export class RealtimeEngine {
|
|
|
347
373
|
return this.native.externalMidiDroppedCount();
|
|
348
374
|
}
|
|
349
375
|
|
|
376
|
+
externalMidiPendingCount(): number {
|
|
377
|
+
return this.native.externalMidiPendingCount();
|
|
378
|
+
}
|
|
379
|
+
|
|
350
380
|
/**
|
|
351
381
|
* Drain queued external-MIDI events, already lowered to MIDI 1.0 byte
|
|
352
382
|
* messages ready to write to a Web MIDI output port. Call once per audio
|
|
@@ -358,6 +388,31 @@ export class RealtimeEngine {
|
|
|
358
388
|
return this.native.drainExternalMidi(maxRecords);
|
|
359
389
|
}
|
|
360
390
|
|
|
391
|
+
/** Scalar, allocation-free external-MIDI drain for AudioWorklet SAB output. */
|
|
392
|
+
popExternalMidiToScratch(): boolean {
|
|
393
|
+
return this.native.popExternalMidiToScratch();
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
externalMidiScratchDestinationId(): number {
|
|
397
|
+
return this.native.externalMidiScratchDestinationId();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
externalMidiScratchRenderFrame(): number {
|
|
401
|
+
return this.native.externalMidiScratchRenderFrame();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
externalMidiScratchByteWord(): number {
|
|
405
|
+
return this.native.externalMidiScratchByteWord();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
externalMidiScratchByteCount(): number {
|
|
409
|
+
return this.native.externalMidiScratchByteCount();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
consumeExternalMidiScratch(): void {
|
|
413
|
+
this.native.consumeExternalMidiScratch();
|
|
414
|
+
}
|
|
415
|
+
|
|
361
416
|
pushMidiInputNoteOn(
|
|
362
417
|
group: number,
|
|
363
418
|
channel: number,
|
|
@@ -427,6 +482,11 @@ export class RealtimeEngine {
|
|
|
427
482
|
this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
|
|
428
483
|
}
|
|
429
484
|
|
|
485
|
+
/** Queue one immediate MIDI 1.0 channel-voice UMP word for a destination. */
|
|
486
|
+
pushMidiUmp(destinationId: number, word0: number, renderFrame = -1): void {
|
|
487
|
+
this.native.pushMidiUmp(destinationId, word0, renderFrame);
|
|
488
|
+
}
|
|
489
|
+
|
|
430
490
|
/**
|
|
431
491
|
* Queue an immediate (live) MIDI SysEx frame to a MIDI destination. `data` is
|
|
432
492
|
* the full message including the leading 0xF0 and trailing 0xF7 (1..512
|
|
@@ -480,6 +540,11 @@ export class RealtimeEngine {
|
|
|
480
540
|
this.native.settleParameters();
|
|
481
541
|
}
|
|
482
542
|
|
|
543
|
+
/** Drains queued commands on an offline/control-only engine immediately. */
|
|
544
|
+
flushControlCommands(): void {
|
|
545
|
+
this.native.flushControlCommands();
|
|
546
|
+
}
|
|
547
|
+
|
|
483
548
|
seekPpq(ppq: number, renderFrame = -1): void {
|
|
484
549
|
this.native.seekPpq(ppq, renderFrame);
|
|
485
550
|
}
|
|
@@ -777,7 +842,7 @@ export class RealtimeEngine {
|
|
|
777
842
|
}
|
|
778
843
|
|
|
779
844
|
/** Sets a track lane strip's pan law in realtime. */
|
|
780
|
-
setTrackStripPanLaw(trackId: number, panLaw:
|
|
845
|
+
setTrackStripPanLaw(trackId: number, panLaw: PanLawInput): void {
|
|
781
846
|
this.native.setTrackStripPanLaw(trackId, panLawCode(panLaw));
|
|
782
847
|
}
|
|
783
848
|
|
|
@@ -824,6 +889,27 @@ export class RealtimeEngine {
|
|
|
824
889
|
return this.native.popClipPageRequest();
|
|
825
890
|
}
|
|
826
891
|
|
|
892
|
+
/**
|
|
893
|
+
* Moves one native request into the binding's persistent scalar scratch.
|
|
894
|
+
* This avoids creating an embind JS object in AudioWorklet process().
|
|
895
|
+
*/
|
|
896
|
+
popClipPageRequestToScratch(): boolean {
|
|
897
|
+
return this.native.popClipPageRequestToScratch();
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
clipPageRequestScratchClipId(): number {
|
|
901
|
+
return this.native.clipPageRequestScratchClipId();
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
clipPageRequestScratchSample(): number {
|
|
905
|
+
return this.native.clipPageRequestScratchSample();
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/** Cumulative page misses dropped because the native bounded request queue was full. */
|
|
909
|
+
clipPageRequestOverflowCount(): number {
|
|
910
|
+
return this.native.clipPageRequestOverflowCount();
|
|
911
|
+
}
|
|
912
|
+
|
|
827
913
|
setCaptureBuffer(numChannels: number, capacityFrames: number): void {
|
|
828
914
|
this.native.setCaptureBuffer(numChannels, capacityFrames);
|
|
829
915
|
}
|
|
@@ -836,7 +922,7 @@ export class RealtimeEngine {
|
|
|
836
922
|
this.native.setCapturePunch(startSample, endSample, enabled);
|
|
837
923
|
}
|
|
838
924
|
|
|
839
|
-
setCaptureSource(source:
|
|
925
|
+
setCaptureSource(source: EngineCaptureSource): void {
|
|
840
926
|
this.native.setCaptureSource(source);
|
|
841
927
|
}
|
|
842
928
|
|
|
@@ -861,6 +947,10 @@ export class RealtimeEngine {
|
|
|
861
947
|
return this.native.capturedAudio();
|
|
862
948
|
}
|
|
863
949
|
|
|
950
|
+
/**
|
|
951
|
+
* Renders in place, adding engine output to `channels`. Zero each plane first
|
|
952
|
+
* when it contains no upstream input.
|
|
953
|
+
*/
|
|
864
954
|
process(channels: Float32Array[]): Float32Array[] {
|
|
865
955
|
return this.native.process(channels);
|
|
866
956
|
}
|
|
@@ -886,6 +976,7 @@ export class RealtimeEngine {
|
|
|
886
976
|
|
|
887
977
|
/**
|
|
888
978
|
* Runs the engine in place over the prepared per-channel scratch buffers.
|
|
979
|
+
* Zero each active span first when it contains no upstream input.
|
|
889
980
|
* Allocation-free: safe to call on the AudioWorklet render thread after
|
|
890
981
|
* `prepareChannels`.
|
|
891
982
|
*/
|
|
@@ -913,6 +1004,51 @@ export class RealtimeEngine {
|
|
|
913
1004
|
return this.native.drainTelemetry(maxRecords);
|
|
914
1005
|
}
|
|
915
1006
|
|
|
1007
|
+
popTelemetryToScratch(): boolean {
|
|
1008
|
+
return this.native.popTelemetryToScratch();
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
telemetryScratchType(): number {
|
|
1012
|
+
return this.native.telemetryScratchType();
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
telemetryScratchError(): number {
|
|
1016
|
+
return this.native.telemetryScratchError();
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
telemetryScratchRenderFrame(): number {
|
|
1020
|
+
return Number(this.native.telemetryScratchRenderFrame());
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
telemetryScratchTimelineSample(): number {
|
|
1024
|
+
return Number(this.native.telemetryScratchTimelineSample());
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
telemetryScratchAudibleTimelineSample(): number {
|
|
1028
|
+
return Number(this.native.telemetryScratchAudibleTimelineSample());
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
telemetryScratchGraphLatencySamplesQ8(): number {
|
|
1032
|
+
return this.native.telemetryScratchGraphLatencySamplesQ8();
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
telemetryScratchValue(): number {
|
|
1036
|
+
return this.native.telemetryScratchValue();
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
popMeterTelemetryToScratch(): boolean {
|
|
1040
|
+
return this.native.popMeterTelemetryToScratch();
|
|
1041
|
+
}
|
|
1042
|
+
meterScratchTargetId(): number {
|
|
1043
|
+
return this.native.meterScratchTargetId();
|
|
1044
|
+
}
|
|
1045
|
+
meterScratchRenderFrame(): number {
|
|
1046
|
+
return Number(this.native.meterScratchRenderFrame());
|
|
1047
|
+
}
|
|
1048
|
+
meterScratchValue(field: number): number {
|
|
1049
|
+
return this.native.meterScratchValue(field);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
916
1052
|
drainMeterTelemetry(maxRecords = 1024): EngineMeterTelemetry[] {
|
|
917
1053
|
return this.native.drainMeterTelemetry(maxRecords);
|
|
918
1054
|
}
|
|
@@ -944,6 +1080,31 @@ export class RealtimeEngine {
|
|
|
944
1080
|
return this.native.drainScopeTelemetry(maxRecords);
|
|
945
1081
|
}
|
|
946
1082
|
|
|
1083
|
+
popScopeTelemetryToScratch(): boolean {
|
|
1084
|
+
return this.native.popScopeTelemetryToScratch();
|
|
1085
|
+
}
|
|
1086
|
+
scopeScratchTargetId(): number {
|
|
1087
|
+
return this.native.scopeScratchTargetId();
|
|
1088
|
+
}
|
|
1089
|
+
scopeScratchRenderFrame(): number {
|
|
1090
|
+
return Number(this.native.scopeScratchRenderFrame());
|
|
1091
|
+
}
|
|
1092
|
+
scopeScratchBandCount(): number {
|
|
1093
|
+
return this.native.scopeScratchBandCount();
|
|
1094
|
+
}
|
|
1095
|
+
scopeScratchBand(index: number): number {
|
|
1096
|
+
return this.native.scopeScratchBand(index);
|
|
1097
|
+
}
|
|
1098
|
+
scopeScratchPointCount(): number {
|
|
1099
|
+
return this.native.scopeScratchPointCount();
|
|
1100
|
+
}
|
|
1101
|
+
scopeScratchPointLeft(index: number): number {
|
|
1102
|
+
return this.native.scopeScratchPointLeft(index);
|
|
1103
|
+
}
|
|
1104
|
+
scopeScratchPointRight(index: number): number {
|
|
1105
|
+
return this.native.scopeScratchPointRight(index);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
947
1108
|
destroy(): void {
|
|
948
1109
|
this.native.delete();
|
|
949
1110
|
}
|