@libraz/libsonare 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/_effects_common.d.ts +2 -1
- package/dist/_effects_common.d.ts.map +1 -1
- package/dist/analysis.js +1 -0
- package/dist/analysis.js.map +1 -1
- package/dist/effects_mastering.d.ts +2 -2
- package/dist/effects_mastering.d.ts.map +1 -1
- package/dist/effects_note_ops.d.ts +55 -30
- package/dist/effects_note_ops.d.ts.map +1 -1
- package/dist/effects_timepitch.d.ts +17 -12
- package/dist/effects_timepitch.d.ts.map +1 -1
- package/dist/feature_decompose.d.ts +1 -1
- package/dist/feature_decompose.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +216 -60
- package/dist/index.js.map +1 -1
- package/dist/mastering_core.d.ts +27 -1
- package/dist/mastering_core.d.ts.map +1 -1
- package/dist/mixer.d.ts.map +1 -1
- package/dist/project_types.d.ts +7 -5
- package/dist/project_types.d.ts.map +1 -1
- package/dist/public_types_mastering.d.ts +19 -1
- package/dist/public_types_mastering.d.ts.map +1 -1
- package/dist/public_types_playback.d.ts +1 -0
- package/dist/public_types_playback.d.ts.map +1 -1
- package/dist/public_types_spectral.d.ts +5 -5
- package/dist/public_types_spectral.d.ts.map +1 -1
- package/dist/realtime_engine.d.ts +49 -6
- package/dist/realtime_engine.d.ts.map +1 -1
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.d.ts +36 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/streaming_processors.d.ts +5 -0
- package/dist/streaming_processors.d.ts.map +1 -1
- package/dist/worker.js.map +1 -1
- package/dist/worklet/engine-mixer-facade.d.ts +40 -4
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -1
- package/dist/worklet/engine-node.d.ts +2 -0
- package/dist/worklet/engine-node.d.ts.map +1 -1
- package/dist/worklet/engine-processor.d.ts +4 -0
- package/dist/worklet/engine-processor.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-sync.d.ts +4 -2
- package/dist/worklet/engine-sync.d.ts.map +1 -1
- package/dist/worklet/engine.d.ts +27 -6
- package/dist/worklet/engine.d.ts.map +1 -1
- package/dist/worklet/guards.d.ts +7 -1
- package/dist/worklet/guards.d.ts.map +1 -1
- package/dist/worklet/messages.d.ts +4 -4
- package/dist/worklet/messages.d.ts.map +1 -1
- package/dist/worklet/mixer-processor.d.ts +2 -2
- package/dist/worklet/mixer-processor.d.ts.map +1 -1
- package/dist/worklet/protocol.d.ts +10 -2
- package/dist/worklet/protocol.d.ts.map +1 -1
- package/dist/worklet.js +585 -188
- package/dist/worklet.js.map +1 -1
- package/package.json +1 -1
- package/src/_effects_common.ts +36 -6
- package/src/effects_mastering.ts +4 -0
- package/src/effects_note_ops.ts +92 -44
- package/src/effects_timepitch.ts +42 -31
- package/src/feature_decompose.ts +2 -2
- package/src/index.ts +6 -0
- package/src/mastering_core.ts +95 -0
- package/src/mixer.ts +39 -19
- package/src/project_types.ts +7 -5
- package/src/public_types_mastering.ts +21 -0
- package/src/public_types_playback.ts +1 -0
- package/src/public_types_spectral.ts +5 -5
- package/src/realtime_engine.ts +71 -15
- package/src/sonare.js.d.ts +36 -0
- package/src/streaming_processors.ts +8 -0
- package/src/worklet/engine-mixer-facade.ts +420 -86
- package/src/worklet/engine-node.ts +22 -4
- package/src/worklet/engine-processor.ts +83 -33
- package/src/worklet/engine-strips.ts +5 -10
- package/src/worklet/engine-sync.ts +6 -1
- package/src/worklet/engine.ts +49 -37
- package/src/worklet/guards.ts +55 -0
- package/src/worklet/messages.ts +4 -2
- package/src/worklet/mixer-processor.ts +10 -3
- package/src/worklet/protocol.ts +29 -8
package/src/mastering_core.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ErrorCode, SonareError } from './errors';
|
|
|
2
2
|
import { getSonareModule } from './module_state';
|
|
3
3
|
import type {
|
|
4
4
|
LoudnessMatchResult,
|
|
5
|
+
LoudnessMatchStereoResult,
|
|
5
6
|
MasteringAssistantParams,
|
|
6
7
|
MasteringInsertParamChoice,
|
|
7
8
|
MasteringInsertSlot,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
PairProcessor,
|
|
14
15
|
SoloProcessor,
|
|
15
16
|
StereoAnalysis,
|
|
17
|
+
StereoPairProcessor,
|
|
16
18
|
StreamingPlatform,
|
|
17
19
|
} from './public_types';
|
|
18
20
|
|
|
@@ -52,6 +54,17 @@ export interface MasteringPairProcessRequest {
|
|
|
52
54
|
params?: MasteringProcessorParams;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/** Canonical request form for a stereo two-input match processor. */
|
|
58
|
+
export interface MasteringPairProcessStereoRequest {
|
|
59
|
+
processorName: StereoPairProcessor;
|
|
60
|
+
sourceLeft: Float32Array;
|
|
61
|
+
sourceRight: Float32Array;
|
|
62
|
+
referenceLeft: Float32Array;
|
|
63
|
+
referenceRight: Float32Array;
|
|
64
|
+
sampleRate?: number;
|
|
65
|
+
params?: MasteringProcessorParams;
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
/** Canonical request form for {@link masteringAbMatchLoudness}. */
|
|
56
69
|
export interface MasteringAbMatchLoudnessRequest {
|
|
57
70
|
/** The take to gain-match. */
|
|
@@ -61,6 +74,15 @@ export interface MasteringAbMatchLoudnessRequest {
|
|
|
61
74
|
sampleRate?: number;
|
|
62
75
|
}
|
|
63
76
|
|
|
77
|
+
/** Canonical request form for stereo AB loudness matching. */
|
|
78
|
+
export interface MasteringAbMatchLoudnessStereoRequest {
|
|
79
|
+
sourceLeft: Float32Array;
|
|
80
|
+
sourceRight: Float32Array;
|
|
81
|
+
referenceLeft: Float32Array;
|
|
82
|
+
referenceRight: Float32Array;
|
|
83
|
+
sampleRate?: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
64
86
|
/** Canonical request form for a two-input match analysis. */
|
|
65
87
|
export interface MasteringPairAnalyzeRequest {
|
|
66
88
|
analysisName: PairAnalysis;
|
|
@@ -548,6 +570,60 @@ export function masteringPairProcess(
|
|
|
548
570
|
);
|
|
549
571
|
}
|
|
550
572
|
|
|
573
|
+
/**
|
|
574
|
+
* Apply the stereo `match.abCrossfade` processor. Source and reference stereo
|
|
575
|
+
* pairs may have independent lengths, but each pair must have equal channels.
|
|
576
|
+
*/
|
|
577
|
+
export function masteringPairProcessStereo(
|
|
578
|
+
request: MasteringPairProcessStereoRequest,
|
|
579
|
+
): MasteringStereoResult;
|
|
580
|
+
export function masteringPairProcessStereo(
|
|
581
|
+
processorName: StereoPairProcessor,
|
|
582
|
+
sourceLeft: Float32Array,
|
|
583
|
+
sourceRight: Float32Array,
|
|
584
|
+
referenceLeft: Float32Array,
|
|
585
|
+
referenceRight: Float32Array,
|
|
586
|
+
sampleRate?: number,
|
|
587
|
+
params?: MasteringProcessorParams,
|
|
588
|
+
): MasteringStereoResult;
|
|
589
|
+
export function masteringPairProcessStereo(
|
|
590
|
+
processorName: StereoPairProcessor | MasteringPairProcessStereoRequest,
|
|
591
|
+
sourceLeft?: Float32Array,
|
|
592
|
+
sourceRight?: Float32Array,
|
|
593
|
+
referenceLeft?: Float32Array,
|
|
594
|
+
referenceRight?: Float32Array,
|
|
595
|
+
sampleRate = 22050,
|
|
596
|
+
params: MasteringProcessorParams = {},
|
|
597
|
+
): MasteringStereoResult {
|
|
598
|
+
const request =
|
|
599
|
+
typeof processorName === 'string'
|
|
600
|
+
? {
|
|
601
|
+
processorName,
|
|
602
|
+
sourceLeft: sourceLeft as Float32Array,
|
|
603
|
+
sourceRight: sourceRight as Float32Array,
|
|
604
|
+
referenceLeft: referenceLeft as Float32Array,
|
|
605
|
+
referenceRight: referenceRight as Float32Array,
|
|
606
|
+
sampleRate,
|
|
607
|
+
params,
|
|
608
|
+
}
|
|
609
|
+
: processorName;
|
|
610
|
+
if (request.sourceLeft.length !== request.sourceRight.length) {
|
|
611
|
+
throw new Error('Source left and right channel lengths must match.');
|
|
612
|
+
}
|
|
613
|
+
if (request.referenceLeft.length !== request.referenceRight.length) {
|
|
614
|
+
throw new Error('Reference left and right channel lengths must match.');
|
|
615
|
+
}
|
|
616
|
+
return requireModule().masteringPairProcessStereo(
|
|
617
|
+
request.processorName,
|
|
618
|
+
request.sourceLeft,
|
|
619
|
+
request.sourceRight,
|
|
620
|
+
request.referenceLeft,
|
|
621
|
+
request.referenceRight,
|
|
622
|
+
request.sampleRate ?? 22050,
|
|
623
|
+
request.params ?? {},
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
|
|
551
627
|
/**
|
|
552
628
|
* Analyze a `source` against a `reference` with a two-input analysis. The two
|
|
553
629
|
* buffers may have independent lengths.
|
|
@@ -616,6 +692,25 @@ export function masteringAbMatchLoudness(
|
|
|
616
692
|
);
|
|
617
693
|
}
|
|
618
694
|
|
|
695
|
+
/** Gain-match a stereo source to a stereo reference with one shared gain. */
|
|
696
|
+
export function masteringAbMatchLoudnessStereo(
|
|
697
|
+
request: MasteringAbMatchLoudnessStereoRequest,
|
|
698
|
+
): LoudnessMatchStereoResult {
|
|
699
|
+
if (request.sourceLeft.length !== request.sourceRight.length) {
|
|
700
|
+
throw new Error('Source left and right channel lengths must match.');
|
|
701
|
+
}
|
|
702
|
+
if (request.referenceLeft.length !== request.referenceRight.length) {
|
|
703
|
+
throw new Error('Reference left and right channel lengths must match.');
|
|
704
|
+
}
|
|
705
|
+
return requireModule().masteringAbMatchLoudnessStereo(
|
|
706
|
+
request.sourceLeft,
|
|
707
|
+
request.sourceRight,
|
|
708
|
+
request.referenceLeft,
|
|
709
|
+
request.referenceRight,
|
|
710
|
+
request.sampleRate ?? 22050,
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
|
|
619
714
|
export function masteringStereoAnalyze(request: MasteringStereoAnalyzeRequest): string;
|
|
620
715
|
export function masteringStereoAnalyze(
|
|
621
716
|
analysisName: StereoAnalysis,
|
package/src/mixer.ts
CHANGED
|
@@ -188,50 +188,70 @@ export class Mixer {
|
|
|
188
188
|
* after {@link delete}.
|
|
189
189
|
*/
|
|
190
190
|
createRealtimeBuffer(): MixerRealtimeBuffer {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
let rightInputs: Float32Array[] = [];
|
|
191
|
+
const leftInputs: Float32Array[] = [];
|
|
192
|
+
const rightInputs: Float32Array[] = [];
|
|
194
193
|
let outLeft = this.mixer.outputLeftView();
|
|
195
194
|
let outRight = this.mixer.outputRightView();
|
|
195
|
+
let acquiredStripCount = -1;
|
|
196
|
+
|
|
197
|
+
// Every view shares one heap buffer, so a growth detaches the output views too.
|
|
198
|
+
const viewsDetached = (): boolean => outLeft.byteLength === 0 || outRight.byteLength === 0;
|
|
199
|
+
|
|
196
200
|
const acquire = (): void => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
const stripCount = this.stripCount();
|
|
202
|
+
const detached = viewsDetached();
|
|
203
|
+
if (detached) {
|
|
204
|
+
// A heap growth detached every view: reacquire all planes.
|
|
205
|
+
leftInputs.length = 0;
|
|
206
|
+
rightInputs.length = 0;
|
|
207
|
+
} else {
|
|
208
|
+
// Topology growth keeps existing planes in place: append views for new strips only.
|
|
209
|
+
leftInputs.length = Math.min(leftInputs.length, stripCount);
|
|
210
|
+
rightInputs.length = Math.min(rightInputs.length, stripCount);
|
|
211
|
+
}
|
|
212
|
+
for (let index = leftInputs.length; index < stripCount; index++) {
|
|
200
213
|
leftInputs.push(this.mixer.inputLeftView(index));
|
|
214
|
+
}
|
|
215
|
+
for (let index = rightInputs.length; index < stripCount; index++) {
|
|
201
216
|
rightInputs.push(this.mixer.inputRightView(index));
|
|
202
217
|
}
|
|
203
|
-
|
|
204
|
-
|
|
218
|
+
if (detached) {
|
|
219
|
+
outLeft = this.mixer.outputLeftView();
|
|
220
|
+
outRight = this.mixer.outputRightView();
|
|
221
|
+
}
|
|
222
|
+
acquiredStripCount = stripCount;
|
|
205
223
|
};
|
|
206
224
|
acquire();
|
|
225
|
+
|
|
207
226
|
// The cached heap views can detach if WASM linear memory grows (the embind
|
|
208
|
-
// module is built ALLOW_MEMORY_GROWTH).
|
|
209
|
-
//
|
|
210
|
-
const
|
|
211
|
-
if (
|
|
227
|
+
// module is built ALLOW_MEMORY_GROWTH). Also refresh the view list when a
|
|
228
|
+
// caller adds a strip and recompiles the graph after this buffer was made.
|
|
229
|
+
const acquireIfNeeded = (): void => {
|
|
230
|
+
if (acquiredStripCount !== this.stripCount() || viewsDetached()) {
|
|
212
231
|
acquire();
|
|
213
232
|
}
|
|
214
233
|
};
|
|
215
234
|
return {
|
|
216
235
|
get leftInputs(): Float32Array[] {
|
|
217
|
-
|
|
236
|
+
acquireIfNeeded();
|
|
218
237
|
return leftInputs;
|
|
219
238
|
},
|
|
220
239
|
get rightInputs(): Float32Array[] {
|
|
221
|
-
|
|
240
|
+
acquireIfNeeded();
|
|
222
241
|
return rightInputs;
|
|
223
242
|
},
|
|
224
243
|
get outLeft(): Float32Array {
|
|
225
|
-
|
|
244
|
+
acquireIfNeeded();
|
|
226
245
|
return outLeft;
|
|
227
246
|
},
|
|
228
247
|
get outRight(): Float32Array {
|
|
229
|
-
|
|
248
|
+
acquireIfNeeded();
|
|
230
249
|
return outRight;
|
|
231
250
|
},
|
|
232
|
-
process: (numSamples
|
|
233
|
-
|
|
234
|
-
|
|
251
|
+
process: (numSamples?: number) => {
|
|
252
|
+
acquireIfNeeded();
|
|
253
|
+
// Resolve the default only after reacquiring: a detached view reports length 0.
|
|
254
|
+
this.mixer.processPreparedStereo(numSamples ?? outLeft.length);
|
|
235
255
|
},
|
|
236
256
|
};
|
|
237
257
|
}
|
package/src/project_types.ts
CHANGED
|
@@ -532,7 +532,7 @@ export interface MidiCcLearnOptions {
|
|
|
532
532
|
minValue?: number;
|
|
533
533
|
/** Upper end of the mapped parameter range. Default `1`. */
|
|
534
534
|
maxValue?: number;
|
|
535
|
-
/**
|
|
535
|
+
/** Activity threshold in 7-bit CC units (integer 0-127) a controller must move to be learned. Default `0`. */
|
|
536
536
|
minMovement?: number;
|
|
537
537
|
}
|
|
538
538
|
|
|
@@ -630,12 +630,14 @@ export interface TranscribeOptions {
|
|
|
630
630
|
*/
|
|
631
631
|
referenceHz?: number;
|
|
632
632
|
/**
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
633
|
+
* F0 tracker range in Hz. Both paths use these bounds; the polyphonic path
|
|
634
|
+
* applies them to the salience estimator's F0 axis while its cent-spectrum
|
|
635
|
+
* bounds remain independent. When omitted, the monophonic defaults are `65`
|
|
636
|
+
* and `2093`, while the polyphonic defaults are `55` and `1760`. Explicit
|
|
637
|
+
* values must be finite and positive, and `fmax` must exceed `fmin`.
|
|
636
638
|
*/
|
|
637
639
|
fmin?: number;
|
|
638
|
-
/** Upper end of the
|
|
640
|
+
/** Upper end of the F0 tracker range in Hz; omitted defaults to `2093` mono or `1760` poly. */
|
|
639
641
|
fmax?: number;
|
|
640
642
|
/** Shortest span kept as a note, in milliseconds. Default `30`; must be positive. */
|
|
641
643
|
minNoteMs?: number;
|
|
@@ -80,6 +80,7 @@ export const SOLO_PROCESSORS = [
|
|
|
80
80
|
'effects.acoustic.roomMorph',
|
|
81
81
|
'effects.delay.stereo',
|
|
82
82
|
'effects.filter.vowel',
|
|
83
|
+
'effects.gsEfx',
|
|
83
84
|
'effects.modulation.autoWah',
|
|
84
85
|
'effects.modulation.chorus',
|
|
85
86
|
'effects.modulation.ensemble',
|
|
@@ -162,6 +163,9 @@ export type PairProcessor =
|
|
|
162
163
|
| 'match.abSwitch'
|
|
163
164
|
| 'match.abCrossfade';
|
|
164
165
|
|
|
166
|
+
/** Pair processors with a stereo entry point. */
|
|
167
|
+
export type StereoPairProcessor = 'match.abCrossfade';
|
|
168
|
+
|
|
165
169
|
export type PairAnalysis =
|
|
166
170
|
| 'match.referenceLoudness'
|
|
167
171
|
| 'match.tonalBalance'
|
|
@@ -213,6 +217,23 @@ export interface LoudnessMatchResult {
|
|
|
213
217
|
matchedTruePeakDbtp: number;
|
|
214
218
|
}
|
|
215
219
|
|
|
220
|
+
/** Stereo counterpart of {@link LoudnessMatchResult}. */
|
|
221
|
+
export interface LoudnessMatchStereoResult {
|
|
222
|
+
/** The left source channel, gain-matched to the reference loudness. */
|
|
223
|
+
left: Float32Array;
|
|
224
|
+
/** The right source channel, gain-matched with the same gain as `left`. */
|
|
225
|
+
right: Float32Array;
|
|
226
|
+
sampleRate: number;
|
|
227
|
+
/** The reference program's BS.1770 integrated loudness. */
|
|
228
|
+
referenceLufs: number;
|
|
229
|
+
/** The stereo source program's loudness before the gain. */
|
|
230
|
+
sourceLufs: number;
|
|
231
|
+
/** One gain applied to both source channels, in dB. */
|
|
232
|
+
appliedGainDb: number;
|
|
233
|
+
/** Maximum true peak across the matched left and right channels, in dBTP. */
|
|
234
|
+
matchedTruePeakDbtp: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
216
237
|
/**
|
|
217
238
|
* Mastering loudness/true-peak processing result
|
|
218
239
|
*/
|
|
@@ -158,6 +158,7 @@ export interface PlaybackDiagnostics {
|
|
|
158
158
|
loudness_gain_clamped: boolean;
|
|
159
159
|
/** True when an `hrtf` was supplied to a speakers target, which ignores it. */
|
|
160
160
|
hrtf_ignored: boolean;
|
|
161
|
+
/** Deepest last-block gain reduction across the main and LFE limiters, in dB (<= 0). */
|
|
161
162
|
limiter_gain_reduction_db: number;
|
|
162
163
|
non_finite_discards: number;
|
|
163
164
|
}
|
|
@@ -34,10 +34,10 @@ export interface PitchCorrectOptions extends ValidateOptions {
|
|
|
34
34
|
retuneSpeedMs?: number;
|
|
35
35
|
/** Corrections below this are bypassed to preserve vibrato (cents). Default 20. */
|
|
36
36
|
vibratoThresholdCents?: number;
|
|
37
|
-
/** Per-frame voiced flags (truthy = voiced);
|
|
38
|
-
voiced?: VoicedFlags;
|
|
39
|
-
/** Per-frame voicing probability in `[0, 1]`;
|
|
40
|
-
voicedProb?: Float32Array;
|
|
37
|
+
/** Per-frame voiced flags (truthy = voiced); when supplied, these take precedence over `voicedProb`. Omit or pass `null` to use `voicedProb`; with neither, all frames are treated as voiced. */
|
|
38
|
+
voiced?: VoicedFlags | null;
|
|
39
|
+
/** Per-frame voicing probability in `[0, 1]`; used only when `voiced` is omitted or `null`, and ignored when flags are supplied. */
|
|
40
|
+
voicedProb?: Float32Array | null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** Options for `noteStretch`. All fields are optional. */
|
|
@@ -68,7 +68,7 @@ export interface NoteExtractorOptions {
|
|
|
68
68
|
referenceHz?: number;
|
|
69
69
|
/**
|
|
70
70
|
* Value of `voicedProb` at or above which a frame counts as voiced, in
|
|
71
|
-
* `[0, 1]`. Read only when `voiced` is omitted
|
|
71
|
+
* `[0, 1]`. Read only when `voiced` is omitted or `null`. Default 0.5.
|
|
72
72
|
*
|
|
73
73
|
* pYIN's `voicedProb` is a frame's voiced observation mass and rises with F0
|
|
74
74
|
* for a fixed frame length, so this default silently drops low registers —
|
package/src/realtime_engine.ts
CHANGED
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
WasmEngineAutomationPoint,
|
|
30
30
|
WasmEngineBounceOptions,
|
|
31
31
|
WasmEngineBounceResult,
|
|
32
|
+
WasmEngineBus,
|
|
32
33
|
WasmEngineCaptureStatus,
|
|
33
34
|
WasmEngineClip,
|
|
34
35
|
WasmEngineFreezeOptions,
|
|
@@ -44,6 +45,7 @@ import type {
|
|
|
44
45
|
WasmEngineTelemetry,
|
|
45
46
|
WasmEngineTempoSegment,
|
|
46
47
|
WasmEngineTimeSignatureSegment,
|
|
48
|
+
WasmEngineTrackSend,
|
|
47
49
|
WasmEngineTransportState,
|
|
48
50
|
WasmExternalMidiEvent,
|
|
49
51
|
WasmRealtimeEngine,
|
|
@@ -626,7 +628,10 @@ export class RealtimeEngine {
|
|
|
626
628
|
/**
|
|
627
629
|
* Route a destination's (track lane's) MIDI to the external output queue
|
|
628
630
|
* instead of the internal instrument rack, so the track plays an external
|
|
629
|
-
* device. Clearing it restores internal-synth playback.
|
|
631
|
+
* device. Clearing it restores internal-synth playback. Control-thread only.
|
|
632
|
+
* The change takes effect at the next processed block; switching a
|
|
633
|
+
* destination's route first releases its notes and resets its controllers
|
|
634
|
+
* through the old route, and drops its pending MIDI-FX events. Single writer.
|
|
630
635
|
*/
|
|
631
636
|
setMidiDestinationExternal(destinationId: number, external: boolean): void {
|
|
632
637
|
this.native.setMidiDestinationExternal(destinationId, external);
|
|
@@ -883,8 +888,11 @@ export class RealtimeEngine {
|
|
|
883
888
|
/**
|
|
884
889
|
* Queue an immediate (live) MIDI SysEx frame to a MIDI destination. `data` is
|
|
885
890
|
* the full message including the leading 0xF0 and trailing 0xF7 (1..512
|
|
886
|
-
* bytes). `renderFrame` is the frame to fire at, or -1 for immediate.
|
|
887
|
-
* the
|
|
891
|
+
* bytes). `renderFrame` is the frame to fire at, or -1 for immediate. Throws
|
|
892
|
+
* `InvalidParameter` when the destination instrument cannot prepare
|
|
893
|
+
* the SysEx (retrying cannot help), and `OutOfMemory` when the payload
|
|
894
|
+
* slots or the command queue are full (retry after a processed block).
|
|
895
|
+
* Mirrors the Node/Python/C-ABI `pushMidiSysex`.
|
|
888
896
|
*/
|
|
889
897
|
pushMidiSysex(destinationId: number, data: Uint8Array, renderFrame = -1): void {
|
|
890
898
|
this.native.pushMidiSysex(destinationId, data, renderFrame);
|
|
@@ -911,14 +919,34 @@ export class RealtimeEngine {
|
|
|
911
919
|
return this.native.getTransportState();
|
|
912
920
|
}
|
|
913
921
|
|
|
922
|
+
/** Queues an integrated-loudness reset; short-term and momentary windows are retained. */
|
|
923
|
+
resetMasterLoudnessMeter(renderFrame = -1): void {
|
|
924
|
+
this.native.resetMasterLoudnessMeter(renderFrame);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/** Reads the immutable factory value for a resolved insert parameter id. */
|
|
928
|
+
insertParameterConstructedValue(paramId: number): number {
|
|
929
|
+
return this.native.insertParameterConstructedValue(paramId);
|
|
930
|
+
}
|
|
931
|
+
|
|
914
932
|
play(renderFrame = -1): void {
|
|
915
933
|
this.native.play(renderFrame);
|
|
916
934
|
}
|
|
917
935
|
|
|
936
|
+
/**
|
|
937
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
938
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
939
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
940
|
+
*/
|
|
918
941
|
stop(renderFrame = -1): void {
|
|
919
942
|
this.native.stop(renderFrame);
|
|
920
943
|
}
|
|
921
944
|
|
|
945
|
+
/**
|
|
946
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
947
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
948
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
949
|
+
*/
|
|
922
950
|
seekSample(timelineSample: number, renderFrame = -1): void {
|
|
923
951
|
this.native.seekSample(timelineSample, renderFrame);
|
|
924
952
|
}
|
|
@@ -948,6 +976,11 @@ export class RealtimeEngine {
|
|
|
948
976
|
this.native.applyCommandsDueNowPreservingFuture();
|
|
949
977
|
}
|
|
950
978
|
|
|
979
|
+
/**
|
|
980
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
981
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
982
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
983
|
+
*/
|
|
951
984
|
seekPpq(ppq: number, renderFrame = -1): void {
|
|
952
985
|
this.native.seekPpq(ppq, renderFrame);
|
|
953
986
|
}
|
|
@@ -973,6 +1006,11 @@ export class RealtimeEngine {
|
|
|
973
1006
|
return Number(this.native.sampleAtPpq(ppq));
|
|
974
1007
|
}
|
|
975
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* A loop wrap, seek or stop sends note-offs plus CC64=0, CC121, CC123 and a
|
|
1011
|
+
* centred pitch bend on every channel played since the last reset, so
|
|
1012
|
+
* controller values set before a loop region are not restored at the wrap.
|
|
1013
|
+
*/
|
|
976
1014
|
setLoop(startPpq: number, endPpq: number, enabled = true): void {
|
|
977
1015
|
this.native.setLoop(startPpq, endPpq, enabled);
|
|
978
1016
|
}
|
|
@@ -1079,7 +1117,7 @@ export class RealtimeEngine {
|
|
|
1079
1117
|
* reads (defaults to post-fader when omitted). Shared by track lanes and
|
|
1080
1118
|
* buses, which carry the same send shape.
|
|
1081
1119
|
*/
|
|
1082
|
-
private static normalizeSends(sends: EngineTrackSend[]):
|
|
1120
|
+
private static normalizeSends(sends: EngineTrackSend[]): WasmEngineTrackSend[] {
|
|
1083
1121
|
return sends.map((send) => ({
|
|
1084
1122
|
...send,
|
|
1085
1123
|
// Post-fader (0) is the default for an omitted sendTiming.
|
|
@@ -1093,10 +1131,10 @@ export class RealtimeEngine {
|
|
|
1093
1131
|
if (typeof lane === 'number') {
|
|
1094
1132
|
return { trackId: lane };
|
|
1095
1133
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1134
|
+
return {
|
|
1135
|
+
...lane,
|
|
1136
|
+
sends: lane.sends ? RealtimeEngine.normalizeSends(lane.sends) : undefined,
|
|
1137
|
+
};
|
|
1100
1138
|
}),
|
|
1101
1139
|
);
|
|
1102
1140
|
}
|
|
@@ -1116,10 +1154,11 @@ export class RealtimeEngine {
|
|
|
1116
1154
|
// failing here on a `.map` that array-likes do not implement.
|
|
1117
1155
|
this.native.setTrackBuses(
|
|
1118
1156
|
Array.isArray(buses)
|
|
1119
|
-
? buses.map((bus) =>
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1157
|
+
? buses.map((bus) => ({
|
|
1158
|
+
...bus,
|
|
1159
|
+
sends: bus.sends ? RealtimeEngine.normalizeSends(bus.sends) : undefined,
|
|
1160
|
+
}))
|
|
1161
|
+
: (buses as WasmEngineBus[]),
|
|
1123
1162
|
);
|
|
1124
1163
|
}
|
|
1125
1164
|
|
|
@@ -1357,6 +1396,16 @@ export class RealtimeEngine {
|
|
|
1357
1396
|
* stages of the offline mastering chain (`repair.*`, `loudness`, and the
|
|
1358
1397
|
* match stages) have no insert form and no automation id: they buffer the
|
|
1359
1398
|
* entire signal by construction and do not run on the realtime path.
|
|
1399
|
+
*
|
|
1400
|
+
* The returned id uses the track's current positional lane selector. When
|
|
1401
|
+
* `setTrackLanes` successfully changes lane order or membership, the engine
|
|
1402
|
+
* remaps already queued and published track automation by track id, but it
|
|
1403
|
+
* cannot update a numeric id retained by the caller. Re-resolve every track
|
|
1404
|
+
* insert id after such a topology change before passing it to
|
|
1405
|
+
* `setAutomationLane`, `setParameter`, or `setParameterSmoothed`. Use
|
|
1406
|
+
* `setTrackStripInsertParamByName` when the operation needs a stable track
|
|
1407
|
+
* identity. Master and bus insert ids are separate and are not invalidated by
|
|
1408
|
+
* track-lane changes.
|
|
1360
1409
|
*/
|
|
1361
1410
|
resolveTrackInsertAutomationId(trackId: number, insertIndex: number, paramName: string): number {
|
|
1362
1411
|
return this.native.resolveTrackInsertAutomationId(trackId, insertIndex, paramName);
|
|
@@ -1757,6 +1806,12 @@ export class RealtimeEngine {
|
|
|
1757
1806
|
meterScratchRenderFrame(): number {
|
|
1758
1807
|
return Number(this.native.meterScratchRenderFrame());
|
|
1759
1808
|
}
|
|
1809
|
+
meterScratchInputPeakDbL(): number {
|
|
1810
|
+
return this.native.meterScratchInputPeakDbL();
|
|
1811
|
+
}
|
|
1812
|
+
meterScratchInputPeakDbR(): number {
|
|
1813
|
+
return this.native.meterScratchInputPeakDbR();
|
|
1814
|
+
}
|
|
1760
1815
|
meterScratchValue(field: number): number {
|
|
1761
1816
|
return this.native.meterScratchValue(field);
|
|
1762
1817
|
}
|
|
@@ -1768,9 +1823,10 @@ export class RealtimeEngine {
|
|
|
1768
1823
|
/**
|
|
1769
1824
|
* Drains pending meter telemetry as per-plane (wide) records for a surround
|
|
1770
1825
|
* target. Use this for a surround mix target; {@link drainMeterTelemetry}
|
|
1771
|
-
* stays the stereo fast path. The two share one queue
|
|
1772
|
-
* target
|
|
1773
|
-
* this wide drain is for an
|
|
1826
|
+
* stays the stereo fast path. The two share one queue and each consumes every
|
|
1827
|
+
* target's records, so an engine uses only one of them. The live AudioWorklet
|
|
1828
|
+
* path owns the queue via the stereo drain, so this wide drain is for an
|
|
1829
|
+
* offline (non-worklet) engine instance; per-plane
|
|
1774
1830
|
* surround meters are not delivered over the live worklet meter ring.
|
|
1775
1831
|
*/
|
|
1776
1832
|
drainMeterTelemetryWide(maxRecords = 1024): EngineMeterTelemetryWide[] {
|
package/src/sonare.js.d.ts
CHANGED
|
@@ -829,6 +829,11 @@ export interface WasmLoudnessMatchResult {
|
|
|
829
829
|
matchedTruePeakDbtp: number;
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
+
export interface WasmLoudnessMatchStereoResult extends Omit<WasmLoudnessMatchResult, 'samples'> {
|
|
833
|
+
left: Float32Array;
|
|
834
|
+
right: Float32Array;
|
|
835
|
+
}
|
|
836
|
+
|
|
832
837
|
export interface WasmStageGainReduction {
|
|
833
838
|
stage: string;
|
|
834
839
|
gainReductionDb: number;
|
|
@@ -965,6 +970,8 @@ export interface WasmEngineTrackSend {
|
|
|
965
970
|
busId: number;
|
|
966
971
|
levelDb?: number;
|
|
967
972
|
enabled?: boolean;
|
|
973
|
+
/** Native send tap: 0 post-fader (default), 1 pre-fader. */
|
|
974
|
+
sendTiming?: number;
|
|
968
975
|
}
|
|
969
976
|
|
|
970
977
|
export interface WasmEngineTrackLane {
|
|
@@ -1165,6 +1172,10 @@ export interface WasmEngineMeterTelemetry {
|
|
|
1165
1172
|
shortTermLufs: number;
|
|
1166
1173
|
integratedLufs: number;
|
|
1167
1174
|
gainReductionDb: number;
|
|
1175
|
+
/** Maximum pre-trim input peak for the left channel, in dBFS. */
|
|
1176
|
+
inputPeakDbL: number;
|
|
1177
|
+
/** Maximum pre-trim input peak for the right channel, in dBFS. */
|
|
1178
|
+
inputPeakDbR: number;
|
|
1168
1179
|
droppedRecords: number;
|
|
1169
1180
|
}
|
|
1170
1181
|
|
|
@@ -1199,6 +1210,8 @@ export interface WasmEngineMeterTelemetryWide {
|
|
|
1199
1210
|
shortTermLufs: number;
|
|
1200
1211
|
integratedLufs: number;
|
|
1201
1212
|
gainReductionDb: number;
|
|
1213
|
+
/** Pre-trim input peak for each valid plane, in dBFS. */
|
|
1214
|
+
inputPeakDb: number[];
|
|
1202
1215
|
droppedRecords: number;
|
|
1203
1216
|
}
|
|
1204
1217
|
|
|
@@ -1363,6 +1376,8 @@ export interface WasmRealtimeEngine {
|
|
|
1363
1376
|
getTransportState: () => WasmEngineTransportState;
|
|
1364
1377
|
play: (renderFrame?: number) => void;
|
|
1365
1378
|
stop: (renderFrame?: number) => void;
|
|
1379
|
+
resetMasterLoudnessMeter: (renderFrame?: number) => void;
|
|
1380
|
+
insertParameterConstructedValue: (paramId: number) => number;
|
|
1366
1381
|
seekSample: (timelineSample: number, renderFrame?: number) => void;
|
|
1367
1382
|
settleParameters: () => void;
|
|
1368
1383
|
settleInsertParameters: () => void;
|
|
@@ -1707,6 +1722,8 @@ export interface WasmRealtimeEngine {
|
|
|
1707
1722
|
meterScratchTargetId: () => number;
|
|
1708
1723
|
meterScratchRenderFrame: () => number;
|
|
1709
1724
|
meterScratchValue: (field: number) => number;
|
|
1725
|
+
meterScratchInputPeakDbL: () => number;
|
|
1726
|
+
meterScratchInputPeakDbR: () => number;
|
|
1710
1727
|
drainMeterTelemetry: (maxRecords: number) => WasmEngineMeterTelemetry[];
|
|
1711
1728
|
drainMeterTelemetryWide: (maxRecords: number) => WasmEngineMeterTelemetryWide[];
|
|
1712
1729
|
configureScopeTelemetry: (intervalFrames: number, bandCount: number) => number;
|
|
@@ -2329,12 +2346,14 @@ export interface SonareModule {
|
|
|
2329
2346
|
options: {
|
|
2330
2347
|
fadeMs?: number;
|
|
2331
2348
|
f0Hz?: Float32Array;
|
|
2349
|
+
voiced?: Float32Array;
|
|
2332
2350
|
frameRate?: number;
|
|
2333
2351
|
vibratoCutoffHz?: number;
|
|
2334
2352
|
},
|
|
2335
2353
|
) => Float32Array;
|
|
2336
2354
|
decomposeNotePitch: (
|
|
2337
2355
|
f0Hz: Float32Array,
|
|
2356
|
+
voiced: Float32Array | undefined,
|
|
2338
2357
|
frameRate: number,
|
|
2339
2358
|
medianHz: number,
|
|
2340
2359
|
vibratoCutoffHz: number,
|
|
@@ -2493,11 +2512,27 @@ export interface SonareModule {
|
|
|
2493
2512
|
sampleRate: number,
|
|
2494
2513
|
params: Record<string, number | boolean>,
|
|
2495
2514
|
) => string;
|
|
2515
|
+
masteringPairProcessStereo: (
|
|
2516
|
+
processorName: string,
|
|
2517
|
+
sourceLeft: Float32Array,
|
|
2518
|
+
sourceRight: Float32Array,
|
|
2519
|
+
referenceLeft: Float32Array,
|
|
2520
|
+
referenceRight: Float32Array,
|
|
2521
|
+
sampleRate: number,
|
|
2522
|
+
params: Record<string, number | boolean>,
|
|
2523
|
+
) => WasmMasteringStereoResult;
|
|
2496
2524
|
masteringAbMatchLoudness: (
|
|
2497
2525
|
source: Float32Array,
|
|
2498
2526
|
reference: Float32Array,
|
|
2499
2527
|
sampleRate: number,
|
|
2500
2528
|
) => WasmLoudnessMatchResult;
|
|
2529
|
+
masteringAbMatchLoudnessStereo: (
|
|
2530
|
+
sourceLeft: Float32Array,
|
|
2531
|
+
sourceRight: Float32Array,
|
|
2532
|
+
referenceLeft: Float32Array,
|
|
2533
|
+
referenceRight: Float32Array,
|
|
2534
|
+
sampleRate: number,
|
|
2535
|
+
) => WasmLoudnessMatchStereoResult;
|
|
2501
2536
|
masteringStereoAnalyze: (
|
|
2502
2537
|
analysisName: string,
|
|
2503
2538
|
left: Float32Array,
|
|
@@ -3521,6 +3556,7 @@ export interface WasmPolyphonicAnalysis {
|
|
|
3521
3556
|
|
|
3522
3557
|
export interface WasmStreamingMasteringChain {
|
|
3523
3558
|
prepare: (sampleRate: number, maxBlockSize: number, numChannels: number) => void;
|
|
3559
|
+
setParameter: (key: string, value: number) => void;
|
|
3524
3560
|
processMono: (samples: Float32Array) => Float32Array;
|
|
3525
3561
|
processStereo: (
|
|
3526
3562
|
left: Float32Array,
|
|
@@ -171,6 +171,14 @@ export class StreamingMasteringChain {
|
|
|
171
171
|
this.chain.reset();
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Set one realtime-safe full-chain parameter at a serialized block boundary.
|
|
176
|
+
* Structural, disabled-stage and unknown parameters are rejected.
|
|
177
|
+
*/
|
|
178
|
+
setParameter(key: string, value: number): void {
|
|
179
|
+
this.chain.setParameter(key, value);
|
|
180
|
+
}
|
|
181
|
+
|
|
174
182
|
/** Total reported latency in samples across all active processors. */
|
|
175
183
|
latencySamples(): number {
|
|
176
184
|
return this.chain.latencySamples();
|