@libraz/libsonare 1.5.2 → 1.5.4

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 +69 -725
  2. package/dist/index.d.ts +1155 -183
  3. package/dist/index.js +4924 -3935
  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 +1141 -970
  9. package/dist/worklet.js.map +1 -1
  10. package/package.json +15 -3
  11. package/src/_chain_config.ts +46 -0
  12. package/src/audio.ts +24 -4
  13. package/src/codes.ts +27 -4
  14. package/src/effects_mastering.ts +25 -1
  15. package/src/effects_transform.ts +292 -46
  16. package/src/effects_voice_change.ts +46 -53
  17. package/src/feature_core.ts +316 -12
  18. package/src/feature_music.ts +371 -4
  19. package/src/feature_pitch.ts +61 -0
  20. package/src/feature_resample.ts +17 -2
  21. package/src/feature_spectral.ts +349 -2
  22. package/src/feature_spectrogram.ts +336 -0
  23. package/src/index.ts +130 -1
  24. package/src/mastering_chain.ts +305 -50
  25. package/src/mastering_core.ts +232 -16
  26. package/src/mastering_dynamics.ts +66 -10
  27. package/src/mastering_repair.ts +119 -7
  28. package/src/metering.ts +370 -83
  29. package/src/mixer.ts +9 -2
  30. package/src/mixing_oneshot.ts +25 -5
  31. package/src/module_state.ts +1 -1
  32. package/src/project_class.ts +30 -6
  33. package/src/project_internal.ts +12 -2
  34. package/src/project_types.ts +25 -2
  35. package/src/public_types_mastering.ts +114 -4
  36. package/src/public_types_spectral.ts +7 -0
  37. package/src/quick_analysis.ts +325 -117
  38. package/src/realtime_engine.ts +8 -0
  39. package/src/realtime_voice_changer.ts +79 -3
  40. package/src/sonare.js.d.ts +35 -0
  41. package/src/stream_analyzer.ts +20 -1
  42. package/src/stream_types.ts +12 -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
@@ -1,3 +1,4 @@
1
+ import { ErrorCode, SonareError } from './errors';
1
2
  import { getSonareModule } from './module_state';
