@libraz/libsonare 1.2.3 → 1.3.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 +38 -1
- package/dist/index.d.ts +1 -2842
- package/dist/index.js +3667 -1984
- package/dist/index.js.map +1 -1
- package/dist/sonare-rt-module.js +1 -1
- package/dist/sonare-rt.js +1 -1
- package/dist/sonare-rt.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worklet.d.ts +4816 -483
- package/dist/worklet.js +747 -440
- package/dist/worklet.js.map +1 -1
- package/package.json +2 -1
- package/src/analysis_helpers.ts +152 -0
- package/src/audio.ts +493 -0
- package/src/codes.ts +56 -0
- package/src/effects_mastering.ts +964 -0
- package/src/feature_core.ts +248 -0
- package/src/feature_music.ts +419 -0
- package/src/feature_pitch.ts +80 -0
- package/src/feature_resample.ts +21 -0
- package/src/feature_spectral.ts +330 -0
- package/src/feature_spectrogram.ts +454 -0
- package/src/features.ts +84 -0
- package/src/index.ts +341 -4963
- package/src/live_audio.ts +47 -0
- package/src/metering.ts +380 -0
- package/src/mixer.ts +523 -0
- package/src/module_state.ts +14 -0
- package/src/opfs_clip_pages.ts +203 -0
- package/src/project.ts +1614 -0
- package/src/public_types.ts +177 -2
- package/src/quick_analysis.ts +508 -0
- package/src/realtime_engine.ts +667 -0
- package/src/realtime_voice_changer.ts +275 -0
- package/src/scale.ts +42 -0
- package/src/sonare.js.d.ts +302 -4
- package/src/stream_analyzer.ts +275 -0
- package/src/stream_types.ts +26 -1
- package/src/streaming_mixing.ts +18 -0
- package/src/streaming_processors.ts +335 -0
- package/src/validation.ts +82 -0
- package/src/web_midi.ts +366 -0
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
import { getSonareModule } from './module_state';
|
|
2
|
+
import type {
|
|
3
|
+
HpssResult,
|
|
4
|
+
MasteringChainConfig,
|
|
5
|
+
MasteringChainResult,
|
|
6
|
+
MasteringOptions,
|
|
7
|
+
MasteringPreset,
|
|
8
|
+
MasteringProcessorParams,
|
|
9
|
+
MasteringResult,
|
|
10
|
+
MasteringStereoChainResult,
|
|
11
|
+
MasteringStereoResult,
|
|
12
|
+
MixOptions,
|
|
13
|
+
MixResult,
|
|
14
|
+
NoteStretchOptions,
|
|
15
|
+
PairAnalysis,
|
|
16
|
+
PairProcessor,
|
|
17
|
+
RealtimeVoiceChangerConfigInput,
|
|
18
|
+
SoloProcessor,
|
|
19
|
+
StereoAnalysis,
|
|
20
|
+
StreamingPlatform,
|
|
21
|
+
} from './public_types';
|
|
22
|
+
import type { ProgressCallback } from './sonare.js';
|
|
23
|
+
import { RealtimeVoiceChanger } from './streaming_mixing';
|
|
24
|
+
import type { ValidateOptions } from './validation';
|
|
25
|
+
import { assertSamples } from './validation';
|
|
26
|
+
|
|
27
|
+
function requireModule() {
|
|
28
|
+
return getSonareModule();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Effects
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Perform Harmonic-Percussive Source Separation (HPSS).
|
|
37
|
+
*
|
|
38
|
+
* @param samples - Audio samples (mono, float32)
|
|
39
|
+
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
40
|
+
* @param kernelHarmonic - Horizontal median filter size for harmonic (default: 31)
|
|
41
|
+
* @param kernelPercussive - Vertical median filter size for percussive (default: 31)
|
|
42
|
+
* @returns Separated harmonic and percussive components
|
|
43
|
+
*/
|
|
44
|
+
export function hpss(
|
|
45
|
+
samples: Float32Array,
|
|
46
|
+
sampleRate = 22050,
|
|
47
|
+
kernelHarmonic = 31,
|
|
48
|
+
kernelPercussive = 31,
|
|
49
|
+
): HpssResult {
|
|
50
|
+
return requireModule().hpss(samples, sampleRate, kernelHarmonic, kernelPercussive);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extract harmonic component from audio.
|
|
55
|
+
*
|
|
56
|
+
* @param samples - Audio samples (mono, float32)
|
|
57
|
+
* @param sampleRate - Sample rate in Hz
|
|
58
|
+
* @returns Harmonic component
|
|
59
|
+
*/
|
|
60
|
+
export function harmonic(
|
|
61
|
+
samples: Float32Array,
|
|
62
|
+
sampleRate: number,
|
|
63
|
+
options: ValidateOptions = {},
|
|
64
|
+
): Float32Array {
|
|
65
|
+
assertSamples('harmonic', samples, options.validate !== false);
|
|
66
|
+
return requireModule().harmonic(samples, sampleRate);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Extract percussive component from audio.
|
|
71
|
+
*
|
|
72
|
+
* @param samples - Audio samples (mono, float32)
|
|
73
|
+
* @param sampleRate - Sample rate in Hz
|
|
74
|
+
* @returns Percussive component
|
|
75
|
+
*/
|
|
76
|
+
export function percussive(
|
|
77
|
+
samples: Float32Array,
|
|
78
|
+
sampleRate: number,
|
|
79
|
+
options: ValidateOptions = {},
|
|
80
|
+
): Float32Array {
|
|
81
|
+
assertSamples('percussive', samples, options.validate !== false);
|
|
82
|
+
return requireModule().percussive(samples, sampleRate);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Time-stretch audio without changing pitch.
|
|
87
|
+
*
|
|
88
|
+
* @param samples - Audio samples (mono, float32)
|
|
89
|
+
* @param sampleRate - Sample rate in Hz
|
|
90
|
+
* @param rate - Time stretch rate (0.5 = double duration, 2.0 = half duration)
|
|
91
|
+
* @returns Time-stretched audio
|
|
92
|
+
*/
|
|
93
|
+
export function timeStretch(
|
|
94
|
+
samples: Float32Array,
|
|
95
|
+
sampleRate: number,
|
|
96
|
+
rate: number,
|
|
97
|
+
options: ValidateOptions = {},
|
|
98
|
+
): Float32Array {
|
|
99
|
+
assertSamples('timeStretch', samples, options.validate !== false);
|
|
100
|
+
return requireModule().timeStretch(samples, sampleRate, rate);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pitch-shift audio without changing duration.
|
|
105
|
+
*
|
|
106
|
+
* @param samples - Audio samples (mono, float32)
|
|
107
|
+
* @param sampleRate - Sample rate in Hz
|
|
108
|
+
* @param semitones - Pitch shift in semitones (+12 = one octave up, -12 = one octave down)
|
|
109
|
+
* @returns Pitch-shifted audio
|
|
110
|
+
*/
|
|
111
|
+
export function pitchShift(
|
|
112
|
+
samples: Float32Array,
|
|
113
|
+
sampleRate: number,
|
|
114
|
+
semitones: number,
|
|
115
|
+
options: ValidateOptions = {},
|
|
116
|
+
): Float32Array {
|
|
117
|
+
assertSamples('pitchShift', samples, options.validate !== false);
|
|
118
|
+
return requireModule().pitchShift(samples, sampleRate, semitones);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pitch-correct audio from a current MIDI note to a target MIDI note.
|
|
123
|
+
*
|
|
124
|
+
* @param samples - Audio samples (mono, float32)
|
|
125
|
+
* @param sampleRate - Sample rate in Hz
|
|
126
|
+
* @param currentMidi - Detected/current MIDI note number
|
|
127
|
+
* @param targetMidi - Desired MIDI note number
|
|
128
|
+
* @returns Pitch-corrected audio
|
|
129
|
+
*/
|
|
130
|
+
export function pitchCorrectToMidi(
|
|
131
|
+
samples: Float32Array,
|
|
132
|
+
sampleRate = 22050,
|
|
133
|
+
currentMidi = 69.0,
|
|
134
|
+
targetMidi = 69.0,
|
|
135
|
+
options: ValidateOptions = {},
|
|
136
|
+
): Float32Array {
|
|
137
|
+
assertSamples('pitchCorrectToMidi', samples, options.validate !== false);
|
|
138
|
+
return requireModule().pitchCorrectToMidi(samples, sampleRate, currentMidi, targetMidi);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Contour-following ("time-varying") pitch correction toward a MIDI target.
|
|
143
|
+
*
|
|
144
|
+
* Unlike {@link pitchCorrectToMidi} (a single constant transpose), this follows
|
|
145
|
+
* the caller-supplied per-frame `f0Hz` contour and retunes every voiced frame
|
|
146
|
+
* toward `targetMidi`, so vibrato/drift in the source is tracked rather than
|
|
147
|
+
* flattened. `voiced` (non-zero = voiced) and `voicedProb` ([0,1]) are optional;
|
|
148
|
+
* omitting them treats every frame as voiced.
|
|
149
|
+
*
|
|
150
|
+
* @param samples - Audio samples (mono, float32)
|
|
151
|
+
* @param f0Hz - Per-frame measured F0 in Hz (one entry per analysis frame)
|
|
152
|
+
* @param targetMidi - Desired MIDI note number
|
|
153
|
+
* @param sampleRate - Sample rate in Hz
|
|
154
|
+
* @param hopLength - F0 hop in samples (frame i covers sample i*hopLength)
|
|
155
|
+
* @param voiced - Optional per-frame voiced flags (non-zero = voiced)
|
|
156
|
+
* @param voicedProb - Optional per-frame voicing probability in [0, 1]
|
|
157
|
+
* @returns Pitch-corrected audio
|
|
158
|
+
*/
|
|
159
|
+
export function pitchCorrectToMidiTimevarying(
|
|
160
|
+
samples: Float32Array,
|
|
161
|
+
f0Hz: Float32Array,
|
|
162
|
+
targetMidi: number,
|
|
163
|
+
sampleRate = 22050,
|
|
164
|
+
hopLength = 512,
|
|
165
|
+
voiced?: Int32Array,
|
|
166
|
+
voicedProb?: Float32Array,
|
|
167
|
+
options: ValidateOptions = {},
|
|
168
|
+
): Float32Array {
|
|
169
|
+
assertSamples('pitchCorrectToMidiTimevarying', samples, options.validate !== false);
|
|
170
|
+
if (voiced && voiced.length !== f0Hz.length) {
|
|
171
|
+
throw new RangeError('pitchCorrectToMidiTimevarying: voiced length must match f0Hz length');
|
|
172
|
+
}
|
|
173
|
+
if (voicedProb && voicedProb.length !== f0Hz.length) {
|
|
174
|
+
throw new RangeError('pitchCorrectToMidiTimevarying: voicedProb length must match f0Hz length');
|
|
175
|
+
}
|
|
176
|
+
// The embind layer reads the companion arrays as Float32Array (voiced uses
|
|
177
|
+
// 0.0/1.0); convert here so a single native conversion path suffices.
|
|
178
|
+
const voicedF32 = voiced ? Float32Array.from(voiced) : undefined;
|
|
179
|
+
return requireModule().pitchCorrectToMidiTimevarying(
|
|
180
|
+
samples,
|
|
181
|
+
sampleRate,
|
|
182
|
+
f0Hz,
|
|
183
|
+
targetMidi,
|
|
184
|
+
hopLength,
|
|
185
|
+
voicedF32,
|
|
186
|
+
voicedProb,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Time-stretch a note region between two sample offsets without changing pitch.
|
|
192
|
+
*
|
|
193
|
+
* @param samples - Audio samples (mono, float32)
|
|
194
|
+
* @param sampleRate - Sample rate in Hz
|
|
195
|
+
* @param onsetSample - Note onset position in samples
|
|
196
|
+
* @param offsetSample - Note offset position in samples
|
|
197
|
+
* @param stretchRatio - Stretch ratio (0.5 = double duration, 2.0 = half duration)
|
|
198
|
+
* @returns Audio with the note region stretched
|
|
199
|
+
*/
|
|
200
|
+
export function noteStretch(
|
|
201
|
+
samples: Float32Array,
|
|
202
|
+
sampleRate = 22050,
|
|
203
|
+
options: NoteStretchOptions & ValidateOptions = {},
|
|
204
|
+
): Float32Array {
|
|
205
|
+
assertSamples('noteStretch', samples, options.validate !== false);
|
|
206
|
+
return requireModule().noteStretch(
|
|
207
|
+
samples,
|
|
208
|
+
sampleRate,
|
|
209
|
+
options.onsetSample ?? 0,
|
|
210
|
+
options.offsetSample ?? 0,
|
|
211
|
+
options.stretchRatio ?? 1.0,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Options for {@link voiceChange}. All fields are optional. */
|
|
216
|
+
export interface VoiceChangeOptions extends ValidateOptions {
|
|
217
|
+
/** Pitch shift in semitones (negative = down). Default 0. */
|
|
218
|
+
pitchSemitones?: number;
|
|
219
|
+
/** Formant scale factor (>1 brightens, <1 darkens). Default 1. */
|
|
220
|
+
formantFactor?: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Apply a voice change by shifting pitch and formants independently.
|
|
225
|
+
*
|
|
226
|
+
* @param samples - Audio samples (mono, float32)
|
|
227
|
+
* @param sampleRate - Sample rate in Hz
|
|
228
|
+
* @param options - Pitch/formant settings ({@link VoiceChangeOptions})
|
|
229
|
+
* @returns Voice-changed audio
|
|
230
|
+
*/
|
|
231
|
+
export function voiceChange(
|
|
232
|
+
samples: Float32Array,
|
|
233
|
+
sampleRate = 22050,
|
|
234
|
+
options: VoiceChangeOptions = {},
|
|
235
|
+
): Float32Array {
|
|
236
|
+
assertSamples('voiceChange', samples, options.validate !== false);
|
|
237
|
+
return requireModule().voiceChange(
|
|
238
|
+
samples,
|
|
239
|
+
sampleRate,
|
|
240
|
+
options.pitchSemitones ?? 0.0,
|
|
241
|
+
options.formantFactor ?? 1.0,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Options for the offline {@link voiceChangeRealtime} convenience wrapper. */
|
|
246
|
+
export interface VoiceChangeRealtimeOptions extends ValidateOptions {
|
|
247
|
+
sampleRate?: number;
|
|
248
|
+
/** Voice-changer preset id or full config object. */
|
|
249
|
+
preset?: RealtimeVoiceChangerConfigInput;
|
|
250
|
+
/** Channel count (1 = mono, 2 = interleaved stereo). */
|
|
251
|
+
channels?: 1 | 2;
|
|
252
|
+
/** Block size for the internal render loop (default 512). */
|
|
253
|
+
blockSize?: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function latencyCompensatedVoiceChange(
|
|
257
|
+
changer: RealtimeVoiceChanger,
|
|
258
|
+
samples: Float32Array,
|
|
259
|
+
channels: 1 | 2,
|
|
260
|
+
blockFrames: number,
|
|
261
|
+
): Float32Array {
|
|
262
|
+
const latencyFrames = Math.max(0, changer.latencySamples());
|
|
263
|
+
if (channels === 1) {
|
|
264
|
+
const total = samples.length + latencyFrames;
|
|
265
|
+
const input = new Float32Array(total);
|
|
266
|
+
input.set(samples);
|
|
267
|
+
const processed = new Float32Array(total);
|
|
268
|
+
for (let offset = 0; offset < total; offset += blockFrames) {
|
|
269
|
+
const block = input.subarray(offset, Math.min(offset + blockFrames, total));
|
|
270
|
+
processed.set(changer.processMono(block), offset);
|
|
271
|
+
}
|
|
272
|
+
return processed.slice(latencyFrames, latencyFrames + samples.length);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const frames = samples.length / 2;
|
|
276
|
+
const totalFrames = frames + latencyFrames;
|
|
277
|
+
const input = new Float32Array(totalFrames * 2);
|
|
278
|
+
input.set(samples);
|
|
279
|
+
const processed = new Float32Array(totalFrames * 2);
|
|
280
|
+
const frameStride = blockFrames * 2;
|
|
281
|
+
for (let offset = 0; offset < input.length; offset += frameStride) {
|
|
282
|
+
const block = input.subarray(offset, Math.min(offset + frameStride, input.length));
|
|
283
|
+
processed.set(changer.processInterleaved(block, 2), offset);
|
|
284
|
+
}
|
|
285
|
+
const start = latencyFrames * 2;
|
|
286
|
+
return processed.slice(start, start + samples.length);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Applies the realtime voice-changer chain to a whole buffer in one call.
|
|
291
|
+
*
|
|
292
|
+
* Constructs and prepares a {@link RealtimeVoiceChanger}, runs the block loop
|
|
293
|
+
* for the caller, then disposes it — matching the Python `voice_change_realtime`
|
|
294
|
+
* and Node `voiceChangeRealtime` convenience wrappers. For mono, `samples` is a
|
|
295
|
+
* plain mono buffer; for stereo, `samples` is interleaved (L0,R0,L1,R1,...).
|
|
296
|
+
*
|
|
297
|
+
* @returns The processed buffer (same layout/length as the input).
|
|
298
|
+
*/
|
|
299
|
+
export function voiceChangeRealtime(
|
|
300
|
+
samples: Float32Array,
|
|
301
|
+
options: VoiceChangeRealtimeOptions = {},
|
|
302
|
+
): Float32Array {
|
|
303
|
+
assertSamples('voiceChangeRealtime', samples, options.validate !== false);
|
|
304
|
+
const channels = options.channels ?? 1;
|
|
305
|
+
if (channels !== 1 && channels !== 2) {
|
|
306
|
+
throw new Error('voiceChangeRealtime: channels must be 1 or 2.');
|
|
307
|
+
}
|
|
308
|
+
if (channels === 2 && samples.length % 2 !== 0) {
|
|
309
|
+
throw new Error('voiceChangeRealtime: stereo input length must be a multiple of 2.');
|
|
310
|
+
}
|
|
311
|
+
// 48000 matches the Python voice_change_realtime and Node voiceChangeRealtime
|
|
312
|
+
// convenience wrappers (and the RealtimeVoiceChanger default).
|
|
313
|
+
const sampleRate = options.sampleRate ?? 48000;
|
|
314
|
+
const blockSize = Math.max(1, Math.floor(options.blockSize ?? 512));
|
|
315
|
+
const changer = new RealtimeVoiceChanger(options.preset ?? 'neutral-monitor');
|
|
316
|
+
try {
|
|
317
|
+
changer.prepare(sampleRate, blockSize, channels);
|
|
318
|
+
return latencyCompensatedVoiceChange(changer, samples, channels, blockSize);
|
|
319
|
+
} finally {
|
|
320
|
+
changer.delete();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Normalize audio to target peak level.
|
|
326
|
+
*
|
|
327
|
+
* @param samples - Audio samples (mono, float32)
|
|
328
|
+
* @param sampleRate - Sample rate in Hz
|
|
329
|
+
* @param targetDb - Target peak level in dB (default: 0 dB = full scale)
|
|
330
|
+
* @returns Normalized audio
|
|
331
|
+
*/
|
|
332
|
+
export function normalize(
|
|
333
|
+
samples: Float32Array,
|
|
334
|
+
sampleRate: number,
|
|
335
|
+
targetDb = 0.0,
|
|
336
|
+
options: ValidateOptions = {},
|
|
337
|
+
): Float32Array {
|
|
338
|
+
assertSamples('normalize', samples, options.validate !== false);
|
|
339
|
+
return requireModule().normalize(samples, sampleRate, targetDb);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Apply mastering loudness normalization with a true-peak ceiling.
|
|
344
|
+
*
|
|
345
|
+
* @param samples - Audio samples (mono, float32)
|
|
346
|
+
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
347
|
+
* @param options - Loudness/ceiling settings ({@link MasteringOptions})
|
|
348
|
+
* @returns Processed audio and loudness metadata
|
|
349
|
+
*/
|
|
350
|
+
export function mastering(
|
|
351
|
+
samples: Float32Array,
|
|
352
|
+
sampleRate = 22050,
|
|
353
|
+
options: MasteringOptions = {},
|
|
354
|
+
): MasteringResult {
|
|
355
|
+
return requireModule().mastering(
|
|
356
|
+
samples,
|
|
357
|
+
sampleRate,
|
|
358
|
+
options.targetLufs ?? -14.0,
|
|
359
|
+
options.ceilingDb ?? -1.0,
|
|
360
|
+
options.truePeakOversample ?? 4,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function masteringProcessorNames(): SoloProcessor[] {
|
|
365
|
+
return requireModule().masteringProcessorNames() as SoloProcessor[];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Names of the insert processors the mastering chain can instantiate by name
|
|
370
|
+
* (`mastering::api::insert_factory_names`). Mirrors the C-ABI
|
|
371
|
+
* `sonare_mastering_insert_names` (which joins this list) as a `string[]`.
|
|
372
|
+
*/
|
|
373
|
+
export function masteringInsertNames(): string[] {
|
|
374
|
+
return (
|
|
375
|
+
requireModule() as unknown as { masteringInsertNames: () => string[] }
|
|
376
|
+
).masteringInsertNames();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export function masteringPairProcessorNames(): PairProcessor[] {
|
|
380
|
+
return requireModule().masteringPairProcessorNames() as PairProcessor[];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export function masteringPairAnalysisNames(): PairAnalysis[] {
|
|
384
|
+
return requireModule().masteringPairAnalysisNames() as PairAnalysis[];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function masteringStereoAnalysisNames(): StereoAnalysis[] {
|
|
388
|
+
return requireModule().masteringStereoAnalysisNames() as StereoAnalysis[];
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function masteringProcess(
|
|
392
|
+
processorName: SoloProcessor,
|
|
393
|
+
samples: Float32Array,
|
|
394
|
+
sampleRate = 22050,
|
|
395
|
+
params: MasteringProcessorParams = {},
|
|
396
|
+
): MasteringResult {
|
|
397
|
+
return requireModule().masteringProcess(processorName, samples, sampleRate, params);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function masteringProcessStereo(
|
|
401
|
+
processorName: SoloProcessor,
|
|
402
|
+
left: Float32Array,
|
|
403
|
+
right: Float32Array,
|
|
404
|
+
sampleRate = 22050,
|
|
405
|
+
params: MasteringProcessorParams = {},
|
|
406
|
+
): MasteringStereoResult {
|
|
407
|
+
if (left.length !== right.length) {
|
|
408
|
+
throw new Error('Stereo channel lengths must match.');
|
|
409
|
+
}
|
|
410
|
+
return requireModule().masteringProcessStereo(processorName, left, right, sampleRate, params);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Apply a two-input `match.*` processor. `source` and `reference` may have
|
|
415
|
+
* independent lengths — the match primitives consume each buffer at its own
|
|
416
|
+
* length.
|
|
417
|
+
*/
|
|
418
|
+
export function masteringPairProcess(
|
|
419
|
+
processorName: PairProcessor,
|
|
420
|
+
source: Float32Array,
|
|
421
|
+
reference: Float32Array,
|
|
422
|
+
sampleRate = 22050,
|
|
423
|
+
params: MasteringProcessorParams = {},
|
|
424
|
+
): MasteringResult {
|
|
425
|
+
return requireModule().masteringPairProcess(processorName, source, reference, sampleRate, params);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Analyze a `source` against a `reference` with a two-input analysis. The two
|
|
430
|
+
* buffers may have independent lengths.
|
|
431
|
+
*/
|
|
432
|
+
export function masteringPairAnalyze(
|
|
433
|
+
analysisName: PairAnalysis,
|
|
434
|
+
source: Float32Array,
|
|
435
|
+
reference: Float32Array,
|
|
436
|
+
sampleRate = 22050,
|
|
437
|
+
params: MasteringProcessorParams = {},
|
|
438
|
+
): string {
|
|
439
|
+
return requireModule().masteringPairAnalyze(analysisName, source, reference, sampleRate, params);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export function masteringStereoAnalyze(
|
|
443
|
+
analysisName: StereoAnalysis,
|
|
444
|
+
left: Float32Array,
|
|
445
|
+
right: Float32Array,
|
|
446
|
+
sampleRate = 22050,
|
|
447
|
+
params: MasteringProcessorParams = {},
|
|
448
|
+
): string {
|
|
449
|
+
return requireModule().masteringStereoAnalyze(analysisName, left, right, sampleRate, params);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function masteringAssistantSuggest(
|
|
453
|
+
samples: Float32Array,
|
|
454
|
+
sampleRate = 22050,
|
|
455
|
+
params: MasteringProcessorParams = {},
|
|
456
|
+
): string {
|
|
457
|
+
return requireModule().masteringAssistantSuggest(samples, sampleRate, params);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export function masteringAudioProfile(
|
|
461
|
+
samples: Float32Array,
|
|
462
|
+
sampleRate = 22050,
|
|
463
|
+
params: MasteringProcessorParams = {},
|
|
464
|
+
): string {
|
|
465
|
+
return requireModule().masteringAudioProfile(samples, sampleRate, params);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export function masteringStreamingPreview(
|
|
469
|
+
samples: Float32Array,
|
|
470
|
+
sampleRate = 22050,
|
|
471
|
+
platforms: StreamingPlatform[] = [],
|
|
472
|
+
): string {
|
|
473
|
+
return requireModule().masteringStreamingPreview(samples, sampleRate, platforms);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ============================================================================
|
|
477
|
+
// Mastering repair (declick, denoise_classical, declip, decrackle, dehum,
|
|
478
|
+
// dereverb_classical, trim_silence) — hand-written bindings.
|
|
479
|
+
// ============================================================================
|
|
480
|
+
|
|
481
|
+
/** Options for `masteringRepairDeclick`. */
|
|
482
|
+
export interface DeclickOptions {
|
|
483
|
+
threshold?: number;
|
|
484
|
+
neighborRatio?: number;
|
|
485
|
+
maxClickSamples?: number;
|
|
486
|
+
lpcOrder?: number;
|
|
487
|
+
residualRatio?: number;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Algorithms accepted by `masteringRepairDenoiseClassical`. */
|
|
491
|
+
export type DenoiseClassicalMode = 'logMmse' | 'mmseStsa' | 'spectralSubtraction';
|
|
492
|
+
|
|
493
|
+
/** Noise PSD estimators accepted by `masteringRepairDenoiseClassical`. */
|
|
494
|
+
export type DenoiseClassicalNoiseEstimator = 'quantile' | 'mcra' | 'imcra';
|
|
495
|
+
|
|
496
|
+
/** Options for `masteringRepairDenoiseClassical`. */
|
|
497
|
+
export interface DenoiseClassicalOptions {
|
|
498
|
+
mode?: DenoiseClassicalMode;
|
|
499
|
+
noiseEstimator?: DenoiseClassicalNoiseEstimator;
|
|
500
|
+
nFft?: number;
|
|
501
|
+
hopLength?: number;
|
|
502
|
+
ddAlpha?: number;
|
|
503
|
+
gainFloor?: number;
|
|
504
|
+
overSubtraction?: number;
|
|
505
|
+
spectralFloor?: number;
|
|
506
|
+
noiseEstimationQuantile?: number;
|
|
507
|
+
speechPresenceGain?: boolean;
|
|
508
|
+
gainSmoothing?: boolean;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Offline LPC-based declicker. */
|
|
512
|
+
export function masteringRepairDeclick(
|
|
513
|
+
samples: Float32Array,
|
|
514
|
+
sampleRate: number,
|
|
515
|
+
options: DeclickOptions = {},
|
|
516
|
+
): Float32Array {
|
|
517
|
+
return requireModule().masteringRepairDeclick(samples, sampleRate, options);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** Offline STFT-domain classical denoiser (LogMMSE / MMSE-STSA / SpectralSubtraction). */
|
|
521
|
+
export function masteringRepairDenoiseClassical(
|
|
522
|
+
samples: Float32Array,
|
|
523
|
+
sampleRate: number,
|
|
524
|
+
options: DenoiseClassicalOptions = {},
|
|
525
|
+
): Float32Array {
|
|
526
|
+
return requireModule().masteringRepairDenoiseClassical(samples, sampleRate, options);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** Options for `masteringRepairDeclip`. */
|
|
530
|
+
export interface DeclipOptions {
|
|
531
|
+
clipThreshold?: number;
|
|
532
|
+
lpcOrder?: number;
|
|
533
|
+
iterations?: number;
|
|
534
|
+
lpcBlend?: number;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/** Algorithms accepted by `masteringRepairDecrackle`. */
|
|
538
|
+
export type DecrackleMode = 'median' | 'waveletShrinkage';
|
|
539
|
+
|
|
540
|
+
/** Options for `masteringRepairDecrackle`. */
|
|
541
|
+
export interface DecrackleOptions {
|
|
542
|
+
threshold?: number;
|
|
543
|
+
mode?: DecrackleMode;
|
|
544
|
+
levels?: number;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** Options for `masteringRepairDehum`. */
|
|
548
|
+
export interface DehumOptions {
|
|
549
|
+
fundamentalHz?: number;
|
|
550
|
+
harmonics?: number;
|
|
551
|
+
q?: number;
|
|
552
|
+
adaptive?: boolean;
|
|
553
|
+
searchRangeHz?: number;
|
|
554
|
+
adaptation?: number;
|
|
555
|
+
frameSize?: number;
|
|
556
|
+
pllBandwidth?: number;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** Options for `masteringRepairDereverbClassical`. */
|
|
560
|
+
export interface DereverbClassicalOptions {
|
|
561
|
+
threshold?: number;
|
|
562
|
+
attenuation?: number;
|
|
563
|
+
nFft?: number;
|
|
564
|
+
hopLength?: number;
|
|
565
|
+
t60Sec?: number;
|
|
566
|
+
lateDelayMs?: number;
|
|
567
|
+
overSubtraction?: number;
|
|
568
|
+
spectralFloor?: number;
|
|
569
|
+
wpeEnabled?: boolean;
|
|
570
|
+
wpeIterations?: number;
|
|
571
|
+
wpeTaps?: number;
|
|
572
|
+
wpeStrength?: number;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/** Trimming modes accepted by `masteringRepairTrimSilence`. */
|
|
576
|
+
export type TrimSilenceMode = 'peak' | 'lufsGated';
|
|
577
|
+
|
|
578
|
+
/** Options for `masteringRepairTrimSilence`. */
|
|
579
|
+
export interface TrimSilenceOptions {
|
|
580
|
+
threshold?: number;
|
|
581
|
+
paddingSamples?: number;
|
|
582
|
+
mode?: TrimSilenceMode;
|
|
583
|
+
gateLufs?: number;
|
|
584
|
+
windowMs?: number;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/** Offline LPC-based declipper. */
|
|
588
|
+
export function masteringRepairDeclip(
|
|
589
|
+
samples: Float32Array,
|
|
590
|
+
sampleRate: number,
|
|
591
|
+
options: DeclipOptions = {},
|
|
592
|
+
): Float32Array {
|
|
593
|
+
return requireModule().masteringRepairDeclip(samples, sampleRate, options);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** Offline crackle suppressor (median or wavelet-shrinkage). */
|
|
597
|
+
export function masteringRepairDecrackle(
|
|
598
|
+
samples: Float32Array,
|
|
599
|
+
sampleRate: number,
|
|
600
|
+
options: DecrackleOptions = {},
|
|
601
|
+
): Float32Array {
|
|
602
|
+
return requireModule().masteringRepairDecrackle(samples, sampleRate, options);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** Offline mains-hum remover. */
|
|
606
|
+
export function masteringRepairDehum(
|
|
607
|
+
samples: Float32Array,
|
|
608
|
+
sampleRate: number,
|
|
609
|
+
options: DehumOptions = {},
|
|
610
|
+
): Float32Array {
|
|
611
|
+
return requireModule().masteringRepairDehum(samples, sampleRate, options);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/** Offline classical dereverberator (spectral subtraction + optional WPE). */
|
|
615
|
+
export function masteringRepairDereverbClassical(
|
|
616
|
+
samples: Float32Array,
|
|
617
|
+
sampleRate: number,
|
|
618
|
+
options: DereverbClassicalOptions = {},
|
|
619
|
+
): Float32Array {
|
|
620
|
+
return requireModule().masteringRepairDereverbClassical(samples, sampleRate, options);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/** Offline silence trimmer (peak threshold or LUFS-gated). */
|
|
624
|
+
export function masteringRepairTrimSilence(
|
|
625
|
+
samples: Float32Array,
|
|
626
|
+
sampleRate: number,
|
|
627
|
+
options: TrimSilenceOptions = {},
|
|
628
|
+
): Float32Array {
|
|
629
|
+
return requireModule().masteringRepairTrimSilence(samples, sampleRate, options);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ============================================================================
|
|
633
|
+
// Mastering — offline dynamics processors (compressor / gate / transient_shaper)
|
|
634
|
+
// ============================================================================
|
|
635
|
+
|
|
636
|
+
/** Compressor sidechain detector mode. */
|
|
637
|
+
export type CompressorDetector = 'peak' | 'rms' | 'log_rms';
|
|
638
|
+
|
|
639
|
+
/** Options for `masteringDynamicsCompressor`. */
|
|
640
|
+
export interface CompressorOptions extends ValidateOptions {
|
|
641
|
+
thresholdDb?: number;
|
|
642
|
+
ratio?: number;
|
|
643
|
+
attackMs?: number;
|
|
644
|
+
releaseMs?: number;
|
|
645
|
+
kneeDb?: number;
|
|
646
|
+
makeupGainDb?: number;
|
|
647
|
+
autoMakeup?: boolean;
|
|
648
|
+
detector?: CompressorDetector | number;
|
|
649
|
+
sidechainHpfEnabled?: boolean;
|
|
650
|
+
sidechainHpfHz?: number;
|
|
651
|
+
pdrTimeMs?: number;
|
|
652
|
+
pdrReleaseScale?: number;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** Options for `masteringDynamicsGate`. */
|
|
656
|
+
export interface GateOptions extends ValidateOptions {
|
|
657
|
+
thresholdDb?: number;
|
|
658
|
+
attackMs?: number;
|
|
659
|
+
releaseMs?: number;
|
|
660
|
+
rangeDb?: number;
|
|
661
|
+
holdMs?: number;
|
|
662
|
+
closeThresholdDb?: number;
|
|
663
|
+
keyHpfHz?: number;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/** Options for `masteringDynamicsTransientShaper`. */
|
|
667
|
+
export interface TransientShaperOptions extends ValidateOptions {
|
|
668
|
+
attackGainDb?: number;
|
|
669
|
+
sustainGainDb?: number;
|
|
670
|
+
fastAttackMs?: number;
|
|
671
|
+
fastReleaseMs?: number;
|
|
672
|
+
slowAttackMs?: number;
|
|
673
|
+
slowReleaseMs?: number;
|
|
674
|
+
sensitivity?: number;
|
|
675
|
+
maxGainDb?: number;
|
|
676
|
+
gainSmoothingMs?: number;
|
|
677
|
+
lookaheadMs?: number;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/** Result envelope returned by offline mastering dynamics processors. */
|
|
681
|
+
export interface DynamicsResult {
|
|
682
|
+
samples: Float32Array;
|
|
683
|
+
latencySamples: number;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const COMPRESSOR_DETECTOR_MAP: Record<CompressorDetector, number> = {
|
|
687
|
+
peak: 0,
|
|
688
|
+
rms: 1,
|
|
689
|
+
log_rms: 2,
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
/** Offline feed-forward compressor (soft knee, optional auto-makeup / sidechain HPF). */
|
|
693
|
+
export function masteringDynamicsCompressor(
|
|
694
|
+
samples: Float32Array,
|
|
695
|
+
sampleRate: number,
|
|
696
|
+
options: CompressorOptions = {},
|
|
697
|
+
): DynamicsResult {
|
|
698
|
+
assertSamples('masteringDynamicsCompressor', samples, options.validate !== false);
|
|
699
|
+
const detector =
|
|
700
|
+
typeof options.detector === 'string'
|
|
701
|
+
? COMPRESSOR_DETECTOR_MAP[options.detector]
|
|
702
|
+
: options.detector;
|
|
703
|
+
const opts: Record<string, unknown> = { ...options };
|
|
704
|
+
if (detector !== undefined) {
|
|
705
|
+
opts.detector = detector;
|
|
706
|
+
}
|
|
707
|
+
return requireModule().masteringDynamicsCompressor(samples, sampleRate, opts);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Offline noise gate (hysteresis, hold, optional key HPF). */
|
|
711
|
+
export function masteringDynamicsGate(
|
|
712
|
+
samples: Float32Array,
|
|
713
|
+
sampleRate: number,
|
|
714
|
+
options: GateOptions = {},
|
|
715
|
+
): DynamicsResult {
|
|
716
|
+
assertSamples('masteringDynamicsGate', samples, options.validate !== false);
|
|
717
|
+
return requireModule().masteringDynamicsGate(samples, sampleRate, options);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/** Offline transient shaper (envelope-difference attack/sustain control). */
|
|
721
|
+
export function masteringDynamicsTransientShaper(
|
|
722
|
+
samples: Float32Array,
|
|
723
|
+
sampleRate: number,
|
|
724
|
+
options: TransientShaperOptions = {},
|
|
725
|
+
): DynamicsResult {
|
|
726
|
+
assertSamples('masteringDynamicsTransientShaper', samples, options.validate !== false);
|
|
727
|
+
return requireModule().masteringDynamicsTransientShaper(samples, sampleRate, options);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Apply a configurable mastering chain in WASM.
|
|
732
|
+
*
|
|
733
|
+
* @param samples - Audio samples (mono, float32)
|
|
734
|
+
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
735
|
+
* @param config - Chain stage configuration
|
|
736
|
+
* @returns Processed audio, loudness metadata, and applied stage names
|
|
737
|
+
*/
|
|
738
|
+
export function masteringChain(
|
|
739
|
+
samples: Float32Array,
|
|
740
|
+
sampleRate = 22050,
|
|
741
|
+
config: MasteringChainConfig,
|
|
742
|
+
): MasteringChainResult {
|
|
743
|
+
return requireModule().masteringChain(samples, sampleRate, config as Record<string, unknown>);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Apply a configurable stereo mastering chain in WASM.
|
|
748
|
+
*
|
|
749
|
+
* @param left - Left channel samples
|
|
750
|
+
* @param right - Right channel samples
|
|
751
|
+
* @param sampleRate - Sample rate in Hz
|
|
752
|
+
* @param config - Chain stage configuration
|
|
753
|
+
* @returns Processed stereo audio, loudness metadata, and applied stage names
|
|
754
|
+
*/
|
|
755
|
+
export function masteringChainStereo(
|
|
756
|
+
left: Float32Array,
|
|
757
|
+
right: Float32Array,
|
|
758
|
+
sampleRate = 22050,
|
|
759
|
+
config: MasteringChainConfig,
|
|
760
|
+
): MasteringStereoChainResult {
|
|
761
|
+
if (left.length !== right.length) {
|
|
762
|
+
throw new Error('Stereo channel lengths must match.');
|
|
763
|
+
}
|
|
764
|
+
return requireModule().masteringChainStereo(
|
|
765
|
+
left,
|
|
766
|
+
right,
|
|
767
|
+
sampleRate,
|
|
768
|
+
config as Record<string, unknown>,
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Apply a configurable mastering chain in WASM with progress reporting.
|
|
774
|
+
*
|
|
775
|
+
* @param samples - Audio samples (mono, float32)
|
|
776
|
+
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
777
|
+
* @param config - Chain stage configuration
|
|
778
|
+
* @param onProgress - Progress callback (progress: 0-1, stage: string)
|
|
779
|
+
* @returns Processed audio, loudness metadata, and applied stage names
|
|
780
|
+
*/
|
|
781
|
+
export function masteringChainWithProgress(
|
|
782
|
+
samples: Float32Array,
|
|
783
|
+
sampleRate = 22050,
|
|
784
|
+
config: MasteringChainConfig,
|
|
785
|
+
onProgress: ProgressCallback,
|
|
786
|
+
): MasteringChainResult {
|
|
787
|
+
return requireModule().masteringChainWithProgress(
|
|
788
|
+
samples,
|
|
789
|
+
sampleRate,
|
|
790
|
+
config as Record<string, unknown>,
|
|
791
|
+
onProgress,
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Apply a configurable stereo mastering chain in WASM with progress reporting.
|
|
797
|
+
*
|
|
798
|
+
* @param left - Left channel samples
|
|
799
|
+
* @param right - Right channel samples
|
|
800
|
+
* @param sampleRate - Sample rate in Hz
|
|
801
|
+
* @param config - Chain stage configuration
|
|
802
|
+
* @param onProgress - Progress callback (progress: 0-1, stage: string)
|
|
803
|
+
* @returns Processed stereo audio, loudness metadata, and applied stage names
|
|
804
|
+
*/
|
|
805
|
+
export function masteringChainStereoWithProgress(
|
|
806
|
+
left: Float32Array,
|
|
807
|
+
right: Float32Array,
|
|
808
|
+
sampleRate = 22050,
|
|
809
|
+
config: MasteringChainConfig,
|
|
810
|
+
onProgress: ProgressCallback,
|
|
811
|
+
): MasteringStereoChainResult {
|
|
812
|
+
if (left.length !== right.length) {
|
|
813
|
+
throw new Error('Stereo channel lengths must match.');
|
|
814
|
+
}
|
|
815
|
+
return requireModule().masteringChainStereoWithProgress(
|
|
816
|
+
left,
|
|
817
|
+
right,
|
|
818
|
+
sampleRate,
|
|
819
|
+
config as Record<string, unknown>,
|
|
820
|
+
onProgress,
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* List built-in mastering preset identifiers.
|
|
826
|
+
*
|
|
827
|
+
* @returns Preset names in display order (e.g. "pop", "edm", "aiMusic")
|
|
828
|
+
*/
|
|
829
|
+
export function masteringPresetNames(): MasteringPreset[] {
|
|
830
|
+
return requireModule().masteringPresetNames() as MasteringPreset[];
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Apply a named mastering preset chain to mono audio.
|
|
835
|
+
*
|
|
836
|
+
* @param samples - Audio samples (mono, float32)
|
|
837
|
+
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
838
|
+
* @param presetName - Preset identifier from {@link masteringPresetNames}
|
|
839
|
+
* @param overrides - Optional flat overrides (dot-notation, e.g. `'loudness.targetLufs'`) applied on top of the preset. Pass `null` for preset defaults.
|
|
840
|
+
* @returns Processed audio, loudness metadata, and applied stage names
|
|
841
|
+
*/
|
|
842
|
+
export function masterAudio(
|
|
843
|
+
samples: Float32Array,
|
|
844
|
+
sampleRate = 22050,
|
|
845
|
+
presetName: MasteringPreset = 'pop',
|
|
846
|
+
overrides: Record<string, number | boolean> = {},
|
|
847
|
+
): MasteringChainResult {
|
|
848
|
+
return requireModule().masterAudio(presetName, samples, sampleRate, overrides);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Apply a named mastering preset chain to stereo audio.
|
|
853
|
+
*
|
|
854
|
+
* @param left - Left channel samples
|
|
855
|
+
* @param right - Right channel samples
|
|
856
|
+
* @param sampleRate - Sample rate in Hz
|
|
857
|
+
* @param presetName - Preset identifier from {@link masteringPresetNames}
|
|
858
|
+
* @param overrides - Optional flat overrides (dot-notation, e.g. `'loudness.targetLufs'`) applied on top of the preset. Pass `null` for preset defaults.
|
|
859
|
+
* @returns Processed stereo audio, loudness metadata, and applied stage names
|
|
860
|
+
*/
|
|
861
|
+
export function masterAudioStereo(
|
|
862
|
+
left: Float32Array,
|
|
863
|
+
right: Float32Array,
|
|
864
|
+
sampleRate = 22050,
|
|
865
|
+
presetName: MasteringPreset = 'pop',
|
|
866
|
+
overrides: Record<string, number | boolean> = {},
|
|
867
|
+
): MasteringStereoChainResult {
|
|
868
|
+
if (left.length !== right.length) {
|
|
869
|
+
throw new Error('Stereo channel lengths must match.');
|
|
870
|
+
}
|
|
871
|
+
return requireModule().masterAudioStereo(presetName, left, right, sampleRate, overrides);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Mono `masterAudio` with per-stage progress reporting. `onProgress` is invoked
|
|
876
|
+
* with `(progress, stage)` between each chain stage (progress is in [0,1]).
|
|
877
|
+
*/
|
|
878
|
+
export function masterAudioWithProgress(
|
|
879
|
+
samples: Float32Array,
|
|
880
|
+
sampleRate = 22050,
|
|
881
|
+
presetName: MasteringPreset,
|
|
882
|
+
onProgress: ProgressCallback,
|
|
883
|
+
overrides: Record<string, number | boolean> | null = null,
|
|
884
|
+
): MasteringChainResult {
|
|
885
|
+
return requireModule().masterAudioWithProgress(
|
|
886
|
+
presetName,
|
|
887
|
+
samples,
|
|
888
|
+
sampleRate,
|
|
889
|
+
overrides,
|
|
890
|
+
onProgress,
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Stereo `masterAudio` with per-stage progress reporting.
|
|
896
|
+
*/
|
|
897
|
+
export function masterAudioStereoWithProgress(
|
|
898
|
+
left: Float32Array,
|
|
899
|
+
right: Float32Array,
|
|
900
|
+
sampleRate = 22050,
|
|
901
|
+
presetName: MasteringPreset,
|
|
902
|
+
onProgress: ProgressCallback,
|
|
903
|
+
overrides: Record<string, number | boolean> | null = null,
|
|
904
|
+
): MasteringStereoChainResult {
|
|
905
|
+
if (left.length !== right.length) {
|
|
906
|
+
throw new Error('Stereo channel lengths must match.');
|
|
907
|
+
}
|
|
908
|
+
return requireModule().masterAudioStereoWithProgress(
|
|
909
|
+
presetName,
|
|
910
|
+
left,
|
|
911
|
+
right,
|
|
912
|
+
sampleRate,
|
|
913
|
+
overrides,
|
|
914
|
+
onProgress,
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
export function mixingScenePresetNames(): string[] {
|
|
919
|
+
return requireModule().mixingScenePresetNames();
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Get a built-in mixing scene preset serialized as JSON. This is the canonical
|
|
924
|
+
* name shared with the Node and Python bindings; the returned JSON loads
|
|
925
|
+
* directly into a {@link Mixer} via {@link Mixer.fromSceneJson}.
|
|
926
|
+
*
|
|
927
|
+
* @param presetName - Preset name (see {@link mixingScenePresetNames})
|
|
928
|
+
* @returns Scene JSON string
|
|
929
|
+
*/
|
|
930
|
+
export function mixingScenePresetJson(presetName: string): string {
|
|
931
|
+
return requireModule().mixingScenePresetJson(presetName);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* One-shot stereo mix of multiple strips through the routing graph + master bus.
|
|
936
|
+
*
|
|
937
|
+
* Each returned per-strip meter reflects only this single one-shot block. The
|
|
938
|
+
* integrating-meter fields (`momentaryLufs`, `shortTermLufs`, `integratedLufs`
|
|
939
|
+
* and the true-peak fields) require sustained streaming to populate; on a short
|
|
940
|
+
* one-shot mix they read the -120 dB floor sentinel. Drive a streaming
|
|
941
|
+
* {@link Mixer} block-by-block if you need meaningful loudness/true-peak
|
|
942
|
+
* readings.
|
|
943
|
+
*
|
|
944
|
+
* @param leftChannels - Per-strip left input buffers (all the same length)
|
|
945
|
+
* @param rightChannels - Per-strip right input buffers (all the same length)
|
|
946
|
+
* @param sampleRate - Sample rate in Hz
|
|
947
|
+
* @param options - Per-strip mix options (trim, fader, pan, width, mute)
|
|
948
|
+
*/
|
|
949
|
+
export function mixStereo(
|
|
950
|
+
leftChannels: Float32Array[],
|
|
951
|
+
rightChannels: Float32Array[],
|
|
952
|
+
sampleRate = 48000,
|
|
953
|
+
options: MixOptions = {},
|
|
954
|
+
): MixResult {
|
|
955
|
+
if (leftChannels.length === 0 || leftChannels.length !== rightChannels.length) {
|
|
956
|
+
throw new Error('leftChannels and rightChannels must have the same non-zero length.');
|
|
957
|
+
}
|
|
958
|
+
return requireModule().mixStereo(
|
|
959
|
+
leftChannels,
|
|
960
|
+
rightChannels,
|
|
961
|
+
sampleRate,
|
|
962
|
+
options as Record<string, unknown>,
|
|
963
|
+
);
|
|
964
|
+
}
|