@libraz/libsonare 1.5.2 → 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.
- package/README.md +18 -3
- package/dist/index.d.ts +1147 -181
- package/dist/index.js +4826 -3941
- package/dist/index.js.map +1 -1
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worklet.d.ts +29 -1
- package/dist/worklet.js +1067 -973
- package/dist/worklet.js.map +1 -1
- package/package.json +2 -1
- package/src/_chain_config.ts +46 -0
- package/src/audio.ts +24 -4
- package/src/effects_mastering.ts +25 -1
- package/src/effects_transform.ts +283 -43
- package/src/effects_voice_change.ts +46 -53
- package/src/feature_core.ts +316 -12
- package/src/feature_music.ts +357 -0
- package/src/feature_pitch.ts +61 -0
- package/src/feature_resample.ts +17 -2
- package/src/feature_spectral.ts +349 -2
- package/src/feature_spectrogram.ts +336 -0
- package/src/index.ts +130 -1
- package/src/mastering_chain.ts +305 -50
- package/src/mastering_core.ts +232 -16
- package/src/mastering_dynamics.ts +66 -10
- package/src/mastering_repair.ts +119 -7
- package/src/metering.ts +366 -81
- package/src/mixer.ts +9 -2
- package/src/mixing_oneshot.ts +25 -5
- package/src/module_state.ts +1 -1
- package/src/project_class.ts +17 -6
- package/src/project_internal.ts +10 -2
- package/src/project_types.ts +25 -2
- package/src/public_types_mastering.ts +114 -4
- package/src/public_types_spectral.ts +7 -0
- package/src/quick_analysis.ts +325 -117
- package/src/realtime_engine.ts +8 -0
- package/src/sonare.js.d.ts +31 -0
- package/src/stream_analyzer.ts +20 -1
- package/src/stream_types.ts +12 -1
- package/src/validation.ts +17 -2
- package/src/worklet/engine-clips.ts +67 -2
- package/src/worklet/engine-processor.ts +33 -5
- package/src/worklet/engine.ts +7 -3
- package/src/worklet/guards.ts +3 -0
- package/src/worklet/messages.ts +27 -0
package/src/feature_music.ts
CHANGED
|
@@ -25,6 +25,80 @@ type GuardedOptions = ValidateOptions;
|
|
|
25
25
|
type AnalyzeSectionsGuardedOptions = AnalyzeSectionsOptions & ValidateOptions;
|
|
26
26
|
type MelodyGuardedOptions = MelodyOptions & ValidateOptions;
|
|
27
27
|
|
|
28
|
+
/** Canonical request form shared by the Constant-Q transform variants. */
|
|
29
|
+
export interface CqtRequest extends GuardedOptions {
|
|
30
|
+
samples: Float32Array;
|
|
31
|
+
sampleRate?: number;
|
|
32
|
+
hopLength?: number;
|
|
33
|
+
fmin?: number;
|
|
34
|
+
nBins?: number;
|
|
35
|
+
binsPerOctave?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Canonical request form for {@link vqt}. */
|
|
39
|
+
export interface VqtRequest extends CqtRequest {
|
|
40
|
+
gamma?: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface OnsetEnvelopeRequest extends GuardedOptions {
|
|
44
|
+
samples: Float32Array;
|
|
45
|
+
sampleRate?: number;
|
|
46
|
+
nFft?: number;
|
|
47
|
+
hopLength?: number;
|
|
48
|
+
nMels?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface OnsetStrengthMultiRequest extends OnsetEnvelopeRequest {
|
|
52
|
+
nBands?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FourierTempogramRequest extends GuardedOptions {
|
|
56
|
+
onsetEnvelope: Float32Array;
|
|
57
|
+
sampleRate?: number;
|
|
58
|
+
hopLength?: number;
|
|
59
|
+
winLength?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface TempogramRatioRequest extends GuardedOptions {
|
|
63
|
+
tempogramData: Float32Array;
|
|
64
|
+
winLength?: number;
|
|
65
|
+
sampleRate?: number;
|
|
66
|
+
hopLength?: number;
|
|
67
|
+
factors?: Float32Array | number[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface CqtToAudioRequest extends GuardedOptions {
|
|
71
|
+
magnitude: Float32Array;
|
|
72
|
+
nBins: number;
|
|
73
|
+
nFrames: number;
|
|
74
|
+
sampleRate?: number;
|
|
75
|
+
hopLength?: number;
|
|
76
|
+
fmin?: number;
|
|
77
|
+
binsPerOctave?: number;
|
|
78
|
+
nIter?: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface VqtToAudioRequest extends CqtToAudioRequest {
|
|
82
|
+
gamma?: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface AnalyzeSectionsRequest extends AnalyzeSectionsGuardedOptions {
|
|
86
|
+
samples: Float32Array;
|
|
87
|
+
sampleRate?: number;
|
|
88
|
+
}
|
|
89
|
+
export interface AnalyzeMelodyRequest extends MelodyGuardedOptions {
|
|
90
|
+
samples: Float32Array;
|
|
91
|
+
sampleRate?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface LufsRequest extends ValidateOptions {
|
|
94
|
+
samples: Float32Array;
|
|
95
|
+
sampleRate?: number;
|
|
96
|
+
}
|
|
97
|
+
export interface NnlsChromaRequest extends GuardedOptions {
|
|
98
|
+
samples: Float32Array;
|
|
99
|
+
sampleRate?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
28
102
|
function validateMusicSamples(
|
|
29
103
|
fnName: string,
|
|
30
104
|
samples: Float32Array,
|
|
@@ -61,11 +135,20 @@ function validateFrequencyBounds(fnName: string, fmin: number, fmax?: number): v
|
|
|
61
135
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
62
136
|
* @returns NNLS chroma result
|
|
63
137
|
*/
|
|
138
|
+
export function nnlsChroma(request: NnlsChromaRequest): WasmNnlsChromaResult;
|
|
64
139
|
export function nnlsChroma(
|
|
65
140
|
samples: Float32Array,
|
|
141
|
+
sampleRate?: number,
|
|
142
|
+
options?: GuardedOptions,
|
|
143
|
+
): WasmNnlsChromaResult;
|
|
144
|
+
export function nnlsChroma(
|
|
145
|
+
samples: Float32Array | NnlsChromaRequest,
|
|
66
146
|
sampleRate = 22050,
|
|
67
147
|
options: GuardedOptions = {},
|
|
68
148
|
): WasmNnlsChromaResult {
|
|
149
|
+
if (!(samples instanceof Float32Array)) {
|
|
150
|
+
return nnlsChroma(samples.samples, samples.sampleRate, samples);
|
|
151
|
+
}
|
|
69
152
|
validateMusicSamples('nnlsChroma', samples, sampleRate, options);
|
|
70
153
|
return requireModule().nnlsChroma(samples, sampleRate);
|
|
71
154
|
}
|
|
@@ -81,8 +164,18 @@ export function nnlsChroma(
|
|
|
81
164
|
* @param binsPerOctave - Bins per octave (default: 12)
|
|
82
165
|
* @returns CQT magnitude result
|
|
83
166
|
*/
|
|
167
|
+
export function cqt(request: CqtRequest): CqtResult;
|
|
84
168
|
export function cqt(
|
|
85
169
|
samples: Float32Array,
|
|
170
|
+
sampleRate?: number,
|
|
171
|
+
hopLength?: number,
|
|
172
|
+
fmin?: number,
|
|
173
|
+
nBins?: number,
|
|
174
|
+
binsPerOctave?: number,
|
|
175
|
+
options?: GuardedOptions,
|
|
176
|
+
): CqtResult;
|
|
177
|
+
export function cqt(
|
|
178
|
+
samples: Float32Array | CqtRequest,
|
|
86
179
|
sampleRate = 22050,
|
|
87
180
|
hopLength = 512,
|
|
88
181
|
fmin = 32.70319566257483,
|
|
@@ -90,6 +183,18 @@ export function cqt(
|
|
|
90
183
|
binsPerOctave = 12,
|
|
91
184
|
options: GuardedOptions = {},
|
|
92
185
|
): CqtResult {
|
|
186
|
+
if (!(samples instanceof Float32Array)) {
|
|
187
|
+
const request = samples;
|
|
188
|
+
return cqt(
|
|
189
|
+
request.samples,
|
|
190
|
+
request.sampleRate,
|
|
191
|
+
request.hopLength,
|
|
192
|
+
request.fmin,
|
|
193
|
+
request.nBins,
|
|
194
|
+
request.binsPerOctave,
|
|
195
|
+
request,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
93
198
|
validateMusicSamples('cqt', samples, sampleRate, options);
|
|
94
199
|
validatePositiveIntegers('cqt', { hopLength, nBins, binsPerOctave });
|
|
95
200
|
validateFrequencyBounds('cqt', fmin);
|
|
@@ -107,8 +212,18 @@ export function cqt(
|
|
|
107
212
|
* @param binsPerOctave - Bins per octave (default: 12)
|
|
108
213
|
* @returns CQT magnitude result
|
|
109
214
|
*/
|
|
215
|
+
export function pseudoCqt(request: CqtRequest): CqtResult;
|
|
110
216
|
export function pseudoCqt(
|
|
111
217
|
samples: Float32Array,
|
|
218
|
+
sampleRate?: number,
|
|
219
|
+
hopLength?: number,
|
|
220
|
+
fmin?: number,
|
|
221
|
+
nBins?: number,
|
|
222
|
+
binsPerOctave?: number,
|
|
223
|
+
options?: GuardedOptions,
|
|
224
|
+
): CqtResult;
|
|
225
|
+
export function pseudoCqt(
|
|
226
|
+
samples: Float32Array | CqtRequest,
|
|
112
227
|
sampleRate = 22050,
|
|
113
228
|
hopLength = 512,
|
|
114
229
|
fmin = 32.70319566257483,
|
|
@@ -116,6 +231,18 @@ export function pseudoCqt(
|
|
|
116
231
|
binsPerOctave = 12,
|
|
117
232
|
options: GuardedOptions = {},
|
|
118
233
|
): CqtResult {
|
|
234
|
+
if (!(samples instanceof Float32Array)) {
|
|
235
|
+
const request = samples;
|
|
236
|
+
return pseudoCqt(
|
|
237
|
+
request.samples,
|
|
238
|
+
request.sampleRate,
|
|
239
|
+
request.hopLength,
|
|
240
|
+
request.fmin,
|
|
241
|
+
request.nBins,
|
|
242
|
+
request.binsPerOctave,
|
|
243
|
+
request,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
119
246
|
validateMusicSamples('pseudoCqt', samples, sampleRate, options);
|
|
120
247
|
validatePositiveIntegers('pseudoCqt', { hopLength, nBins, binsPerOctave });
|
|
121
248
|
validateFrequencyBounds('pseudoCqt', fmin);
|
|
@@ -133,8 +260,18 @@ export function pseudoCqt(
|
|
|
133
260
|
* @param binsPerOctave - Bins per octave (default: 12)
|
|
134
261
|
* @returns CQT magnitude result
|
|
135
262
|
*/
|
|
263
|
+
export function hybridCqt(request: CqtRequest): CqtResult;
|
|
136
264
|
export function hybridCqt(
|
|
137
265
|
samples: Float32Array,
|
|
266
|
+
sampleRate?: number,
|
|
267
|
+
hopLength?: number,
|
|
268
|
+
fmin?: number,
|
|
269
|
+
nBins?: number,
|
|
270
|
+
binsPerOctave?: number,
|
|
271
|
+
options?: GuardedOptions,
|
|
272
|
+
): CqtResult;
|
|
273
|
+
export function hybridCqt(
|
|
274
|
+
samples: Float32Array | CqtRequest,
|
|
138
275
|
sampleRate = 22050,
|
|
139
276
|
hopLength = 512,
|
|
140
277
|
fmin = 32.70319566257483,
|
|
@@ -142,6 +279,18 @@ export function hybridCqt(
|
|
|
142
279
|
binsPerOctave = 12,
|
|
143
280
|
options: GuardedOptions = {},
|
|
144
281
|
): CqtResult {
|
|
282
|
+
if (!(samples instanceof Float32Array)) {
|
|
283
|
+
const request = samples;
|
|
284
|
+
return hybridCqt(
|
|
285
|
+
request.samples,
|
|
286
|
+
request.sampleRate,
|
|
287
|
+
request.hopLength,
|
|
288
|
+
request.fmin,
|
|
289
|
+
request.nBins,
|
|
290
|
+
request.binsPerOctave,
|
|
291
|
+
request,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
145
294
|
validateMusicSamples('hybridCqt', samples, sampleRate, options);
|
|
146
295
|
validatePositiveIntegers('hybridCqt', { hopLength, nBins, binsPerOctave });
|
|
147
296
|
validateFrequencyBounds('hybridCqt', fmin);
|
|
@@ -160,8 +309,19 @@ export function hybridCqt(
|
|
|
160
309
|
* @param gamma - Bandwidth offset; 0 is equivalent to CQT (default: 0)
|
|
161
310
|
* @returns VQT magnitude result (same shape as CQT)
|
|
162
311
|
*/
|
|
312
|
+
export function vqt(request: VqtRequest): CqtResult;
|
|
163
313
|
export function vqt(
|
|
164
314
|
samples: Float32Array,
|
|
315
|
+
sampleRate?: number,
|
|
316
|
+
hopLength?: number,
|
|
317
|
+
fmin?: number,
|
|
318
|
+
nBins?: number,
|
|
319
|
+
binsPerOctave?: number,
|
|
320
|
+
gamma?: number,
|
|
321
|
+
options?: GuardedOptions,
|
|
322
|
+
): CqtResult;
|
|
323
|
+
export function vqt(
|
|
324
|
+
samples: Float32Array | VqtRequest,
|
|
165
325
|
sampleRate = 22050,
|
|
166
326
|
hopLength = 512,
|
|
167
327
|
fmin = 32.70319566257483,
|
|
@@ -170,6 +330,19 @@ export function vqt(
|
|
|
170
330
|
gamma = 0,
|
|
171
331
|
options: GuardedOptions = {},
|
|
172
332
|
): CqtResult {
|
|
333
|
+
if (!(samples instanceof Float32Array)) {
|
|
334
|
+
const request = samples;
|
|
335
|
+
return vqt(
|
|
336
|
+
request.samples,
|
|
337
|
+
request.sampleRate,
|
|
338
|
+
request.hopLength,
|
|
339
|
+
request.fmin,
|
|
340
|
+
request.nBins,
|
|
341
|
+
request.binsPerOctave,
|
|
342
|
+
request.gamma,
|
|
343
|
+
request,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
173
346
|
validateMusicSamples('vqt', samples, sampleRate, options);
|
|
174
347
|
validatePositiveIntegers('vqt', { hopLength, nBins, binsPerOctave });
|
|
175
348
|
validateFrequencyBounds('vqt', fmin);
|
|
@@ -208,10 +381,22 @@ function validateCqtInverse(
|
|
|
208
381
|
}
|
|
209
382
|
|
|
210
383
|
/** Reconstruct mono audio from row-major CQT magnitude via Griffin-Lim. */
|
|
384
|
+
export function cqtToAudio(request: CqtToAudioRequest): Float32Array;
|
|
211
385
|
export function cqtToAudio(
|
|
212
386
|
magnitude: Float32Array,
|
|
213
387
|
nBins: number,
|
|
214
388
|
nFrames: number,
|
|
389
|
+
sampleRate?: number,
|
|
390
|
+
hopLength?: number,
|
|
391
|
+
fmin?: number,
|
|
392
|
+
binsPerOctave?: number,
|
|
393
|
+
nIter?: number,
|
|
394
|
+
options?: GuardedOptions,
|
|
395
|
+
): Float32Array;
|
|
396
|
+
export function cqtToAudio(
|
|
397
|
+
magnitude: Float32Array | CqtToAudioRequest,
|
|
398
|
+
nBins = 0,
|
|
399
|
+
nFrames = 0,
|
|
215
400
|
sampleRate = 22050,
|
|
216
401
|
hopLength = 512,
|
|
217
402
|
fmin = 32.70319566257483,
|
|
@@ -219,6 +404,20 @@ export function cqtToAudio(
|
|
|
219
404
|
nIter = 32,
|
|
220
405
|
options: GuardedOptions = {},
|
|
221
406
|
): Float32Array {
|
|
407
|
+
if (!(magnitude instanceof Float32Array)) {
|
|
408
|
+
const request = magnitude;
|
|
409
|
+
return cqtToAudio(
|
|
410
|
+
request.magnitude,
|
|
411
|
+
request.nBins,
|
|
412
|
+
request.nFrames,
|
|
413
|
+
request.sampleRate,
|
|
414
|
+
request.hopLength,
|
|
415
|
+
request.fmin,
|
|
416
|
+
request.binsPerOctave,
|
|
417
|
+
request.nIter,
|
|
418
|
+
request,
|
|
419
|
+
);
|
|
420
|
+
}
|
|
222
421
|
validateCqtInverse(
|
|
223
422
|
'cqtToAudio',
|
|
224
423
|
magnitude,
|
|
@@ -244,10 +443,23 @@ export function cqtToAudio(
|
|
|
244
443
|
}
|
|
245
444
|
|
|
246
445
|
/** Reconstruct mono audio from row-major VQT magnitude via Griffin-Lim. */
|
|
446
|
+
export function vqtToAudio(request: VqtToAudioRequest): Float32Array;
|
|
247
447
|
export function vqtToAudio(
|
|
248
448
|
magnitude: Float32Array,
|
|
249
449
|
nBins: number,
|
|
250
450
|
nFrames: number,
|
|
451
|
+
sampleRate?: number,
|
|
452
|
+
hopLength?: number,
|
|
453
|
+
fmin?: number,
|
|
454
|
+
binsPerOctave?: number,
|
|
455
|
+
gamma?: number,
|
|
456
|
+
nIter?: number,
|
|
457
|
+
options?: GuardedOptions,
|
|
458
|
+
): Float32Array;
|
|
459
|
+
export function vqtToAudio(
|
|
460
|
+
magnitude: Float32Array | VqtToAudioRequest,
|
|
461
|
+
nBins = 0,
|
|
462
|
+
nFrames = 0,
|
|
251
463
|
sampleRate = 22050,
|
|
252
464
|
hopLength = 512,
|
|
253
465
|
fmin = 32.70319566257483,
|
|
@@ -256,6 +468,21 @@ export function vqtToAudio(
|
|
|
256
468
|
nIter = 32,
|
|
257
469
|
options: GuardedOptions = {},
|
|
258
470
|
): Float32Array {
|
|
471
|
+
if (!(magnitude instanceof Float32Array)) {
|
|
472
|
+
const request = magnitude;
|
|
473
|
+
return vqtToAudio(
|
|
474
|
+
request.magnitude,
|
|
475
|
+
request.nBins,
|
|
476
|
+
request.nFrames,
|
|
477
|
+
request.sampleRate,
|
|
478
|
+
request.hopLength,
|
|
479
|
+
request.fmin,
|
|
480
|
+
request.binsPerOctave,
|
|
481
|
+
request.gamma,
|
|
482
|
+
request.nIter,
|
|
483
|
+
request,
|
|
484
|
+
);
|
|
485
|
+
}
|
|
259
486
|
validateCqtInverse(
|
|
260
487
|
'vqtToAudio',
|
|
261
488
|
magnitude,
|
|
@@ -295,11 +522,21 @@ export function vqtToAudio(
|
|
|
295
522
|
* @param minSectionSec - Minimum section duration in seconds (default: 4.0)
|
|
296
523
|
* @returns Array of detected sections
|
|
297
524
|
*/
|
|
525
|
+
export function analyzeSections(request: AnalyzeSectionsRequest): Section[];
|
|
298
526
|
export function analyzeSections(
|
|
299
527
|
samples: Float32Array,
|
|
528
|
+
sampleRate?: number,
|
|
529
|
+
options?: AnalyzeSectionsGuardedOptions,
|
|
530
|
+
): Section[];
|
|
531
|
+
export function analyzeSections(
|
|
532
|
+
samples: Float32Array | AnalyzeSectionsRequest,
|
|
300
533
|
sampleRate = 22050,
|
|
301
534
|
options: AnalyzeSectionsGuardedOptions = {},
|
|
302
535
|
): Section[] {
|
|
536
|
+
if (!(samples instanceof Float32Array)) {
|
|
537
|
+
const r = samples;
|
|
538
|
+
return analyzeSections(r.samples, r.sampleRate, r);
|
|
539
|
+
}
|
|
303
540
|
validateMusicSamples('analyzeSections', samples, sampleRate, options);
|
|
304
541
|
validatePositiveIntegers('analyzeSections', {
|
|
305
542
|
nFft: options.nFft ?? 2048,
|
|
@@ -357,11 +594,21 @@ export interface MelodyOptions {
|
|
|
357
594
|
* @param options - Tracker + tuning options ({@link MelodyOptions})
|
|
358
595
|
* @returns Melody contour with per-frame pitch points and summary stats
|
|
359
596
|
*/
|
|
597
|
+
export function analyzeMelody(request: AnalyzeMelodyRequest): MelodyResult;
|
|
360
598
|
export function analyzeMelody(
|
|
361
599
|
samples: Float32Array,
|
|
600
|
+
sampleRate?: number,
|
|
601
|
+
options?: MelodyGuardedOptions,
|
|
602
|
+
): MelodyResult;
|
|
603
|
+
export function analyzeMelody(
|
|
604
|
+
samples: Float32Array | AnalyzeMelodyRequest,
|
|
362
605
|
sampleRate = 22050,
|
|
363
606
|
options: MelodyGuardedOptions = {},
|
|
364
607
|
): MelodyResult {
|
|
608
|
+
if (!(samples instanceof Float32Array)) {
|
|
609
|
+
const r = samples;
|
|
610
|
+
return analyzeMelody(r.samples, r.sampleRate, r);
|
|
611
|
+
}
|
|
365
612
|
validateMusicSamples('analyzeMelody', samples, sampleRate, options);
|
|
366
613
|
const fmin = options.fmin ?? 65.0;
|
|
367
614
|
const fmax = options.fmax ?? 2093.0;
|
|
@@ -404,14 +651,34 @@ export function analyzeMelody(
|
|
|
404
651
|
* @param nMels - Number of Mel bands (default: 128)
|
|
405
652
|
* @returns Onset envelope for each frame
|
|
406
653
|
*/
|
|
654
|
+
export function onsetEnvelope(request: OnsetEnvelopeRequest): Float32Array;
|
|
407
655
|
export function onsetEnvelope(
|
|
408
656
|
samples: Float32Array,
|
|
657
|
+
sampleRate?: number,
|
|
658
|
+
nFft?: number,
|
|
659
|
+
hopLength?: number,
|
|
660
|
+
nMels?: number,
|
|
661
|
+
options?: GuardedOptions,
|
|
662
|
+
): Float32Array;
|
|
663
|
+
export function onsetEnvelope(
|
|
664
|
+
samples: Float32Array | OnsetEnvelopeRequest,
|
|
409
665
|
sampleRate = 22050,
|
|
410
666
|
nFft = 2048,
|
|
411
667
|
hopLength = 512,
|
|
412
668
|
nMels = 128,
|
|
413
669
|
options: GuardedOptions = {},
|
|
414
670
|
): Float32Array {
|
|
671
|
+
if (!(samples instanceof Float32Array)) {
|
|
672
|
+
const request = samples;
|
|
673
|
+
return onsetEnvelope(
|
|
674
|
+
request.samples,
|
|
675
|
+
request.sampleRate,
|
|
676
|
+
request.nFft,
|
|
677
|
+
request.hopLength,
|
|
678
|
+
request.nMels,
|
|
679
|
+
request,
|
|
680
|
+
);
|
|
681
|
+
}
|
|
415
682
|
validateMusicSamples('onsetEnvelope', samples, sampleRate, options);
|
|
416
683
|
validatePositiveIntegers('onsetEnvelope', { nFft, hopLength, nMels });
|
|
417
684
|
return requireModule().onsetEnvelope(samples, sampleRate, nFft, hopLength, nMels);
|
|
@@ -428,8 +695,18 @@ export function onsetEnvelope(
|
|
|
428
695
|
* @param nBands - Number of onset bands (default: 3)
|
|
429
696
|
* @returns Multi-band onset matrix
|
|
430
697
|
*/
|
|
698
|
+
export function onsetStrengthMulti(request: OnsetStrengthMultiRequest): OnsetStrengthMultiResult;
|
|
431
699
|
export function onsetStrengthMulti(
|
|
432
700
|
samples: Float32Array,
|
|
701
|
+
sampleRate?: number,
|
|
702
|
+
nFft?: number,
|
|
703
|
+
hopLength?: number,
|
|
704
|
+
nMels?: number,
|
|
705
|
+
nBands?: number,
|
|
706
|
+
options?: GuardedOptions,
|
|
707
|
+
): OnsetStrengthMultiResult;
|
|
708
|
+
export function onsetStrengthMulti(
|
|
709
|
+
samples: Float32Array | OnsetStrengthMultiRequest,
|
|
433
710
|
sampleRate = 22050,
|
|
434
711
|
nFft = 2048,
|
|
435
712
|
hopLength = 512,
|
|
@@ -437,6 +714,18 @@ export function onsetStrengthMulti(
|
|
|
437
714
|
nBands = 3,
|
|
438
715
|
options: GuardedOptions = {},
|
|
439
716
|
): OnsetStrengthMultiResult {
|
|
717
|
+
if (!(samples instanceof Float32Array)) {
|
|
718
|
+
const request = samples;
|
|
719
|
+
return onsetStrengthMulti(
|
|
720
|
+
request.samples,
|
|
721
|
+
request.sampleRate,
|
|
722
|
+
request.nFft,
|
|
723
|
+
request.hopLength,
|
|
724
|
+
request.nMels,
|
|
725
|
+
request.nBands,
|
|
726
|
+
request,
|
|
727
|
+
);
|
|
728
|
+
}
|
|
440
729
|
validateMusicSamples('onsetStrengthMulti', samples, sampleRate, options);
|
|
441
730
|
validatePositiveIntegers('onsetStrengthMulti', { nFft, hopLength, nMels, nBands });
|
|
442
731
|
return requireModule().onsetStrengthMulti(samples, sampleRate, nFft, hopLength, nMels, nBands);
|
|
@@ -451,13 +740,31 @@ export function onsetStrengthMulti(
|
|
|
451
740
|
* @param winLength - Window length in frames (default: 384)
|
|
452
741
|
* @returns Fourier tempogram result
|
|
453
742
|
*/
|
|
743
|
+
export function fourierTempogram(request: FourierTempogramRequest): WasmFourierTempogramResult;
|
|
454
744
|
export function fourierTempogram(
|
|
455
745
|
onsetEnvelope: Float32Array,
|
|
746
|
+
sampleRate?: number,
|
|
747
|
+
hopLength?: number,
|
|
748
|
+
winLength?: number,
|
|
749
|
+
options?: GuardedOptions,
|
|
750
|
+
): WasmFourierTempogramResult;
|
|
751
|
+
export function fourierTempogram(
|
|
752
|
+
onsetEnvelope: Float32Array | FourierTempogramRequest,
|
|
456
753
|
sampleRate = 22050,
|
|
457
754
|
hopLength = 512,
|
|
458
755
|
winLength = 384,
|
|
459
756
|
options: GuardedOptions = {},
|
|
460
757
|
): WasmFourierTempogramResult {
|
|
758
|
+
if (!(onsetEnvelope instanceof Float32Array)) {
|
|
759
|
+
const request = onsetEnvelope;
|
|
760
|
+
return fourierTempogram(
|
|
761
|
+
request.onsetEnvelope,
|
|
762
|
+
request.sampleRate,
|
|
763
|
+
request.hopLength,
|
|
764
|
+
request.winLength,
|
|
765
|
+
request,
|
|
766
|
+
);
|
|
767
|
+
}
|
|
461
768
|
assertSampleRate('fourierTempogram', sampleRate);
|
|
462
769
|
assertSamples('fourierTempogram', onsetEnvelope, options.validate !== false, 'onsetEnvelope');
|
|
463
770
|
validatePositiveIntegers('fourierTempogram', { hopLength, winLength });
|
|
@@ -475,14 +782,34 @@ export function fourierTempogram(
|
|
|
475
782
|
* default {0.5, 1, 2, 3, 4} is used.
|
|
476
783
|
* @returns Tempogram ratio features (one value per factor)
|
|
477
784
|
*/
|
|
785
|
+
export function tempogramRatio(request: TempogramRatioRequest): Float32Array;
|
|
478
786
|
export function tempogramRatio(
|
|
479
787
|
tempogramData: Float32Array,
|
|
788
|
+
winLength?: number,
|
|
789
|
+
sampleRate?: number,
|
|
790
|
+
hopLength?: number,
|
|
791
|
+
factors?: Float32Array | number[],
|
|
792
|
+
options?: GuardedOptions,
|
|
793
|
+
): Float32Array;
|
|
794
|
+
export function tempogramRatio(
|
|
795
|
+
tempogramData: Float32Array | TempogramRatioRequest,
|
|
480
796
|
winLength = 384,
|
|
481
797
|
sampleRate = 22050,
|
|
482
798
|
hopLength = 512,
|
|
483
799
|
factors?: Float32Array | number[],
|
|
484
800
|
options: GuardedOptions = {},
|
|
485
801
|
): Float32Array {
|
|
802
|
+
if (!(tempogramData instanceof Float32Array)) {
|
|
803
|
+
const request = tempogramData;
|
|
804
|
+
return tempogramRatio(
|
|
805
|
+
request.tempogramData,
|
|
806
|
+
request.winLength,
|
|
807
|
+
request.sampleRate,
|
|
808
|
+
request.hopLength,
|
|
809
|
+
request.factors,
|
|
810
|
+
request,
|
|
811
|
+
);
|
|
812
|
+
}
|
|
486
813
|
assertSampleRate('tempogramRatio', sampleRate);
|
|
487
814
|
assertSamples('tempogramRatio', tempogramData, options.validate !== false, 'tempogramData');
|
|
488
815
|
validatePositiveIntegers('tempogramRatio', { winLength, hopLength });
|
|
@@ -498,11 +825,21 @@ export function tempogramRatio(
|
|
|
498
825
|
* dependent and a wrong rate yields wrong loudness.
|
|
499
826
|
* @returns Loudness measurement result
|
|
500
827
|
*/
|
|
828
|
+
export function lufs(request: LufsRequest): LufsResult;
|
|
501
829
|
export function lufs(
|
|
502
830
|
samples: Float32Array,
|
|
831
|
+
sampleRate?: number,
|
|
832
|
+
options?: ValidateOptions,
|
|
833
|
+
): LufsResult;
|
|
834
|
+
export function lufs(
|
|
835
|
+
samples: Float32Array | LufsRequest,
|
|
503
836
|
sampleRate = 22050,
|
|
504
837
|
options: ValidateOptions = {},
|
|
505
838
|
): LufsResult {
|
|
839
|
+
if (!(samples instanceof Float32Array)) {
|
|
840
|
+
const r = samples;
|
|
841
|
+
return lufs(r.samples, r.sampleRate, r);
|
|
842
|
+
}
|
|
506
843
|
assertSampleRate('lufs', sampleRate);
|
|
507
844
|
assertSamples('lufs', samples, options.validate !== false);
|
|
508
845
|
return requireModule().lufs(samples, sampleRate);
|
|
@@ -516,11 +853,21 @@ export function lufs(
|
|
|
516
853
|
* K-weighting is sample-rate dependent; pass the buffer's actual rate.
|
|
517
854
|
* @returns Momentary LUFS values over time
|
|
518
855
|
*/
|
|
856
|
+
export function momentaryLufs(request: LufsRequest): Float32Array;
|
|
519
857
|
export function momentaryLufs(
|
|
520
858
|
samples: Float32Array,
|
|
859
|
+
sampleRate?: number,
|
|
860
|
+
options?: ValidateOptions,
|
|
861
|
+
): Float32Array;
|
|
862
|
+
export function momentaryLufs(
|
|
863
|
+
samples: Float32Array | LufsRequest,
|
|
521
864
|
sampleRate = 22050,
|
|
522
865
|
options: ValidateOptions = {},
|
|
523
866
|
): Float32Array {
|
|
867
|
+
if (!(samples instanceof Float32Array)) {
|
|
868
|
+
const r = samples;
|
|
869
|
+
return momentaryLufs(r.samples, r.sampleRate, r);
|
|
870
|
+
}
|
|
524
871
|
assertSampleRate('momentaryLufs', sampleRate);
|
|
525
872
|
assertSamples('momentaryLufs', samples, options.validate !== false);
|
|
526
873
|
return requireModule().momentaryLufs(samples, sampleRate);
|
|
@@ -534,11 +881,21 @@ export function momentaryLufs(
|
|
|
534
881
|
* K-weighting is sample-rate dependent; pass the buffer's actual rate.
|
|
535
882
|
* @returns Short-term LUFS values over time
|
|
536
883
|
*/
|
|
884
|
+
export function shortTermLufs(request: LufsRequest): Float32Array;
|
|
537
885
|
export function shortTermLufs(
|
|
538
886
|
samples: Float32Array,
|
|
887
|
+
sampleRate?: number,
|
|
888
|
+
options?: ValidateOptions,
|
|
889
|
+
): Float32Array;
|
|
890
|
+
export function shortTermLufs(
|
|
891
|
+
samples: Float32Array | LufsRequest,
|
|
539
892
|
sampleRate = 22050,
|
|
540
893
|
options: ValidateOptions = {},
|
|
541
894
|
): Float32Array {
|
|
895
|
+
if (!(samples instanceof Float32Array)) {
|
|
896
|
+
const r = samples;
|
|
897
|
+
return shortTermLufs(r.samples, r.sampleRate, r);
|
|
898
|
+
}
|
|
542
899
|
assertSampleRate('shortTermLufs', sampleRate);
|
|
543
900
|
assertSamples('shortTermLufs', samples, options.validate !== false);
|
|
544
901
|
return requireModule().shortTermLufs(samples, sampleRate);
|
package/src/feature_pitch.ts
CHANGED
|
@@ -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,
|
package/src/feature_resample.ts
CHANGED
|
@@ -16,6 +16,21 @@ function requireModule() {
|
|
|
16
16
|
* @param targetSr - Target sample rate in Hz
|
|
17
17
|
* @returns Resampled audio
|
|
18
18
|
*/
|
|
19
|
-
export
|
|
20
|
-
|
|
19
|
+
export interface ResampleRequest {
|
|
20
|
+
samples: Float32Array;
|
|
21
|
+
srcSr: number;
|
|
22
|
+
targetSr: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resample(request: ResampleRequest): Float32Array;
|
|
26
|
+
export function resample(samples: Float32Array, srcSr: number, targetSr: number): Float32Array;
|
|
27
|
+
export function resample(
|
|
28
|
+
samples: Float32Array | ResampleRequest,
|
|
29
|
+
srcSr?: number,
|
|
30
|
+
targetSr?: number,
|
|
31
|
+
): Float32Array {
|
|
32
|
+
if (!(samples instanceof Float32Array)) {
|
|
33
|
+
return resample(samples.samples, samples.srcSr, samples.targetSr);
|
|
34
|
+
}
|
|
35
|
+
return requireModule().resample(samples, srcSr as number, targetSr as number);
|
|
21
36
|
}
|