@libraz/libsonare 1.2.3 → 1.3.0

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 (43) hide show
  1. package/README.md +38 -1
  2. package/dist/index.d.ts +1 -2842
  3. package/dist/index.js +3602 -1934
  4. package/dist/index.js.map +1 -1
  5. package/dist/sonare-rt-module.js +1 -1
  6. package/dist/sonare-rt.js +1 -1
  7. package/dist/sonare-rt.wasm +0 -0
  8. package/dist/sonare.js +1 -1
  9. package/dist/sonare.wasm +0 -0
  10. package/dist/worklet.d.ts +4816 -483
  11. package/dist/worklet.js +747 -440
  12. package/dist/worklet.js.map +1 -1
  13. package/package.json +2 -1
  14. package/src/analysis_helpers.ts +152 -0
  15. package/src/audio.ts +493 -0
  16. package/src/codes.ts +56 -0
  17. package/src/effects_mastering.ts +964 -0
  18. package/src/feature_core.ts +248 -0
  19. package/src/feature_music.ts +419 -0
  20. package/src/feature_pitch.ts +80 -0
  21. package/src/feature_resample.ts +21 -0
  22. package/src/feature_spectral.ts +330 -0
  23. package/src/feature_spectrogram.ts +454 -0
  24. package/src/features.ts +84 -0
  25. package/src/index.ts +341 -4963
  26. package/src/live_audio.ts +45 -0
  27. package/src/metering.ts +380 -0
  28. package/src/mixer.ts +523 -0
  29. package/src/module_state.ts +14 -0
  30. package/src/opfs_clip_pages.ts +188 -0
  31. package/src/project.ts +1614 -0
  32. package/src/public_types.ts +177 -2
  33. package/src/quick_analysis.ts +508 -0
  34. package/src/realtime_engine.ts +667 -0
  35. package/src/realtime_voice_changer.ts +275 -0
  36. package/src/scale.ts +42 -0
  37. package/src/sonare.js.d.ts +302 -4
  38. package/src/stream_analyzer.ts +275 -0
  39. package/src/stream_types.ts +26 -1
  40. package/src/streaming_mixing.ts +18 -0
  41. package/src/streaming_processors.ts +335 -0
  42. package/src/validation.ts +82 -0
  43. package/src/web_midi.ts +367 -0