2
3
  import type {
3
4
  AnalyzeSectionsOptions,
@@ -25,6 +26,80 @@ type GuardedOptions = ValidateOptions;
25
26
  type AnalyzeSectionsGuardedOptions = AnalyzeSectionsOptions & ValidateOptions;
26
27
  type MelodyGuardedOptions = MelodyOptions & ValidateOptions;
27
28
 
29
+ /** Canonical request form shared by the Constant-Q transform variants. */
30
+ export interface CqtRequest extends GuardedOptions {
31
+ samples: Float32Array;
32
+ sampleRate?: number;
33
+ hopLength?: number;
34
+ fmin?: number;
35
+ nBins?: number;
36
+ binsPerOctave?: number;
37
+ }
38
+
39
+ /** Canonical request form for {@link vqt}. */
40
+ export interface VqtRequest extends CqtRequest {
41
+ gamma?: number;
42
+ }
43
+
44
+ export interface OnsetEnvelopeRequest extends GuardedOptions {
45
+ samples: Float32Array;
46
+ sampleRate?: number;
47
+ nFft?: number;
48
+ hopLength?: number;
49
+ nMels?: number;
50
+ }
51
+
52
+ export interface OnsetStrengthMultiRequest extends OnsetEnvelopeRequest {
53
+ nBands?: number;
54
+ }
55
+
56
+ export interface FourierTempogramRequest extends GuardedOptions {
57
+ onsetEnvelope: Float32Array;
58
+ sampleRate?: number;
59
+ hopLength?: number;
60
+ winLength?: number;
61
+ }
62
+
63
+ export interface TempogramRatioRequest extends GuardedOptions {
64
+ tempogramData: Float32Array;
65
+ winLength?: number;
66
+ sampleRate?: number;
67
+ hopLength?: number;
68
+ factors?: Float32Array | number[];
69
+ }
70
+
71
+ export interface CqtToAudioRequest extends GuardedOptions {
72
+ magnitude: Float32Array;
73
+ nBins: number;
74
+ nFrames: number;
75
+ sampleRate?: number;
76
+ hopLength?: number;
77
+ fmin?: number;
78
+ binsPerOctave?: number;
79
+ nIter?: number;
80
+ }
81
+
82
+ export interface VqtToAudioRequest extends CqtToAudioRequest {
83
+ gamma?: number;
84
+ }
85
+
86
+ export interface AnalyzeSectionsRequest extends AnalyzeSectionsGuardedOptions {
87
+ samples: Float32Array;
88
+ sampleRate?: number;
89
+ }
90
+ export interface AnalyzeMelodyRequest extends MelodyGuardedOptions {
91
+ samples: Float32Array;
92
+ sampleRate?: number;
93
+ }
94
+ export interface LufsRequest extends ValidateOptions {
95
+ samples: Float32Array;
96
+ sampleRate?: number;
97
+ }
98
+ export interface NnlsChromaRequest extends GuardedOptions {
99
+ samples: Float32Array;
100
+ sampleRate?: number;
101
+ }
102
+
28
103
  function validateMusicSamples(
29
104
  fnName: string,
30
105
  samples: Float32Array,
@@ -61,11 +136,20 @@ function validateFrequencyBounds(fnName: string, fmin: number, fmax?: number): v
61
136
  * @param sampleRate - Sample rate in Hz (default: 22050)
62
137
  * @returns NNLS chroma result
63
138
  */
139
+ export function nnlsChroma(request: NnlsChromaRequest): WasmNnlsChromaResult;
64
140
  export function nnlsChroma(
65
141
  samples: Float32Array,
142
+ sampleRate?: number,
143
+ options?: GuardedOptions,
144
+ ): WasmNnlsChromaResult;
145
+ export function nnlsChroma(
146
+ samples: Float32Array | NnlsChromaRequest,
66
147
  sampleRate = 22050,
67
148
  options: GuardedOptions = {},
68
149
  ): WasmNnlsChromaResult {
150
+ if (!(samples instanceof Float32Array)) {
151
+ return nnlsChroma(samples.samples, samples.sampleRate, samples);
152
+ }
69
153
  validateMusicSamples('nnlsChroma', samples, sampleRate, options);
70
154
  return requireModule().nnlsChroma(samples, sampleRate);
71
155
  }
@@ -81,8 +165,18 @@ export function nnlsChroma(
81
165
  * @param binsPerOctave - Bins per octave (default: 12)
82
166
  * @returns CQT magnitude result
83
167
  */
168
+ export function cqt(request: CqtRequest): CqtResult;
84
169
  export function cqt(
85
170
  samples: Float32Array,
171
+ sampleRate?: number,
172
+ hopLength?: number,
173
+ fmin?: number,
174
+ nBins?: number,
175
+ binsPerOctave?: number,
176
+ options?: GuardedOptions,
177
+ ): CqtResult;
178
+ export function cqt(
179
+ samples: Float32Array | CqtRequest,
86
180
  sampleRate = 22050,
87
181
  hopLength = 512,
88
182
  fmin = 32.70319566257483,
@@ -90,6 +184,18 @@ export function cqt(
90
184
  binsPerOctave = 12,
91
185
  options: GuardedOptions = {},
92
186
  ): CqtResult {
187
+ if (!(samples instanceof Float32Array)) {
188
+ const request = samples;
189
+ return cqt(
190
+ request.samples,
191
+ request.sampleRate,
192
+ request.hopLength,
193
+ request.fmin,
194
+ request.nBins,
195
+ request.binsPerOctave,
196
+ request,
197
+ );
198
+ }
93
199
  validateMusicSamples('cqt', samples, sampleRate, options);
94
200
  validatePositiveIntegers('cqt', { hopLength, nBins, binsPerOctave });
95
201
  validateFrequencyBounds('cqt', fmin);
@@ -107,8 +213,18 @@ export function cqt(
107
213
  * @param binsPerOctave - Bins per octave (default: 12)
108
214
  * @returns CQT magnitude result
109
215
  */
216
+ export function pseudoCqt(request: CqtRequest): CqtResult;
110
217
  export function pseudoCqt(
111
218
  samples: Float32Array,
219
+ sampleRate?: number,
220
+ hopLength?: number,
221
+ fmin?: number,
222
+ nBins?: number,
223
+ binsPerOctave?: number,
224
+ options?: GuardedOptions,
225
+ ): CqtResult;
226
+ export function pseudoCqt(
227
+ samples: Float32Array | CqtRequest,
112
228
  sampleRate = 22050,
113
229
  hopLength = 512,
114
230
  fmin = 32.70319566257483,
@@ -116,6 +232,18 @@ export function pseudoCqt(
116
232
  binsPerOctave = 12,
117
233
  options: GuardedOptions = {},
118
234
  ): CqtResult {
235
+ if (!(samples instanceof Float32Array)) {
236
+ const request = samples;
237
+ return pseudoCqt(
238
+ request.samples,
239
+ request.sampleRate,
240
+ request.hopLength,
241
+ request.fmin,
242
+ request.nBins,
243
+ request.binsPerOctave,
244
+ request,
245
+ );
246
+ }
119
247
  validateMusicSamples('pseudoCqt', samples, sampleRate, options);
120
248
  validatePositiveIntegers('pseudoCqt', { hopLength, nBins, binsPerOctave });
121
249
  validateFrequencyBounds('pseudoCqt', fmin);
@@ -133,8 +261,18 @@ export function pseudoCqt(
133
261
  * @param binsPerOctave - Bins per octave (default: 12)
134
262
  * @returns CQT magnitude result
135
263
  */
264
+ export function hybridCqt(request: CqtRequest): CqtResult;
136
265
  export function hybridCqt(
137
266
  samples: Float32Array,
267
+ sampleRate?: number,
268
+ hopLength?: number,
269
+ fmin?: number,
270
+ nBins?: number,
271
+ binsPerOctave?: number,
272
+ options?: GuardedOptions,
273
+ ): CqtResult;
274
+ export function hybridCqt(
275
+ samples: Float32Array | CqtRequest,
138
276
  sampleRate = 22050,
139
277
  hopLength = 512,
140
278
  fmin = 32.70319566257483,
@@ -142,6 +280,18 @@ export function hybridCqt(
142
280
  binsPerOctave = 12,
143
281
  options: GuardedOptions = {},
144
282
  ): CqtResult {
283
+ if (!(samples instanceof Float32Array)) {
284
+ const request = samples;
285
+ return hybridCqt(
286
+ request.samples,
287
+ request.sampleRate,
288
+ request.hopLength,
289
+ request.fmin,
290
+ request.nBins,
291
+ request.binsPerOctave,
292
+ request,
293
+ );
294
+ }
145
295
  validateMusicSamples('hybridCqt', samples, sampleRate, options);
146
296
  validatePositiveIntegers('hybridCqt', { hopLength, nBins, binsPerOctave });
147
297
  validateFrequencyBounds('hybridCqt', fmin);
@@ -160,8 +310,19 @@ export function hybridCqt(
160
310
  * @param gamma - Bandwidth offset; 0 is equivalent to CQT (default: 0)
161
311
  * @returns VQT magnitude result (same shape as CQT)
162
312
  */
313
+ export function vqt(request: VqtRequest): CqtResult;
163
314
  export function vqt(
164
315
  samples: Float32Array,
316
+ sampleRate?: number,
317
+ hopLength?: number,
318
+ fmin?: number,
319
+ nBins?: number,
320
+ binsPerOctave?: number,
321
+ gamma?: number,
322
+ options?: GuardedOptions,
323
+ ): CqtResult;
324
+ export function vqt(
325
+ samples: Float32Array | VqtRequest,
165
326
  sampleRate = 22050,
166
327
  hopLength = 512,
167
328
  fmin = 32.70319566257483,
@@ -170,6 +331,19 @@ export function vqt(
170
331
  gamma = 0,
171
332
  options: GuardedOptions = {},
172
333
  ): CqtResult {
334
+ if (!(samples instanceof Float32Array)) {
335
+ const request = samples;
336
+ return vqt(
337
+ request.samples,
338
+ request.sampleRate,
339
+ request.hopLength,
340
+ request.fmin,
341
+ request.nBins,
342
+ request.binsPerOctave,
343
+ request.gamma,
344
+ request,
345
+ );
346
+ }
173
347
  validateMusicSamples('vqt', samples, sampleRate, options);
174
348
  validatePositiveIntegers('vqt', { hopLength, nBins, binsPerOctave });
175
349
  validateFrequencyBounds('vqt', fmin);
@@ -208,10 +382,22 @@ function validateCqtInverse(
208
382
  }
209
383
 
210
384
  /** Reconstruct mono audio from row-major CQT magnitude via Griffin-Lim. */
385
+ export function cqtToAudio(request: CqtToAudioRequest): Float32Array;
211
386
  export function cqtToAudio(
212
387
  magnitude: Float32Array,
213
388
  nBins: number,
214
389
  nFrames: number,
390
+ sampleRate?: number,
391
+ hopLength?: number,
392
+ fmin?: number,
393
+ binsPerOctave?: number,
394
+ nIter?: number,
395
+ options?: GuardedOptions,
396
+ ): Float32Array;
397
+ export function cqtToAudio(
398
+ magnitude: Float32Array | CqtToAudioRequest,
399
+ nBins = 0,
400
+ nFrames = 0,
215
401
  sampleRate = 22050,
216
402
  hopLength = 512,
217
403
  fmin = 32.70319566257483,
@@ -219,6 +405,20 @@ export function cqtToAudio(
219
405
  nIter = 32,
220
406
  options: GuardedOptions = {},
221
407
  ): Float32Array {
408
+ if (!(magnitude instanceof Float32Array)) {
409
+ const request = magnitude;
410
+ return cqtToAudio(
411
+ request.magnitude,
412
+ request.nBins,
413
+ request.nFrames,
414
+ request.sampleRate,
415
+ request.hopLength,
416
+ request.fmin,
417
+ request.binsPerOctave,
418
+ request.nIter,
419
+ request,
420
+ );
421
+ }
222
422
  validateCqtInverse(
223
423
  'cqtToAudio',
224
424
  magnitude,
@@ -244,10 +444,23 @@ export function cqtToAudio(
244
444
  }
245
445
 
246
446
  /** Reconstruct mono audio from row-major VQT magnitude via Griffin-Lim. */
447
+ export function vqtToAudio(request: VqtToAudioRequest): Float32Array;
247
448
  export function vqtToAudio(
248
449
  magnitude: Float32Array,
249
450
  nBins: number,
250
451
  nFrames: number,
452
+ sampleRate?: number,
453
+ hopLength?: number,
454
+ fmin?: number,
455
+ binsPerOctave?: number,
456
+ gamma?: number,
457
+ nIter?: number,
458
+ options?: GuardedOptions,
459
+ ): Float32Array;
460
+ export function vqtToAudio(
461
+ magnitude: Float32Array | VqtToAudioRequest,
462
+ nBins = 0,
463
+ nFrames = 0,
251
464
  sampleRate = 22050,
252
465
  hopLength = 512,
253
466
  fmin = 32.70319566257483,
@@ -256,6 +469,21 @@ export function vqtToAudio(
256
469
  nIter = 32,
257
470
  options: GuardedOptions = {},
258
471
  ): Float32Array {
472
+ if (!(magnitude instanceof Float32Array)) {
473
+ const request = magnitude;
474
+ return vqtToAudio(
475
+ request.magnitude,
476
+ request.nBins,
477
+ request.nFrames,
478
+ request.sampleRate,
479
+ request.hopLength,
480
+ request.fmin,
481
+ request.binsPerOctave,
482
+ request.gamma,
483
+ request.nIter,
484
+ request,
485
+ );
486
+ }
259
487
  validateCqtInverse(
260
488
  'vqtToAudio',
261
489
  magnitude,
@@ -295,11 +523,21 @@ export function vqtToAudio(
295
523
  * @param minSectionSec - Minimum section duration in seconds (default: 4.0)
296
524
  * @returns Array of detected sections
297
525
  */
526
+ export function analyzeSections(request: AnalyzeSectionsRequest): Section[];
298
527
  export function analyzeSections(
299
528
  samples: Float32Array,
529
+ sampleRate?: number,
530
+ options?: AnalyzeSectionsGuardedOptions,
531
+ ): Section[];
532
+ export function analyzeSections(
533
+ samples: Float32Array | AnalyzeSectionsRequest,
300
534
  sampleRate = 22050,
301
535
  options: AnalyzeSectionsGuardedOptions = {},
302
536
  ): Section[] {
537
+ if (!(samples instanceof Float32Array)) {
538
+ const r = samples;
539
+ return analyzeSections(r.samples, r.sampleRate, r);
540
+ }
303
541
  validateMusicSamples('analyzeSections', samples, sampleRate, options);
304
542
  validatePositiveIntegers('analyzeSections', {
305
543
  nFft: options.nFft ?? 2048,
@@ -357,20 +595,35 @@ export interface MelodyOptions {
357
595
  * @param options - Tracker + tuning options ({@link MelodyOptions})
358
596
  * @returns Melody contour with per-frame pitch points and summary stats
359
597
  */
598
+ export function analyzeMelody(request: AnalyzeMelodyRequest): MelodyResult;
360
599
  export function analyzeMelody(
361
600
  samples: Float32Array,
601
+ sampleRate?: number,
602
+ options?: MelodyGuardedOptions,
603
+ ): MelodyResult;
604
+ export function analyzeMelody(
605
+ samples: Float32Array | AnalyzeMelodyRequest,
362
606
  sampleRate = 22050,
363
607
  options: MelodyGuardedOptions = {},
364
608
  ): MelodyResult {
609
+ if (!(samples instanceof Float32Array)) {
610
+ const r = samples;
611
+ return analyzeMelody(r.samples, r.sampleRate, r);
612
+ }
365
613
  validateMusicSamples('analyzeMelody', samples, sampleRate, options);
366
614
  const fmin = options.fmin ?? 65.0;
367
615
  const fmax = options.fmax ?? 2093.0;
368
616
  validateFrequencyBounds('analyzeMelody', fmin, fmax);
369
617
  // The melody tracker's fmin is a YIN pitch floor: 0 is meaningless, and the
370
- // flat C ABI (sonare_analyze_melody) rejects it. validateFrequencyBounds only
371
- // guards fmin >= 0, so enforce strict positivity here for parity.
618
+ // flat C ABI (sonare_analyze_melody) rejects it with InvalidParameter.
619
+ // validateFrequencyBounds only guards fmin >= 0, so enforce strict positivity
620
+ // here and report the same branded error the Node/Python surfaces raise.
372
621
  if (fmin <= 0) {
373
- throw new RangeError('analyzeMelody: fmin must be positive');
622
+ throw new SonareError(
623
+ ErrorCode.InvalidParameter,
624
+ 'InvalidParameter',
625
+ 'analyzeMelody: fmin must be positive',
626
+ );
374
627
  }
375
628
  validatePositiveIntegers('analyzeMelody', {
376
629
  frameLength: options.frameLength ?? 2048,
@@ -379,7 +632,11 @@ export function analyzeMelody(
379
632
  const threshold = options.threshold ?? 0.1;
380
633
  assertFiniteScalar('analyzeMelody', threshold, 'threshold');
381
634
  if (threshold <= 0) {
382
- throw new RangeError('analyzeMelody: threshold must be positive');
635
+ throw new SonareError(
636
+ ErrorCode.InvalidParameter,
637
+ 'InvalidParameter',
638
+ 'analyzeMelody: threshold must be positive',
639
+ );
383
640
  }
384
641
  return requireModule().analyzeMelody(
385
642
  samples,
@@ -404,14 +661,34 @@ export function analyzeMelody(
404
661
  * @param nMels - Number of Mel bands (default: 128)
405
662
  * @returns Onset envelope for each frame
406
663
  */
664
+ export function onsetEnvelope(request: OnsetEnvelopeRequest): Float32Array;
407
665
  export function onsetEnvelope(
408
666
  samples: Float32Array,
667
+ sampleRate?: number,
668
+ nFft?: number,
669
+ hopLength?: number,
670
+ nMels?: number,
671
+ options?: GuardedOptions,
672
+ ): Float32Array;
673
+ export function onsetEnvelope(
674
+ samples: Float32Array | OnsetEnvelopeRequest,
409
675
  sampleRate = 22050,
410
676
  nFft = 2048,
411
677
  hopLength = 512,
412
678
  nMels = 128,
413
679
  options: GuardedOptions = {},
414
680
  ): Float32Array {
681
+ if (!(samples instanceof Float32Array)) {
682
+ const request = samples;
683
+ return onsetEnvelope(
684
+ request.samples,
685
+ request.sampleRate,
686
+ request.nFft,
687
+ request.hopLength,
688
+ request.nMels,
689
+ request,
690
+ );
691
+ }
415
692
  validateMusicSamples('onsetEnvelope', samples, sampleRate, options);
416
693
  validatePositiveIntegers('onsetEnvelope', { nFft, hopLength, nMels });
417
694
  return requireModule().onsetEnvelope(samples, sampleRate, nFft, hopLength, nMels);
@@ -428,8 +705,18 @@ export function onsetEnvelope(
428
705
  * @param nBands - Number of onset bands (default: 3)
429
706
  * @returns Multi-band onset matrix
430
707
  */
708
+ export function onsetStrengthMulti(request: OnsetStrengthMultiRequest): OnsetStrengthMultiResult;
431
709
  export function onsetStrengthMulti(
432
710
  samples: Float32Array,
711
+ sampleRate?: number,
712
+ nFft?: number,
713
+ hopLength?: number,
714
+ nMels?: number,
715
+ nBands?: number,
716
+ options?: GuardedOptions,
717
+ ): OnsetStrengthMultiResult;
718
+ export function onsetStrengthMulti(
719
+ samples: Float32Array | OnsetStrengthMultiRequest,
433
720
  sampleRate = 22050,
434
721
  nFft = 2048,
435
722
  hopLength = 512,
@@ -437,6 +724,18 @@ export function onsetStrengthMulti(
437
724
  nBands = 3,
438
725
  options: GuardedOptions = {},
439
726
  ): OnsetStrengthMultiResult {
727
+ if (!(samples instanceof Float32Array)) {
728
+ const request = samples;
729
+ return onsetStrengthMulti(
730
+ request.samples,
731
+ request.sampleRate,
732
+ request.nFft,
733
+ request.hopLength,
734
+ request.nMels,
735
+ request.nBands,
736
+ request,
737
+ );
738
+ }
440
739
  validateMusicSamples('onsetStrengthMulti', samples, sampleRate, options);
441
740
  validatePositiveIntegers('onsetStrengthMulti', { nFft, hopLength, nMels, nBands });
442
741
  return requireModule().onsetStrengthMulti(samples, sampleRate, nFft, hopLength, nMels, nBands);
@@ -451,13 +750,31 @@ export function onsetStrengthMulti(
451
750
  * @param winLength - Window length in frames (default: 384)
452
751
  * @returns Fourier tempogram result
453
752
  */
753
+ export function fourierTempogram(request: FourierTempogramRequest): WasmFourierTempogramResult;
454
754
  export function fourierTempogram(
455
755
  onsetEnvelope: Float32Array,
756
+ sampleRate?: number,
757
+ hopLength?: number,
758
+ winLength?: number,
759
+ options?: GuardedOptions,
760
+ ): WasmFourierTempogramResult;
761
+ export function fourierTempogram(
762
+ onsetEnvelope: Float32Array | FourierTempogramRequest,
456
763
  sampleRate = 22050,
457
764
  hopLength = 512,
458
765
  winLength = 384,
459
766
  options: GuardedOptions = {},
460
767
  ): WasmFourierTempogramResult {
768
+ if (!(onsetEnvelope instanceof Float32Array)) {
769
+ const request = onsetEnvelope;
770
+ return fourierTempogram(
771
+ request.onsetEnvelope,
772
+ request.sampleRate,
773
+ request.hopLength,
774
+ request.winLength,
775
+ request,
776
+ );
777
+ }
461
778
  assertSampleRate('fourierTempogram', sampleRate);
462
779
  assertSamples('fourierTempogram', onsetEnvelope, options.validate !== false, 'onsetEnvelope');
463
780
  validatePositiveIntegers('fourierTempogram', { hopLength, winLength });
@@ -475,14 +792,34 @@ export function fourierTempogram(
475
792
  * default {0.5, 1, 2, 3, 4} is used.
476
793
  * @returns Tempogram ratio features (one value per factor)
477
794
  */
795
+ export function tempogramRatio(request: TempogramRatioRequest): Float32Array;
478
796
  export function tempogramRatio(
479
797
  tempogramData: Float32Array,
798
+ winLength?: number,
799
+ sampleRate?: number,
800
+ hopLength?: number,
801
+ factors?: Float32Array | number[],
802
+ options?: GuardedOptions,
803
+ ): Float32Array;
804
+ export function tempogramRatio(
805
+ tempogramData: Float32Array | TempogramRatioRequest,
480
806
  winLength = 384,
481
807
  sampleRate = 22050,
482
808
  hopLength = 512,
483
809
  factors?: Float32Array | number[],
484
810
  options: GuardedOptions = {},
485
811
  ): Float32Array {
812
+ if (!(tempogramData instanceof Float32Array)) {
813
+ const request = tempogramData;
814
+ return tempogramRatio(
815
+ request.tempogramData,
816
+ request.winLength,
817
+ request.sampleRate,
818
+ request.hopLength,
819
+ request.factors,
820
+ request,
821
+ );
822
+ }
486
823
  assertSampleRate('tempogramRatio', sampleRate);
487
824
  assertSamples('tempogramRatio', tempogramData, options.validate !== false, 'tempogramData');
488
825
  validatePositiveIntegers('tempogramRatio', { winLength, hopLength });
@@ -498,11 +835,21 @@ export function tempogramRatio(
498
835
  * dependent and a wrong rate yields wrong loudness.
499
836
  * @returns Loudness measurement result
500
837
  */
838
+ export function lufs(request: LufsRequest): LufsResult;
501
839
  export function lufs(
502
840
  samples: Float32Array,
841
+ sampleRate?: number,
842
+ options?: ValidateOptions,
843
+ ): LufsResult;
844
+ export function lufs(
845
+ samples: Float32Array | LufsRequest,
503
846
  sampleRate = 22050,
504
847
  options: ValidateOptions = {},
505
848
  ): LufsResult {
849
+ if (!(samples instanceof Float32Array)) {
850
+ const r = samples;
851
+ return lufs(r.samples, r.sampleRate, r);
852
+ }
506
853
  assertSampleRate('lufs', sampleRate);
507
854
  assertSamples('lufs', samples, options.validate !== false);
508
855
  return requireModule().lufs(samples, sampleRate);
@@ -516,11 +863,21 @@ export function lufs(
516
863
  * K-weighting is sample-rate dependent; pass the buffer's actual rate.
517
864
  * @returns Momentary LUFS values over time
518
865
  */
866
+ export function momentaryLufs(request: LufsRequest): Float32Array;
519
867
  export function momentaryLufs(
520
868
  samples: Float32Array,
869
+ sampleRate?: number,
870
+ options?: ValidateOptions,
871
+ ): Float32Array;
872
+ export function momentaryLufs(
873
+ samples: Float32Array | LufsRequest,
521
874
  sampleRate = 22050,
522
875
  options: ValidateOptions = {},
523
876
  ): Float32Array {
877
+ if (!(samples instanceof Float32Array)) {
878
+ const r = samples;
879
+ return momentaryLufs(r.samples, r.sampleRate, r);
880
+ }
524
881
  assertSampleRate('momentaryLufs', sampleRate);
525
882
  assertSamples('momentaryLufs', samples, options.validate !== false);
526
883
  return requireModule().momentaryLufs(samples, sampleRate);
@@ -534,11 +891,21 @@ export function momentaryLufs(
534
891
  * K-weighting is sample-rate dependent; pass the buffer's actual rate.
535
892
  * @returns Short-term LUFS values over time
536
893
  */
894
+ export function shortTermLufs(request: LufsRequest): Float32Array;
537
895
  export function shortTermLufs(
538
896
  samples: Float32Array,
897
+ sampleRate?: number,
898
+ options?: ValidateOptions,
899
+ ): Float32Array;
900
+ export function shortTermLufs(
901
+ samples: Float32Array | LufsRequest,
539
902
  sampleRate = 22050,
540
903
  options: ValidateOptions = {},
541
904
  ): Float32Array {
905
+ if (!(samples instanceof Float32Array)) {
906
+ const r = samples;
907
+ return shortTermLufs(r.samples, r.sampleRate, r);
908
+ }
542
909
  assertSampleRate('shortTermLufs', sampleRate);
543
910
  assertSamples('shortTermLufs', samples, options.validate !== false);
544
911
  return requireModule().shortTermLufs(samples, sampleRate);
@@ -22,8 +22,30 @@ function requireModule() {
22
22
  * @param fillNa - If true, return 0 for unvoiced f0 frames; otherwise keep NaN (default: false)
23
23
  * @returns Pitch detection result
24
24
  */
25
+ export interface PitchYinRequest {
26
+ samples: Float32Array;
27
+ sampleRate?: number;
28
+ frameLength?: number;
29
+ hopLength?: number;
30
+ fmin?: number;
31
+ fmax?: number;
32
+ threshold?: number;
33
+ fillNa?: boolean;
34
+ }
35
+
36
+ export function pitchYin(request: PitchYinRequest): PitchResult;
25
37
  export function pitchYin(
26
38
  samples: Float32Array,
39
+ sampleRate?: number,
40
+ frameLength?: number,
41
+ hopLength?: number,
42
+ fmin?: number,
43
+ fmax?: number,
44
+ threshold?: number,
45
+ fillNa?: boolean,
46
+ ): PitchResult;
47
+ export function pitchYin(
48
+ samples: Float32Array | PitchYinRequest,
27
49
  sampleRate = 22050,
28
50
  frameLength = 2048,
29
51
  hopLength = 512,
@@ -32,6 +54,19 @@ export function pitchYin(
32
54
  threshold = 0.3,
33
55
  fillNa = false,
34
56
  ): PitchResult {
57
+ if (!(samples instanceof Float32Array)) {
58
+ const request = samples;
59
+ return pitchYin(
60
+ request.samples,
61
+ request.sampleRate,
62
+ request.frameLength,
63
+ request.hopLength,
64
+ request.fmin,
65
+ request.fmax,
66
+ request.threshold,
67
+ request.fillNa,
68
+ );
69
+ }
35
70
  return requireModule().pitchYin(
36
71
  samples,
37
72
  sampleRate,
@@ -57,8 +92,21 @@ export function pitchYin(
57
92
  * @param fillNa - If true, return 0 for unvoiced f0 frames; otherwise keep NaN (default: false)
58
93
  * @returns Pitch detection result
59
94
  */
95
+ export interface PitchPyinRequest extends PitchYinRequest {}
96
+
97
+ export function pitchPyin(request: PitchPyinRequest): PitchResult;
60
98
  export function pitchPyin(
61
99
  samples: Float32Array,
100
+ sampleRate?: number,
101
+ frameLength?: number,
102
+ hopLength?: number,
103
+ fmin?: number,
104
+ fmax?: number,
105
+ threshold?: number,
106
+ fillNa?: boolean,
107
+ ): PitchResult;
108
+ export function pitchPyin(
109
+ samples: Float32Array | PitchPyinRequest,
62
110
  sampleRate = 22050,
63
111
  frameLength = 2048,
64
112
  hopLength = 512,
@@ -67,6 +115,19 @@ export function pitchPyin(
67
115
  threshold = 0.3,
68
116
  fillNa = false,
69
117
  ): PitchResult {
118
+ if (!(samples instanceof Float32Array)) {
119
+ const request = samples;
120
+ return pitchPyin(
121
+ request.samples,
122
+ request.sampleRate,
123
+ request.frameLength,
124
+ request.hopLength,
125
+ request.fmin,
126
+ request.fmax,
127
+ request.threshold,
128
+ request.fillNa,
129
+ );
130
+ }
70
131
  return requireModule().pitchPyin(
71
132
  samples,
72
133
  sampleRate,