@libraz/libsonare 1.5.1 → 1.5.3

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.
Files changed (48) hide show
  1. package/README.md +18 -3
  2. package/dist/index.d.ts +1165 -178
  3. package/dist/index.js +4830 -3871
  4. package/dist/index.js.map +1 -1
  5. package/dist/sonare.js +1 -1
  6. package/dist/sonare.wasm +0 -0
  7. package/dist/worklet.d.ts +29 -1
  8. package/dist/worklet.js +1068 -974
  9. package/dist/worklet.js.map +1 -1
  10. package/package.json +2 -1
  11. package/src/_chain_config.ts +46 -0
  12. package/src/audio.ts +24 -4
  13. package/src/effects_mastering.ts +25 -1
  14. package/src/effects_transform.ts +283 -43
  15. package/src/effects_voice_change.ts +46 -53
  16. package/src/feature_core.ts +316 -12
  17. package/src/feature_music.ts +462 -0
  18. package/src/feature_pitch.ts +61 -0
  19. package/src/feature_resample.ts +17 -2
  20. package/src/feature_spectral.ts +349 -2
  21. package/src/feature_spectrogram.ts +336 -0
  22. package/src/features.ts +2 -0
  23. package/src/index.ts +133 -1
  24. package/src/mastering_chain.ts +305 -50
  25. package/src/mastering_core.ts +242 -16
  26. package/src/mastering_dynamics.ts +66 -10
  27. package/src/mastering_repair.ts +119 -7
  28. package/src/metering.ts +366 -81
  29. package/src/mixer.ts +10 -3
  30. package/src/mixing_oneshot.ts +25 -5
  31. package/src/module_state.ts +1 -1
  32. package/src/project_class.ts +17 -6
  33. package/src/project_internal.ts +10 -2
  34. package/src/project_types.ts +25 -2
  35. package/src/public_types_mastering.ts +114 -4
  36. package/src/public_types_music.ts +1 -0
  37. package/src/public_types_spectral.ts +7 -0
  38. package/src/quick_analysis.ts +325 -117
  39. package/src/realtime_engine.ts +8 -0
  40. package/src/sonare.js.d.ts +56 -0
  41. package/src/stream_analyzer.ts +25 -2
  42. package/src/stream_types.ts +16 -1
  43. package/src/validation.ts +17 -2
  44. package/src/worklet/engine-clips.ts +67 -2
  45. package/src/worklet/engine-processor.ts +33 -5
  46. package/src/worklet/engine.ts +7 -3
  47. package/src/worklet/guards.ts +3 -0
  48. package/src/worklet/messages.ts +27 -0
@@ -15,6 +15,68 @@ function requireModule() {
15
15
  return getSonareModule();
16
16
  }
17
17
 