@@ -0,0 +1,248 @@
1
+ import { getSonareModule } from './module_state';
2
+ import type { TempogramMode } from './public_types';
3
+ import type {
4
+ WasmCyclicTempogramResult,
5
+ WasmFrameResult,
6
+ WasmTempogramResult,
7
+ WasmTrimResult,
8
+ } from './sonare.js';
9
+
10
+ function requireModule() {
11
+ return getSonareModule();
12
+ }
13
+
14
+ // ============================================================================
15
+ // Core - Unit Conversion
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Convert frequency in Hz to Mel scale.
20
+ *
21
+ * @param hz - Frequency in Hz
22
+ * @returns Mel frequency
23
+ */
24
+ export function hzToMel(hz: number): number {
25
+ return requireModule().hzToMel(hz);
26
+ }
27
+
28
+ /**
29
+ * Convert Mel scale to frequency in Hz.
30
+ *
31
+ * @param mel - Mel frequency
32
+ * @returns Frequency in Hz
33
+ */
34
+ export function melToHz(mel: number): number {
35
+ return requireModule().melToHz(mel);
36
+ }
37
+
38
+ /**
39
+ * Convert frequency in Hz to MIDI note number.
40
+ *
41
+ * @param hz - Frequency in Hz
42
+ * @returns MIDI note number (A4 = 440 Hz = 69)
43
+ */
44
+ export function hzToMidi(hz: number): number {
45
+ return requireModule().hzToMidi(hz);
46
+ }
47
+
48
+ /**
49
+ * Convert MIDI note number to frequency in Hz.
50
+ *
51
+ * @param midi - MIDI note number
52
+ * @returns Frequency in Hz
53
+ */
54
+ export function midiToHz(midi: number): number {
55
+ return requireModule().midiToHz(midi);
56
+ }
57
+
58
+ /**
59
+ * Convert frequency in Hz to note name.
60
+ *
61
+ * @param hz - Frequency in Hz
62
+ * @returns Note name (e.g., "A4", "C#5")
63
+ */
64
+ export function hzToNote(hz: number): string {
65
+ return requireModule().hzToNote(hz);
66
+ }
67
+
68
+ /**
69
+ * Convert note name to frequency in Hz.
70
+ *
71
+ * @param note - Note name (e.g., "A4", "C#5")
72
+ * @returns Frequency in Hz
73
+ */
74
+ export function noteToHz(note: string): number {
75
+ return requireModule().noteToHz(note);
76
+ }
77
+
78
+ /**
79
+ * Convert frame index to time in seconds.
80
+ *
81
+ * @param frames - Frame index
82
+ * @param sr - Sample rate in Hz (default: 22050)
83
+ * @param hopLength - Hop length in samples (default: 512)
84
+ * @returns Time in seconds
85
+ */
86
+ export function framesToTime(frames: number, sr = 22050, hopLength = 512): number {
87
+ return requireModule().framesToTime(frames, sr, hopLength);
88
+ }
89
+
90
+ /**
91
+ * Convert time in seconds to frame index.
92
+ *
93
+ * @param time - Time in seconds
94
+ * @param sr - Sample rate in Hz (default: 22050)
95
+ * @param hopLength - Hop length in samples (default: 512)
96
+ * @returns Frame index
97
+ */
98
+ export function timeToFrames(time: number, sr = 22050, hopLength = 512): number {
99
+ return requireModule().timeToFrames(time, sr, hopLength);
100
+ }
101
+
102
+ export function framesToSamples(frames: number, hopLength = 512, nFft = 0): number {
103
+ return requireModule().framesToSamples(frames, hopLength, nFft);
104
+ }
105
+
106
+ export function samplesToFrames(samples: number, hopLength = 512, nFft = 0): number {
107
+ return requireModule().samplesToFrames(samples, hopLength, nFft);
108
+ }
109
+
110
+ export function powerToDb(
111
+ values: Float32Array,
112
+ ref = 1.0,
113
+ amin = 1e-10,
114
+ topDb = 80.0,
115
+ ): Float32Array {
116
+ return requireModule().powerToDb(values, ref, amin, topDb);
117
+ }
118
+
119
+ export function amplitudeToDb(
120
+ values: Float32Array,
121
+ ref = 1.0,
122
+ amin = 1e-5,
123
+ topDb = 80.0,
124
+ ): Float32Array {
125
+ return requireModule().amplitudeToDb(values, ref, amin, topDb);
126
+ }
127
+
128
+ export function dbToPower(values: Float32Array, ref = 1.0): Float32Array {
129
+ return requireModule().dbToPower(values, ref);
130
+ }
131
+
132
+ export function dbToAmplitude(values: Float32Array, ref = 1.0): Float32Array {
133
+ return requireModule().dbToAmplitude(values, ref);
134
+ }
135
+
136
+ export function preemphasis(samples: Float32Array, coef = 0.97, zi?: number): Float32Array {
137
+ return requireModule().preemphasis(samples, coef, zi ?? null);
138
+ }
139
+
140
+ export function deemphasis(samples: Float32Array, coef = 0.97, zi?: number): Float32Array {
141
+ return requireModule().deemphasis(samples, coef, zi ?? null);
142
+ }
143
+
144
+ export function trimSilence(
145
+ samples: Float32Array,
146
+ topDb = 60.0,
147
+ frameLength = 2048,
148
+ hopLength = 512,
149
+ ): WasmTrimResult {
150
+ return requireModule().trimSilence(samples, topDb, frameLength, hopLength);
151
+ }
152
+
153
+ export function splitSilence(
154
+ samples: Float32Array,
155
+ topDb = 60.0,
156
+ frameLength = 2048,
157
+ hopLength = 512,
158
+ ): Int32Array {
159
+ return requireModule().splitSilence(samples, topDb, frameLength, hopLength);
160
+ }
161
+
162
+ export function frameSignal(
163
+ samples: Float32Array,
164
+ frameLength: number,
165
+ hopLength: number,
166
+ ): WasmFrameResult {
167
+ return requireModule().frameSignal(samples, frameLength, hopLength);
168
+ }
169
+
170
+ export function padCenter(values: Float32Array, targetSize: number, padValue = 0.0): Float32Array {
171
+ return requireModule().padCenter(values, targetSize, padValue);
172
+ }
173
+
174
+ export function fixLength(values: Float32Array, targetSize: number, padValue = 0.0): Float32Array {
175
+ return requireModule().fixLength(values, targetSize, padValue);
176
+ }
177
+
178
+ export function fixFrames(frames: Int32Array, xMin = 0, xMax = -1, pad = true): Int32Array {
179
+ return requireModule().fixFrames(frames, xMin, xMax, pad);
180
+ }
181
+
182
+ export function peakPick(
183
+ values: Float32Array,
184
+ preMax: number,
185
+ postMax: number,
186
+ preAvg: number,
187
+ postAvg: number,
188
+ delta: number,
189
+ wait: number,
190
+ ): Int32Array {
191
+ return requireModule().peakPick(values, preMax, postMax, preAvg, postAvg, delta, wait);
192
+ }
193
+
194
+ export function vectorNormalize(values: Float32Array, normType = 0, threshold = 0.0): Float32Array {
195
+ return requireModule().vectorNormalize(values, normType, threshold);
196
+ }
197
+
198
+ export function pcen(
199
+ values: Float32Array,
200
+ nBins: number,
201
+ nFrames: number,
202
+ options: Record<string, number> = {},
203
+ ): Float32Array {
204
+ return requireModule().pcen(values, nBins, nFrames, options);
205
+ }
206
+
207
+ export function tonnetz(chromagram: Float32Array, nChroma: number, nFrames: number): Float32Array {
208
+ return requireModule().tonnetz(chromagram, nChroma, nFrames);
209
+ }
210
+
211
+ export function tempogram(
212
+ onsetEnvelope: Float32Array,
213
+ sampleRate = 22050,
214
+ hopLength = 512,
215
+ winLength = 384,
216
+ mode: TempogramMode = 'autocorrelation',
217
+ ): WasmTempogramResult {
218
+ return requireModule().tempogram(onsetEnvelope, sampleRate, hopLength, winLength, mode);
219
+ }
220
+
221
+ export function cyclicTempogram(
222
+ onsetEnvelope: Float32Array,
223
+ sampleRate = 22050,
224
+ hopLength = 512,
225
+ winLength = 384,
226
+ bpmMin = 60.0,
227
+ nBins = 60,
228
+ ): WasmCyclicTempogramResult {
229
+ return requireModule().cyclicTempogram(
230
+ onsetEnvelope,
231
+ sampleRate,
232
+ hopLength,
233
+ winLength,
234
+ bpmMin,
235
+ nBins,
236
+ );
237
+ }
238
+
239
+ export function plp(
240
+ onsetEnvelope: Float32Array,
241
+ sampleRate = 22050,
242
+ hopLength = 512,
243
+ tempoMin = 30.0,
244
+ tempoMax = 300.0,
245
+ winLength = 384,
246
+ ): Float32Array {
247
+ return requireModule().plp(onsetEnvelope, sampleRate, hopLength, tempoMin, tempoMax, winLength);
248
+ }
@@ -0,0 +1,419 @@
1
+ import { getSonareModule } from './module_state';
2
+ import type {
3
+ AnalyzeSectionsOptions,
4
+ CqtResult,
5
+ LufsResult,
6
+ MelodyResult,
7
+ OnsetStrengthMultiResult,
8
+ Section,
9
+ SectionType,
10
+ } from './public_types';
11
+ import type { WasmFourierTempogramResult, WasmNnlsChromaResult } from './sonare.js';
12
+ import type { ValidateOptions } from './validation';
13
+ import {
14
+ assertFiniteScalar,
15
+ assertPositiveInteger,
16
+ assertSampleRate,
17
+ assertSamples,
18
+ } from './validation';
19
+
20
+ function requireModule() {
21
+ return getSonareModule();
22
+ }
23
+
24
+ type GuardedOptions = ValidateOptions;
25
+ type AnalyzeSectionsGuardedOptions = AnalyzeSectionsOptions & ValidateOptions;
26
+ type MelodyGuardedOptions = MelodyOptions & ValidateOptions;
27
+
28
+ function validateMusicSamples(
29
+ fnName: string,
30
+ samples: Float32Array,
31
+ sampleRate: number,
32
+ options: GuardedOptions = {},
33
+ ): void {
34
+ assertSampleRate(fnName, sampleRate);
35
+ assertSamples(fnName, samples, options.validate !== false);
36
+ }
37
+
38
+ function validatePositiveIntegers(fnName: string, values: Record<string, number>): void {
39
+ for (const [name, value] of Object.entries(values)) {
40
+ assertPositiveInteger(fnName, value, name);
41
+ }
42
+ }
43
+
44
+ function validateFrequencyBounds(fnName: string, fmin: number, fmax?: number): void {
45
+ assertFiniteScalar(fnName, fmin, 'fmin');
46
+ if (fmin < 0) {
47
+ throw new RangeError(`${fnName}: fmin must be non-negative`);
48
+ }
49
+ if (fmax !== undefined) {
50
+ assertFiniteScalar(fnName, fmax, 'fmax');
51
+ if (fmax <= fmin) {
52
+ throw new RangeError(`${fnName}: fmax must be greater than fmin`);
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Compute NNLS (non-negative least squares) chromagram.
59
+ *
60
+ * @param samples - Audio samples (mono, float32)
61
+ * @param sampleRate - Sample rate in Hz (default: 22050)
62
+ * @returns NNLS chroma result
63
+ */
64
+ export function nnlsChroma(
65
+ samples: Float32Array,
66
+ sampleRate = 22050,
67
+ options: GuardedOptions = {},
68
+ ): WasmNnlsChromaResult {
69
+ validateMusicSamples('nnlsChroma', samples, sampleRate, options);
70
+ return requireModule().nnlsChroma(samples, sampleRate);
71
+ }
72
+
73
+ /**
74
+ * Compute the Constant-Q Transform magnitude.
75
+ *
76
+ * @param samples - Audio samples (mono, float32)
77
+ * @param sampleRate - Sample rate in Hz (default: 22050)
78
+ * @param hopLength - Hop length (default: 512)
79
+ * @param fmin - Minimum frequency in Hz (default: 32.70319566257483, C1)
80
+ * @param nBins - Number of frequency bins (default: 84)
81
+ * @param binsPerOctave - Bins per octave (default: 12)
82
+ * @returns CQT magnitude result
83
+ */
84
+ export function cqt(
85
+ samples: Float32Array,
86
+ sampleRate = 22050,
87
+ hopLength = 512,
88
+ fmin = 32.70319566257483,
89
+ nBins = 84,
90
+ binsPerOctave = 12,
91
+ options: GuardedOptions = {},
92
+ ): CqtResult {
93
+ validateMusicSamples('cqt', samples, sampleRate, options);
94
+ validatePositiveIntegers('cqt', { hopLength, nBins, binsPerOctave });
95
+ validateFrequencyBounds('cqt', fmin);
96
+ return requireModule().cqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave);
97
+ }
98
+
99
+ /**
100
+ * Compute the pseudo Constant-Q Transform magnitude.
101
+ *
102
+ * @param samples - Audio samples (mono, float32)
103
+ * @param sampleRate - Sample rate in Hz (default: 22050)
104
+ * @param hopLength - Hop length (default: 512)
105
+ * @param fmin - Minimum frequency in Hz (default: 32.70319566257483, C1)
106
+ * @param nBins - Number of frequency bins (default: 84)
107
+ * @param binsPerOctave - Bins per octave (default: 12)
108
+ * @returns CQT magnitude result
109
+ */
110
+ export function pseudoCqt(
111
+ samples: Float32Array,
112
+ sampleRate = 22050,
113
+ hopLength = 512,
114
+ fmin = 32.70319566257483,
115
+ nBins = 84,
116
+ binsPerOctave = 12,
117
+ options: GuardedOptions = {},
118
+ ): CqtResult {
119
+ validateMusicSamples('pseudoCqt', samples, sampleRate, options);
120
+ validatePositiveIntegers('pseudoCqt', { hopLength, nBins, binsPerOctave });
121
+ validateFrequencyBounds('pseudoCqt', fmin);
122
+ return requireModule().pseudoCqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave);
123
+ }
124
+
125
+ /**
126
+ * Compute the hybrid Constant-Q Transform magnitude.
127
+ *
128
+ * @param samples - Audio samples (mono, float32)
129
+ * @param sampleRate - Sample rate in Hz (default: 22050)
130
+ * @param hopLength - Hop length (default: 512)
131
+ * @param fmin - Minimum frequency in Hz (default: 32.70319566257483, C1)
132
+ * @param nBins - Number of frequency bins (default: 84)
133
+ * @param binsPerOctave - Bins per octave (default: 12)
134
+ * @returns CQT magnitude result
135
+ */
136
+ export function hybridCqt(
137
+ samples: Float32Array,
138
+ sampleRate = 22050,
139
+ hopLength = 512,
140
+ fmin = 32.70319566257483,
141
+ nBins = 84,
142
+ binsPerOctave = 12,
143
+ options: GuardedOptions = {},
144
+ ): CqtResult {
145
+ validateMusicSamples('hybridCqt', samples, sampleRate, options);
146
+ validatePositiveIntegers('hybridCqt', { hopLength, nBins, binsPerOctave });
147
+ validateFrequencyBounds('hybridCqt', fmin);
148
+ return requireModule().hybridCqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave);
149
+ }
150
+
151
+ /**
152
+ * Compute the Variable-Q Transform magnitude (gamma controls Q).
153
+ *
154
+ * @param samples - Audio samples (mono, float32)
155
+ * @param sampleRate - Sample rate in Hz (default: 22050)
156
+ * @param hopLength - Hop length (default: 512)
157
+ * @param fmin - Minimum frequency in Hz (default: 32.70319566257483, C1)
158
+ * @param nBins - Number of frequency bins (default: 84)
159
+ * @param binsPerOctave - Bins per octave (default: 12)
160
+ * @param gamma - Bandwidth offset; 0 is equivalent to CQT (default: 0)
161
+ * @returns VQT magnitude result (same shape as CQT)
162
+ */
163
+ export function vqt(
164
+ samples: Float32Array,
165
+ sampleRate = 22050,
166
+ hopLength = 512,
167
+ fmin = 32.70319566257483,
168
+ nBins = 84,
169
+ binsPerOctave = 12,
170
+ gamma = 0,
171
+ options: GuardedOptions = {},
172
+ ): CqtResult {
173
+ validateMusicSamples('vqt', samples, sampleRate, options);
174
+ validatePositiveIntegers('vqt', { hopLength, nBins, binsPerOctave });
175
+ validateFrequencyBounds('vqt', fmin);
176
+ assertFiniteScalar('vqt', gamma, 'gamma');
177
+ if (gamma < 0) {
178
+ throw new RangeError('vqt: gamma must be non-negative');
179
+ }
180
+ return requireModule().vqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave, gamma);
181
+ }
182
+
183
+ /**
184
+ * Detect song-structure sections (intro/verse/chorus/...).
185
+ *
186
+ * @param samples - Audio samples (mono, float32)
187
+ * @param sampleRate - Sample rate in Hz (default: 22050)
188
+ * @param nFft - FFT size (default: 2048)
189
+ * @param hopLength - Hop length (default: 512)
190
+ * @param minSectionSec - Minimum section duration in seconds (default: 4.0)
191
+ * @returns Array of detected sections
192
+ */
193
+ export function analyzeSections(
194
+ samples: Float32Array,
195
+ sampleRate = 22050,
196
+ options: AnalyzeSectionsGuardedOptions = {},
197
+ ): Section[] {
198
+ validateMusicSamples('analyzeSections', samples, sampleRate, options);
199
+ validatePositiveIntegers('analyzeSections', {
200
+ nFft: options.nFft ?? 2048,
201
+ hopLength: options.hopLength ?? 512,
202
+ });
203
+ assertFiniteScalar('analyzeSections', options.minSectionSec ?? 4.0, 'minSectionSec');
204
+ if ((options.minSectionSec ?? 4.0) <= 0) {
205
+ throw new RangeError('analyzeSections: minSectionSec must be positive');
206
+ }
207
+ return requireModule()
208
+ .analyzeSections(
209
+ samples,
210
+ sampleRate,
211
+ options.nFft ?? 2048,
212
+ options.hopLength ?? 512,
213
+ options.minSectionSec ?? 4.0,
214
+ )
215
+ .map((s) => ({ ...s, type: s.type as SectionType }));
216
+ }
217
+
218
+ /** Options for {@link analyzeMelody}. All fields are optional. */
219
+ export interface MelodyOptions {
220
+ /** Lowest f0 (Hz) the tracker will consider. Default 65 (≈ C2). */
221
+ fmin?: number;
222
+ /** Highest f0 (Hz) the tracker will consider. Default 2093 (≈ C7). */
223
+ fmax?: number;
224
+ /** Analysis frame length in samples. Default 2048. */
225
+ frameLength?: number;
226
+ /** Hop length between frames in samples. Default 256. */
227
+ hopLength?: number;
228
+ /** Voicing confidence threshold in [0,1]; frames below are unvoiced. Default 0.1. */
229
+ threshold?: number;
230
+ /**
231
+ * Use the pYIN tracker (Viterbi-smoothed) instead of plain per-frame YIN.
232
+ * Produces a less octave-jumpy contour. Defaults to `false`.
233
+ */
234
+ usePyin?: boolean;
235
+ /**
236
+ * When {@link usePyin} is `true`, reflect-pad by `frameLength / 2` so frame
237
+ * `i` is centered at `i * hopLength` (matches `librosa.pyin(center=True)`).
238
+ * Ignored by the plain-YIN path. Defaults to `true`.
239
+ */
240
+ center?: boolean;
241
+ }
242
+
243
+ /**
244
+ * Extract the melody contour from monophonic audio via YIN (or pYIN).
245
+ *
246
+ * @param samples - Audio samples (mono, float32)
247
+ * @param sampleRate - Sample rate in Hz (default: 22050)
248
+ * @param options - Tracker + tuning options ({@link MelodyOptions})
249
+ * @returns Melody contour with per-frame pitch points and summary stats
250
+ */
251
+ export function analyzeMelody(
252
+ samples: Float32Array,
253
+ sampleRate = 22050,
254
+ options: MelodyGuardedOptions = {},
255
+ ): MelodyResult {
256
+ validateMusicSamples('analyzeMelody', samples, sampleRate, options);
257
+ const fmin = options.fmin ?? 65.0;
258
+ const fmax = options.fmax ?? 2093.0;
259
+ validateFrequencyBounds('analyzeMelody', fmin, fmax);
260
+ validatePositiveIntegers('analyzeMelody', {
261
+ frameLength: options.frameLength ?? 2048,
262
+ hopLength: options.hopLength ?? 256,
263
+ });
264
+ assertFiniteScalar('analyzeMelody', options.threshold ?? 0.1, 'threshold');
265
+ return requireModule().analyzeMelody(
266
+ samples,
267
+ sampleRate,
268
+ options.fmin ?? 65.0,
269
+ options.fmax ?? 2093.0,
270
+ options.frameLength ?? 2048,
271
+ options.hopLength ?? 256,
272
+ options.threshold ?? 0.1,
273
+ options.usePyin ?? false,
274
+ options.center ?? true,
275
+ );
276
+ }
277
+
278
+ /**
279
+ * Compute the onset strength envelope.
280
+ *
281
+ * @param samples - Audio samples (mono, float32)
282
+ * @param sampleRate - Sample rate in Hz (default: 22050)
283
+ * @param nFft - FFT size (default: 2048)
284
+ * @param hopLength - Hop length (default: 512)
285
+ * @param nMels - Number of Mel bands (default: 128)
286
+ * @returns Onset envelope for each frame
287
+ */
288
+ export function onsetEnvelope(
289
+ samples: Float32Array,
290
+ sampleRate = 22050,
291
+ nFft = 2048,
292
+ hopLength = 512,
293
+ nMels = 128,
294
+ options: GuardedOptions = {},
295
+ ): Float32Array {
296
+ validateMusicSamples('onsetEnvelope', samples, sampleRate, options);
297
+ validatePositiveIntegers('onsetEnvelope', { nFft, hopLength, nMels });
298
+ return requireModule().onsetEnvelope(samples, sampleRate, nFft, hopLength, nMels);
299
+ }
300
+
301
+ /**
302
+ * Compute multi-band onset strength envelopes.
303
+ *
304
+ * @param samples - Audio samples (mono, float32)
305
+ * @param sampleRate - Sample rate in Hz (default: 22050)
306
+ * @param nFft - FFT size (default: 2048)
307
+ * @param hopLength - Hop length (default: 512)
308
+ * @param nMels - Number of Mel bands (default: 128)
309
+ * @param nBands - Number of onset bands (default: 3)
310
+ * @returns Multi-band onset matrix
311
+ */
312
+ export function onsetStrengthMulti(
313
+ samples: Float32Array,
314
+ sampleRate = 22050,
315
+ nFft = 2048,
316
+ hopLength = 512,
317
+ nMels = 128,
318
+ nBands = 3,
319
+ options: GuardedOptions = {},
320
+ ): OnsetStrengthMultiResult {
321
+ validateMusicSamples('onsetStrengthMulti', samples, sampleRate, options);
322
+ validatePositiveIntegers('onsetStrengthMulti', { nFft, hopLength, nMels, nBands });
323
+ return requireModule().onsetStrengthMulti(samples, sampleRate, nFft, hopLength, nMels, nBands);
324
+ }
325
+
326
+ /**
327
+ * Compute the Fourier tempogram from an onset envelope.
328
+ *
329
+ * @param onsetEnvelope - Onset strength envelope (float32)
330
+ * @param sampleRate - Sample rate in Hz (default: 22050)
331
+ * @param hopLength - Hop length (default: 512)
332
+ * @param winLength - Window length in frames (default: 384)
333
+ * @returns Fourier tempogram result
334
+ */
335
+ export function fourierTempogram(
336
+ onsetEnvelope: Float32Array,
337
+ sampleRate = 22050,
338
+ hopLength = 512,
339
+ winLength = 384,
340
+ options: GuardedOptions = {},
341
+ ): WasmFourierTempogramResult {
342
+ assertSampleRate('fourierTempogram', sampleRate);
343
+ assertSamples('fourierTempogram', onsetEnvelope, options.validate !== false, 'onsetEnvelope');
344
+ validatePositiveIntegers('fourierTempogram', { hopLength, winLength });
345
+ return requireModule().fourierTempogram(onsetEnvelope, sampleRate, hopLength, winLength);
346
+ }
347
+
348
+ /**
349
+ * Compute tempogram ratio features.
350
+ *
351
+ * @param tempogramData - Tempogram data (float32)
352
+ * @param winLength - Window length in frames (default: 384)
353
+ * @param sampleRate - Sample rate in Hz (default: 22050)
354
+ * @param hopLength - Hop length (default: 512)
355
+ * @returns Tempogram ratio features
356
+ */
357
+ export function tempogramRatio(
358
+ tempogramData: Float32Array,
359
+ winLength = 384,
360
+ sampleRate = 22050,
361
+ hopLength = 512,
362
+ options: GuardedOptions = {},
363
+ ): Float32Array {
364
+ assertSampleRate('tempogramRatio', sampleRate);
365
+ assertSamples('tempogramRatio', tempogramData, options.validate !== false, 'tempogramData');
366
+ validatePositiveIntegers('tempogramRatio', { winLength, hopLength });
367
+ return requireModule().tempogramRatio(tempogramData, winLength, sampleRate, hopLength);
368
+ }
369
+
370
+ /**
371
+ * Measure loudness (EBU R128 / ITU-R BS.1770).
372
+ *
373
+ * @param samples - Audio samples (mono, float32)
374
+ * @param sampleRate - Sample rate in Hz (default: 22050)
375
+ * @returns Loudness measurement result
376
+ */
377
+ export function lufs(
378
+ samples: Float32Array,
379
+ sampleRate = 22050,
380
+ options: ValidateOptions = {},
381
+ ): LufsResult {
382
+ assertSampleRate('lufs', sampleRate);
383
+ assertSamples('lufs', samples, options.validate !== false);
384
+ return requireModule().lufs(samples, sampleRate);
385
+ }
386
+
387
+ /**
388
+ * Compute the momentary loudness (LUFS) over time.
389
+ *
390
+ * @param samples - Audio samples (mono, float32)
391
+ * @param sampleRate - Sample rate in Hz (default: 22050)
392
+ * @returns Momentary LUFS values over time
393
+ */
394
+ export function momentaryLufs(
395
+ samples: Float32Array,
396
+ sampleRate = 22050,
397
+ options: ValidateOptions = {},
398
+ ): Float32Array {
399
+ assertSampleRate('momentaryLufs', sampleRate);
400
+ assertSamples('momentaryLufs', samples, options.validate !== false);
401
+ return requireModule().momentaryLufs(samples, sampleRate);
402
+ }
403
+
404
+ /**
405
+ * Compute the short-term loudness (LUFS) over time.
406
+ *
407
+ * @param samples - Audio samples (mono, float32)
408
+ * @param sampleRate - Sample rate in Hz (default: 22050)
409
+ * @returns Short-term LUFS values over time
410
+ */
411
+ export function shortTermLufs(
412
+ samples: Float32Array,
413
+ sampleRate = 22050,
414
+ options: ValidateOptions = {},
415
+ ): Float32Array {
416
+ assertSampleRate('shortTermLufs', sampleRate);
417
+ assertSamples('shortTermLufs', samples, options.validate !== false);
418
+ return requireModule().shortTermLufs(samples, sampleRate);
419
+ }