18
+ /** Canonical request form for loudness/true-peak mastering. */
19
+ export interface MasteringRequest extends MasteringOptions {
20
+ samples: Float32Array;
21
+ sampleRate?: number;
22
+ }
23
+
24
+ export interface MasteringProcessRequest {
25
+ processorName: SoloProcessor;
26
+ samples: Float32Array;
27
+ sampleRate?: number;
28
+ params?: MasteringProcessorParams;
29
+ }
30
+
31
+ export interface MasteringProcessStereoRequest {
32
+ processorName: SoloProcessor;
33
+ left: Float32Array;
34
+ right: Float32Array;
35
+ sampleRate?: number;
36
+ params?: MasteringProcessorParams;
37
+ }
38
+
39
+ /** Canonical request form for a two-input match processor. */
40
+ export interface MasteringPairProcessRequest {
41
+ processorName: PairProcessor;
42
+ source: Float32Array;
43
+ reference: Float32Array;
44
+ sampleRate?: number;
45
+ params?: MasteringProcessorParams;
46
+ }
47
+
48
+ /** Canonical request form for a two-input match analysis. */
49
+ export interface MasteringPairAnalyzeRequest {
50
+ analysisName: PairAnalysis;
51
+ source: Float32Array;
52
+ reference: Float32Array;
53
+ sampleRate?: number;
54
+ params?: MasteringProcessorParams;
55
+ }
56
+
57
+ /** Canonical request form for a stereo analysis. */
58
+ export interface MasteringStereoAnalyzeRequest {
59
+ analysisName: StereoAnalysis;
60
+ left: Float32Array;
61
+ right: Float32Array;
62
+ sampleRate?: number;
63
+ params?: MasteringProcessorParams;
64
+ }
65
+
66
+ /** Canonical request form for assistant/profile calls. */
67
+ export interface MasteringSamplesParamsRequest {
68
+ samples: Float32Array;
69
+ sampleRate?: number;
70
+ params?: MasteringProcessorParams;
71
+ }
72
+
73
+ /** Canonical request form for streaming-platform preview. */
74
+ export interface MasteringStreamingPreviewRequest {
75
+ samples: Float32Array;
76
+ sampleRate?: number;
77
+ platforms?: StreamingPlatform[];
78
+ }
79
+
18
80
  /**
19
81
  * Apply mastering loudness normalization with a true-peak ceiling.
20
82
  *
@@ -23,19 +85,26 @@ function requireModule() {
23
85
  * @param options - Loudness/ceiling settings ({@link MasteringOptions})
24
86
  * @returns Processed audio and loudness metadata
25
87
  */
88
+ export function mastering(request: MasteringRequest): MasteringResult;
26
89
  export function mastering(
27
90
  samples: Float32Array,
91
+ sampleRate?: number,
92
+ options?: MasteringOptions,
93
+ ): MasteringResult;
94
+ export function mastering(
95
+ samples: MasteringRequest | Float32Array,
28
96
  sampleRate = 22050,
29
97
  options: MasteringOptions = {},
30
98
  ): MasteringResult {
99
+ const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
31
100
  return requireModule().mastering(
32
- samples,
33
- sampleRate,
34
- options.targetLufs ?? -14.0,
35
- options.ceilingDb ?? -1.0,
36
- options.truePeakOversample ?? 4,
37
- options.releaseMs ?? 0, // 0 => library default (50 ms)
38
- options.applyGainAtInputRate ?? false,
101
+ request.samples,
102
+ request.sampleRate ?? 22050,
103
+ request.targetLufs ?? -14.0,
104
+ request.ceilingDb ?? -1.0,
105
+ request.truePeakOversample ?? 4,
106
+ request.releaseMs ?? 0, // 0 => library default (50 ms)
107
+ request.applyGainAtInputRate ?? false,
39
108
  );
40
109
  }
41
110
 
@@ -129,6 +198,16 @@ export interface MasteringProcessorCatalogEntry {
129
198
  realtimeInsertable: boolean;
130
199
  /** True for processors with no mono implementation (stereo-only). */
131
200
  stereoOnly: boolean;
201
+ /**
202
+ * Reported latency for the default 48 kHz / 512-sample probe configuration.
203
+ * Zero for offline processors; configuration-dependent values are estimates.
204
+ */
205
+ latencySamples: number;
206
+ /**
207
+ * Audible decay length for the same default prepared probe. Zero for
208
+ * offline, dry-only, and no-tail processors.
209
+ */
210
+ tailSamples: number;
132
211
  /**
133
212
  * How the mixer wraps the processor on a >2-channel (surround) bus insert:
134
213
  * "multichannel" (one full-buffer call) or "stereoPairOnly" (front L/R pair,
@@ -162,26 +241,68 @@ export function masteringStereoAnalysisNames(): StereoAnalysis[] {
162
241
  return Array.from(requireModule().masteringStereoAnalysisNames()) as StereoAnalysis[];
163
242
  }
164
243
 
244
+ export function masteringProcess(request: MasteringProcessRequest): MasteringResult;
165
245
  export function masteringProcess(
166
246
  processorName: SoloProcessor,
167
247
  samples: Float32Array,
248
+ sampleRate?: number,
249
+ params?: MasteringProcessorParams,
250
+ ): MasteringResult;
251
+ export function masteringProcess(
252
+ processorName: SoloProcessor | MasteringProcessRequest,
253
+ samples?: Float32Array,
168
254
  sampleRate = 22050,
169
255
  params: MasteringProcessorParams = {},
170
256
  ): MasteringResult {
171
- return requireModule().masteringProcess(processorName, samples, sampleRate, params);
257
+ const request =
258
+ typeof processorName === 'string'
259
+ ? { processorName, samples: samples as Float32Array, sampleRate, params }
260
+ : processorName;
261
+ return requireModule().masteringProcess(
262
+ request.processorName,
263
+ request.samples,
264
+ request.sampleRate ?? 22050,
265
+ request.params ?? {},
266
+ );
172
267
  }
173
268
 
269
+ export function masteringProcessStereo(
270
+ request: MasteringProcessStereoRequest,
271
+ ): MasteringStereoResult;
174
272
  export function masteringProcessStereo(
175
273
  processorName: SoloProcessor,
176
274
  left: Float32Array,
177
275
  right: Float32Array,
276
+ sampleRate?: number,
277
+ params?: MasteringProcessorParams,
278
+ ): MasteringStereoResult;
279
+ export function masteringProcessStereo(
280
+ processorName: SoloProcessor | MasteringProcessStereoRequest,
281
+ left?: Float32Array,
282
+ right?: Float32Array,
178
283
  sampleRate = 22050,
179
284
  params: MasteringProcessorParams = {},
180
285
  ): MasteringStereoResult {
181
- if (left.length !== right.length) {
286
+ const request =
287
+ typeof processorName === 'string'
288
+ ? {
289
+ processorName,
290
+ left: left as Float32Array,
291
+ right: right as Float32Array,
292
+ sampleRate,
293
+ params,
294
+ }
295
+ : processorName;
296
+ if (request.left.length !== request.right.length) {
182
297
  throw new Error('Stereo channel lengths must match.');
183
298
  }
184
- return requireModule().masteringProcessStereo(processorName, left, right, sampleRate, params);
299
+ return requireModule().masteringProcessStereo(
300
+ request.processorName,
301
+ request.left,
302
+ request.right,
303
+ request.sampleRate ?? 22050,
304
+ request.params ?? {},
305
+ );
185
306
  }
186
307
 
187
308
  /**
@@ -189,60 +310,165 @@ export function masteringProcessStereo(
189
310
  * independent lengths — the match primitives consume each buffer at its own
190
311
  * length.
191
312
  */
313
+ export function masteringPairProcess(request: MasteringPairProcessRequest): MasteringResult;
192
314
  export function masteringPairProcess(
193
315
  processorName: PairProcessor,
194
316
  source: Float32Array,
195
317
  reference: Float32Array,
318
+ sampleRate?: number,
319
+ params?: MasteringProcessorParams,
320
+ ): MasteringResult;
321
+ export function masteringPairProcess(
322
+ processorName: PairProcessor | MasteringPairProcessRequest,
323
+ source?: Float32Array,
324
+ reference?: Float32Array,
196
325
  sampleRate = 22050,
197
326
  params: MasteringProcessorParams = {},
198
327
  ): MasteringResult {
199
- return requireModule().masteringPairProcess(processorName, source, reference, sampleRate, params);
328
+ const request =
329
+ typeof processorName === 'string'
330
+ ? {
331
+ processorName,
332
+ source: source as Float32Array,
333
+ reference: reference as Float32Array,
334
+ sampleRate,
335
+ params,
336
+ }
337
+ : processorName;
338
+ return requireModule().masteringPairProcess(
339
+ request.processorName,
340
+ request.source,
341
+ request.reference,
342
+ request.sampleRate ?? 22050,
343
+ request.params ?? {},
344
+ );
200
345
  }
201
346
 
202
347
  /**
203
348
  * Analyze a `source` against a `reference` with a two-input analysis. The two
204
349
  * buffers may have independent lengths.
205
350
  */
351
+ export function masteringPairAnalyze(request: MasteringPairAnalyzeRequest): string;
206
352
  export function masteringPairAnalyze(
207
353
  analysisName: PairAnalysis,
208
354
  source: Float32Array,
209
355
  reference: Float32Array,
356
+ sampleRate?: number,
357
+ params?: MasteringProcessorParams,
358
+ ): string;
359
+ export function masteringPairAnalyze(
360
+ analysisName: PairAnalysis | MasteringPairAnalyzeRequest,
361
+ source?: Float32Array,
362
+ reference?: Float32Array,
210
363
  sampleRate = 22050,
211
364
  params: MasteringProcessorParams = {},
212
365
  ): string {
213
- return requireModule().masteringPairAnalyze(analysisName, source, reference, sampleRate, params);
366
+ const request =
367
+ typeof analysisName === 'string'
368
+ ? {
369
+ analysisName,
370
+ source: source as Float32Array,
371
+ reference: reference as Float32Array,
372
+ sampleRate,
373
+ params,
374
+ }
375
+ : analysisName;
376
+ return requireModule().masteringPairAnalyze(
377
+ request.analysisName,
378
+ request.source,
379
+ request.reference,
380
+ request.sampleRate ?? 22050,
381
+ request.params ?? {},
382
+ );
214
383
  }
215
384
 
385
+ export function masteringStereoAnalyze(request: MasteringStereoAnalyzeRequest): string;
216
386
  export function masteringStereoAnalyze(
217
387
  analysisName: StereoAnalysis,
218
388
  left: Float32Array,
219
389
  right: Float32Array,
390
+ sampleRate?: number,
391
+ params?: MasteringProcessorParams,
392
+ ): string;
393
+ export function masteringStereoAnalyze(
394
+ analysisName: StereoAnalysis | MasteringStereoAnalyzeRequest,
395
+ left?: Float32Array,
396
+ right?: Float32Array,
220
397
  sampleRate = 22050,
221
398
  params: MasteringProcessorParams = {},
222
399
  ): string {
223
- return requireModule().masteringStereoAnalyze(analysisName, left, right, sampleRate, params);
400
+ const request =
401
+ typeof analysisName === 'string'
402
+ ? {
403
+ analysisName,
404
+ left: left as Float32Array,
405
+ right: right as Float32Array,
406
+ sampleRate,
407
+ params,
408
+ }
409
+ : analysisName;
410
+ return requireModule().masteringStereoAnalyze(
411
+ request.analysisName,
412
+ request.left,
413
+ request.right,
414
+ request.sampleRate ?? 22050,
415
+ request.params ?? {},
416
+ );
224
417
  }
225
418
 
419
+ export function masteringAssistantSuggest(request: MasteringSamplesParamsRequest): string;
226
420
  export function masteringAssistantSuggest(
227
421
  samples: Float32Array,
422
+ sampleRate?: number,
423
+ params?: MasteringProcessorParams,
424
+ ): string;
425
+ export function masteringAssistantSuggest(
426
+ samples: Float32Array | MasteringSamplesParamsRequest,
228
427
  sampleRate = 22050,
229
428
  params: MasteringProcessorParams = {},
230
429
  ): string {
231
- return requireModule().masteringAssistantSuggest(samples, sampleRate, params);
430
+ const request = samples instanceof Float32Array ? { samples, sampleRate, params } : samples;
431
+ return requireModule().masteringAssistantSuggest(
432
+ request.samples,
433
+ request.sampleRate ?? 22050,
434
+ request.params ?? {},
435
+ );
232
436
  }
233
437
 
438
+ export function masteringAudioProfile(request: MasteringSamplesParamsRequest): string;
234
439
  export function masteringAudioProfile(
235
440
  samples: Float32Array,
441
+ sampleRate?: number,
442
+ params?: MasteringProcessorParams,
443
+ ): string;
444
+ export function masteringAudioProfile(
445
+ samples: Float32Array | MasteringSamplesParamsRequest,
236
446
  sampleRate = 22050,
237
447
  params: MasteringProcessorParams = {},
238
448
  ): string {
239
- return requireModule().masteringAudioProfile(samples, sampleRate, params);
449
+ const request = samples instanceof Float32Array ? { samples, sampleRate, params } : samples;
450
+ return requireModule().masteringAudioProfile(
451
+ request.samples,
452
+ request.sampleRate ?? 22050,
453
+ request.params ?? {},
454
+ );
240
455
  }
241
456
 
457
+ export function masteringStreamingPreview(request: MasteringStreamingPreviewRequest): string;
242
458
  export function masteringStreamingPreview(
243
459
  samples: Float32Array,
460
+ sampleRate?: number,
461
+ platforms?: StreamingPlatform[],
462
+ ): string;
463
+ export function masteringStreamingPreview(
464
+ samples: Float32Array | MasteringStreamingPreviewRequest,
244
465
  sampleRate = 22050,
245
466
  platforms: StreamingPlatform[] = [],
246
467
  ): string {
247
- return requireModule().masteringStreamingPreview(samples, sampleRate, platforms);
468
+ const request = samples instanceof Float32Array ? { samples, sampleRate, platforms } : samples;
469
+ return requireModule().masteringStreamingPreview(
470
+ request.samples,
471
+ request.sampleRate ?? 22050,
472
+ request.platforms ?? [],
473
+ );
248
474
  }
@@ -29,6 +29,12 @@ export interface CompressorOptions extends ValidateOptions {
29
29
  pdrReleaseScale?: number;
30
30
  }
31
31
 
32
+ /** Canonical request form for the offline compressor. */
33
+ export interface MasteringDynamicsCompressorRequest extends CompressorOptions {
34
+ samples: Float32Array;
35
+ sampleRate: number;
36
+ }
37
+
32
38
  /** Options for `masteringDynamicsGate`. */
33
39
  export interface GateOptions extends ValidateOptions {
34
40
  thresholdDb?: number;
@@ -40,6 +46,12 @@ export interface GateOptions extends ValidateOptions {
40
46
  keyHpfHz?: number;
41
47
  }
42
48
 
49
+ /** Canonical request form for the offline gate. */
50
+ export interface MasteringDynamicsGateRequest extends GateOptions {
51
+ samples: Float32Array;
52
+ sampleRate: number;
53
+ }
54
+
43
55
  /** Options for `masteringDynamicsTransientShaper`. */
44
56
  export interface TransientShaperOptions extends ValidateOptions {
45
57
  attackGainDb?: number;
@@ -54,6 +66,12 @@ export interface TransientShaperOptions extends ValidateOptions {
54
66
  lookaheadMs?: number;
55
67
  }
56
68
 
69
+ /** Canonical request form for the offline transient shaper. */
70
+ export interface MasteringDynamicsTransientShaperRequest extends TransientShaperOptions {
71
+ samples: Float32Array;
72
+ sampleRate: number;
73
+ }
74
+
57
75
  /** Result envelope returned by offline mastering dynamics processors. */
58
76
  export interface DynamicsResult {
59
77
  samples: Float32Array;
@@ -67,39 +85,77 @@ const COMPRESSOR_DETECTOR_MAP: Record<CompressorDetector, number> = {
67
85
  };
68
86
 
69
87
  /** Offline feed-forward compressor (soft knee, optional auto-makeup / sidechain HPF). */
88
+ export function masteringDynamicsCompressor(
89
+ request: MasteringDynamicsCompressorRequest,
90
+ ): DynamicsResult;
70
91
  export function masteringDynamicsCompressor(
71
92
  samples: Float32Array,
72
93
  sampleRate: number,
94
+ options?: CompressorOptions,
95
+ ): DynamicsResult;
96
+ export function masteringDynamicsCompressor(
97
+ samples: Float32Array | MasteringDynamicsCompressorRequest,
98
+ sampleRate?: number,
73
99
  options: CompressorOptions = {},
74
100
  ): DynamicsResult {
75
- assertSamples('masteringDynamicsCompressor', samples, options.validate !== false);
101
+ const request =
102
+ samples instanceof Float32Array
103
+ ? { samples, sampleRate: sampleRate as number, ...options }
104
+ : samples;
105
+ assertSamples('masteringDynamicsCompressor', request.samples, request.validate !== false);
76
106
  const detector =
77
- typeof options.detector === 'string'
78
- ? COMPRESSOR_DETECTOR_MAP[options.detector]
79
- : options.detector;
80
- const opts: Record<string, unknown> = { ...options };
107
+ typeof request.detector === 'string'
108
+ ? COMPRESSOR_DETECTOR_MAP[request.detector]
109
+ : request.detector;
110
+ const opts: Record<string, unknown> = { ...request };
81
111
  if (detector !== undefined) {
82
112
  opts.detector = detector;
83
113
  }
84
- return requireModule().masteringDynamicsCompressor(samples, sampleRate, opts);
114
+ return requireModule().masteringDynamicsCompressor(request.samples, request.sampleRate, opts);
85
115
  }
86
116
 
87
117
  /** Offline noise gate (hysteresis, hold, optional key HPF). */
118
+ export function masteringDynamicsGate(request: MasteringDynamicsGateRequest): DynamicsResult;
88
119
  export function masteringDynamicsGate(
89
120
  samples: Float32Array,
90
121
  sampleRate: number,
122
+ options?: GateOptions,
123
+ ): DynamicsResult;
124
+ export function masteringDynamicsGate(
125
+ samples: Float32Array | MasteringDynamicsGateRequest,
126
+ sampleRate?: number,
91
127
  options: GateOptions = {},
92
128
  ): DynamicsResult {
93
- assertSamples('masteringDynamicsGate', samples, options.validate !== false);
94
- return requireModule().masteringDynamicsGate(samples, sampleRate, options);
129
+ const request =
130
+ samples instanceof Float32Array
131
+ ? { samples, sampleRate: sampleRate as number, ...options }
132
+ : samples;
133
+ assertSamples('masteringDynamicsGate', request.samples, request.validate !== false);
134
+ return requireModule().masteringDynamicsGate(request.samples, request.sampleRate, request);
95
135
  }
96
136
 
97
137
  /** Offline transient shaper (envelope-difference attack/sustain control). */
138
+ export function masteringDynamicsTransientShaper(
139
+ request: MasteringDynamicsTransientShaperRequest,
140
+ ): DynamicsResult;
98
141
  export function masteringDynamicsTransientShaper(
99
142
  samples: Float32Array,
100
143
  sampleRate: number,
144
+ options?: TransientShaperOptions,
145
+ ): DynamicsResult;
146
+ export function masteringDynamicsTransientShaper(
147
+ samples: Float32Array | MasteringDynamicsTransientShaperRequest,
148
+ sampleRate?: number,
101
149
  options: TransientShaperOptions = {},
102
150
  ): DynamicsResult {
103
- assertSamples('masteringDynamicsTransientShaper', samples, options.validate !== false);
104
- return requireModule().masteringDynamicsTransientShaper(samples, sampleRate, options);
151
+ const request =
152
+ samples instanceof Float32Array
153
+ ? { samples, sampleRate: sampleRate as number, ...options }
154
+ : samples;
155
+ assertSamples('masteringDynamicsTransientShaper', request.samples, request.validate !== false);
156
+ return requireModule().masteringDynamicsTransientShaper(
157
+ request.samples,
158
+ request.sampleRate,
159
+ request,
160
+ );
105
161
  }