@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.
- package/README.md +69 -725
- package/dist/index.d.ts +1155 -183
- package/dist/index.js +4924 -3935
- 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 +1141 -970
- package/dist/worklet.js.map +1 -1
- package/package.json +15 -3
- package/src/_chain_config.ts +46 -0
- package/src/audio.ts +24 -4
- package/src/codes.ts +27 -4
- package/src/effects_mastering.ts +25 -1
- package/src/effects_transform.ts +292 -46
- package/src/effects_voice_change.ts +46 -53
- package/src/feature_core.ts +316 -12
- package/src/feature_music.ts +371 -4
- 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 +370 -83
- 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 +30 -6
- package/src/project_internal.ts +12 -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/realtime_voice_changer.ts +79 -3
- package/src/sonare.js.d.ts +35 -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/quick_analysis.ts
CHANGED
|
@@ -37,6 +37,53 @@ function requireModule() {
|
|
|
37
37
|
|
|
38
38
|
type GuardedOptions = ValidateOptions;
|
|
39
39
|
|
|
40
|
+
/** Canonical request form for one-shot analysis functions. */
|
|
41
|
+
export interface SamplesRequest extends GuardedOptions {
|
|
42
|
+
samples: Float32Array;
|
|
43
|
+
sampleRate?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Canonical request form for key detection functions. */
|
|
47
|
+
export interface DetectKeyRequest extends KeyDetectionOptions, SamplesRequest {}
|
|
48
|
+
|
|
49
|
+
/** Canonical request form for analysis with synchronous progress reporting. */
|
|
50
|
+
export interface AnalyzeWithProgressRequest extends SamplesRequest {
|
|
51
|
+
onProgress: ProgressCallback;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Canonical request form for chord detection. */
|
|
55
|
+
export interface DetectChordsRequest extends ChordDetectionOptions, SamplesRequest {}
|
|
56
|
+
|
|
57
|
+
/** Canonical request form for functional chord analysis. */
|
|
58
|
+
export interface ChordFunctionalAnalysisRequest extends DetectChordsRequest {
|
|
59
|
+
keyRoot: PitchClass;
|
|
60
|
+
/** Musical mode; defaults to {@link Mode.Major}. */
|
|
61
|
+
keyMode?: Mode;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Canonical request form for impulse-response analysis. */
|
|
65
|
+
export interface AnalyzeImpulseResponseRequest extends SamplesRequest {
|
|
66
|
+
nOctaveBands?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Canonical request form for acoustic analysis. */
|
|
70
|
+
export interface DetectAcousticRequest extends AcousticOptions, SamplesRequest {}
|
|
71
|
+
|
|
72
|
+
/** Canonical request form for equivalent-room estimation. */
|
|
73
|
+
export interface EstimateRoomRequest extends RoomEstimateOptions, SamplesRequest {}
|
|
74
|
+
|
|
75
|
+
/** Canonical request form for room-reverb morphing. */
|
|
76
|
+
export interface RoomMorphRequest extends RoomMorphOptions, GuardedOptions {
|
|
77
|
+
samples: Float32Array;
|
|
78
|
+
sampleRate: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Canonical request forms for detailed music-analysis APIs. */
|
|
82
|
+
export interface AnalyzeBpmRequest extends AnalyzeBpmOptions, SamplesRequest {}
|
|
83
|
+
export interface AnalyzeRhythmRequest extends AnalyzeRhythmOptions, SamplesRequest {}
|
|
84
|
+
export interface AnalyzeDynamicsRequest extends AnalyzeDynamicsOptions, SamplesRequest {}
|
|
85
|
+
export interface AnalyzeTimbreRequest extends AnalyzeTimbreOptions, SamplesRequest {}
|
|
86
|
+
|
|
40
87
|
function validateAnalysisInput(
|
|
41
88
|
fnName: string,
|
|
42
89
|
samples: Float32Array,
|
|
@@ -58,13 +105,20 @@ function validateAnalysisInput(
|
|
|
58
105
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
59
106
|
* @returns Detected BPM
|
|
60
107
|
*/
|
|
108
|
+
export function detectBpm(request: SamplesRequest): number;
|
|
61
109
|
export function detectBpm(
|
|
62
110
|
samples: Float32Array,
|
|
111
|
+
sampleRate?: number,
|
|
112
|
+
options?: GuardedOptions,
|
|
113
|
+
): number;
|
|
114
|
+
export function detectBpm(
|
|
115
|
+
samples: Float32Array | SamplesRequest,
|
|
63
116
|
sampleRate = 22050,
|
|
64
117
|
options: GuardedOptions = {},
|
|
65
118
|
): number {
|
|
66
|
-
|
|
67
|
-
|
|
119
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
120
|
+
validateAnalysisInput('detectBpm', request.samples, request.sampleRate ?? 22050, request);
|
|
121
|
+
return requireModule().detectBpm(request.samples, request.sampleRate ?? 22050);
|
|
68
122
|
}
|
|
69
123
|
|
|
70
124
|
/**
|
|
@@ -74,23 +128,30 @@ export function detectBpm(
|
|
|
74
128
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
75
129
|
* @returns Detected key
|
|
76
130
|
*/
|
|
131
|
+
export function detectKey(request: DetectKeyRequest): Key;
|
|
77
132
|
export function detectKey(
|
|
78
133
|
samples: Float32Array,
|
|
134
|
+
sampleRate?: number,
|
|
135
|
+
options?: KeyDetectionOptions,
|
|
136
|
+
): Key;
|
|
137
|
+
export function detectKey(
|
|
138
|
+
samples: Float32Array | DetectKeyRequest,
|
|
79
139
|
sampleRate = 22050,
|
|
80
140
|
options: KeyDetectionOptions = {},
|
|
81
141
|
): Key {
|
|
82
|
-
|
|
142
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
143
|
+
validateAnalysisInput('detectKey', request.samples, request.sampleRate ?? 22050, request);
|
|
83
144
|
const result = requireModule()._detectKeyWithOptions(
|
|
84
|
-
samples,
|
|
85
|
-
sampleRate,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
keyModeValues(
|
|
92
|
-
keyProfileValue(
|
|
93
|
-
|
|
145
|
+
request.samples,
|
|
146
|
+
request.sampleRate ?? 22050,
|
|
147
|
+
request.nFft ?? 4096,
|
|
148
|
+
request.hopLength ?? 512,
|
|
149
|
+
request.useHpss ?? false,
|
|
150
|
+
request.loudnessWeighted ?? false,
|
|
151
|
+
request.highPassHz ?? 0,
|
|
152
|
+
keyModeValues(request.modes),
|
|
153
|
+
keyProfileValue(request.profile),
|
|
154
|
+
request.genreHint ?? '',
|
|
94
155
|
);
|
|
95
156
|
return {
|
|
96
157
|
root: result.root as PitchClass,
|
|
@@ -101,28 +162,40 @@ export function detectKey(
|
|
|
101
162
|
};
|
|
102
163
|
}
|
|
103
164
|
|
|
165
|
+
export function detectKeyCandidates(request: DetectKeyRequest): KeyCandidate[];
|
|
104
166
|
export function detectKeyCandidates(
|
|
105
167
|
samples: Float32Array,
|
|
168
|
+
sampleRate?: number,
|
|
169
|
+
options?: KeyDetectionOptions,
|
|
170
|
+
): KeyCandidate[];
|
|
171
|
+
export function detectKeyCandidates(
|
|
172
|
+
samples: Float32Array | DetectKeyRequest,
|
|
106
173
|
sampleRate = 22050,
|
|
107
174
|
options: KeyDetectionOptions = {},
|
|
108
175
|
): KeyCandidate[] {
|
|
109
|
-
|
|
176
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
177
|
+
validateAnalysisInput(
|
|
178
|
+
'detectKeyCandidates',
|
|
179
|
+
request.samples,
|
|
180
|
+
request.sampleRate ?? 22050,
|
|
181
|
+
request,
|
|
182
|
+
);
|
|
110
183
|
// The embind value marshalling returns an array whose constructor is not this
|
|
111
184
|
// realm's Array; chaining .map() onto it propagates that constructor via
|
|
112
185
|
// Symbol.species, leaving a result that structuredClone (and so postMessage to
|
|
113
186
|
// a Worker) rejects with "could not be cloned". Array.from() re-roots it as a
|
|
114
187
|
// plain Array before mapping.
|
|
115
188
|
const candidates = requireModule()._detectKeyCandidates(
|
|
116
|
-
samples,
|
|
117
|
-
sampleRate,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
keyModeValues(
|
|
124
|
-
keyProfileValue(
|
|
125
|
-
|
|
189
|
+
request.samples,
|
|
190
|
+
request.sampleRate ?? 22050,
|
|
191
|
+
request.nFft ?? 4096,
|
|
192
|
+
request.hopLength ?? 512,
|
|
193
|
+
request.useHpss ?? false,
|
|
194
|
+
request.loudnessWeighted ?? false,
|
|
195
|
+
request.highPassHz ?? 0,
|
|
196
|
+
keyModeValues(request.modes),
|
|
197
|
+
keyProfileValue(request.profile),
|
|
198
|
+
request.genreHint ?? '',
|
|
126
199
|
);
|
|
127
200
|
return Array.from(candidates, convertKeyCandidate);
|
|
128
201
|
}
|
|
@@ -134,13 +207,20 @@ export function detectKeyCandidates(
|
|
|
134
207
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
135
208
|
* @returns Array of onset times in seconds
|
|
136
209
|
*/
|
|
210
|
+
export function detectOnsets(request: SamplesRequest): Float32Array;
|
|
137
211
|
export function detectOnsets(
|
|
138
212
|
samples: Float32Array,
|
|
213
|
+
sampleRate?: number,
|
|
214
|
+
options?: GuardedOptions,
|
|
215
|
+
): Float32Array;
|
|
216
|
+
export function detectOnsets(
|
|
217
|
+
samples: Float32Array | SamplesRequest,
|
|
139
218
|
sampleRate = 22050,
|
|
140
219
|
options: GuardedOptions = {},
|
|
141
220
|
): Float32Array {
|
|
142
|
-
|
|
143
|
-
|
|
221
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
222
|
+
validateAnalysisInput('detectOnsets', request.samples, request.sampleRate ?? 22050, request);
|
|
223
|
+
return requireModule().detectOnsets(request.samples, request.sampleRate ?? 22050);
|
|
144
224
|
}
|
|
145
225
|
|
|
146
226
|
/**
|
|
@@ -150,13 +230,20 @@ export function detectOnsets(
|
|
|
150
230
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
151
231
|
* @returns Array of beat times in seconds
|
|
152
232
|
*/
|
|
233
|
+
export function detectBeats(request: SamplesRequest): Float32Array;
|
|
153
234
|
export function detectBeats(
|
|
154
235
|
samples: Float32Array,
|
|
236
|
+
sampleRate?: number,
|
|
237
|
+
options?: GuardedOptions,
|
|
238
|
+
): Float32Array;
|
|
239
|
+
export function detectBeats(
|
|
240
|
+
samples: Float32Array | SamplesRequest,
|
|
155
241
|
sampleRate = 22050,
|
|
156
242
|
options: GuardedOptions = {},
|
|
157
243
|
): Float32Array {
|
|
158
|
-
|
|
159
|
-
|
|
244
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
245
|
+
validateAnalysisInput('detectBeats', request.samples, request.sampleRate ?? 22050, request);
|
|
246
|
+
return requireModule().detectBeats(request.samples, request.sampleRate ?? 22050);
|
|
160
247
|
}
|
|
161
248
|
|
|
162
249
|
/**
|
|
@@ -166,13 +253,20 @@ export function detectBeats(
|
|
|
166
253
|
* @param sampleRate - Sample rate in Hz (default: 22050)
|
|
167
254
|
* @returns Array of downbeat times in seconds
|
|
168
255
|
*/
|
|
256
|
+
export function detectDownbeats(request: SamplesRequest): Float32Array;
|
|
169
257
|
export function detectDownbeats(
|
|
170
258
|
samples: Float32Array,
|
|
259
|
+
sampleRate?: number,
|
|
260
|
+
options?: GuardedOptions,
|
|
261
|
+
): Float32Array;
|
|
262
|
+
export function detectDownbeats(
|
|
263
|
+
samples: Float32Array | SamplesRequest,
|
|
171
264
|
sampleRate = 22050,
|
|
172
265
|
options: GuardedOptions = {},
|
|
173
266
|
): Float32Array {
|
|
174
|
-
|
|
175
|
-
|
|
267
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
268
|
+
validateAnalysisInput('detectDownbeats', request.samples, request.sampleRate ?? 22050, request);
|
|
269
|
+
return requireModule().detectDownbeats(request.samples, request.sampleRate ?? 22050);
|
|
176
270
|
}
|
|
177
271
|
|
|
178
272
|
/**
|
|
@@ -183,29 +277,36 @@ export function detectDownbeats(
|
|
|
183
277
|
* @param options - Optional chord detection settings
|
|
184
278
|
* @returns Detected chord segments
|
|
185
279
|
*/
|
|
280
|
+
export function detectChords(request: DetectChordsRequest): ChordAnalysisResult;
|
|
186
281
|
export function detectChords(
|
|
187
282
|
samples: Float32Array,
|
|
283
|
+
sampleRate?: number,
|
|
284
|
+
options?: ChordDetectionOptions,
|
|
285
|
+
): ChordAnalysisResult;
|
|
286
|
+
export function detectChords(
|
|
287
|
+
samples: Float32Array | DetectChordsRequest,
|
|
188
288
|
sampleRate = 22050,
|
|
189
289
|
options: ChordDetectionOptions = {},
|
|
190
290
|
): ChordAnalysisResult {
|
|
191
|
-
|
|
291
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
292
|
+
validateAnalysisInput('detectChords', request.samples, request.sampleRate ?? 22050, request);
|
|
192
293
|
const result = requireModule().detectChords(
|
|
193
|
-
samples,
|
|
194
|
-
sampleRate,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
chordChromaMethodValue(
|
|
294
|
+
request.samples,
|
|
295
|
+
request.sampleRate ?? 22050,
|
|
296
|
+
request.minDuration ?? 0.3,
|
|
297
|
+
request.smoothingWindow ?? 2.0,
|
|
298
|
+
request.threshold ?? 0.5,
|
|
299
|
+
request.useTriadsOnly ?? false,
|
|
300
|
+
request.nFft ?? 2048,
|
|
301
|
+
request.hopLength ?? 512,
|
|
302
|
+
request.useBeatSync ?? true,
|
|
303
|
+
request.useHmm ?? false,
|
|
304
|
+
request.hmmBeamWidth ?? 24,
|
|
305
|
+
request.useKeyContext ?? false,
|
|
306
|
+
request.keyRoot ?? PitchClass.C,
|
|
307
|
+
request.keyMode ?? Mode.Major,
|
|
308
|
+
request.detectInversions ?? false,
|
|
309
|
+
chordChromaMethodValue(request.chromaMethod ?? 'stft'),
|
|
209
310
|
);
|
|
210
311
|
return convertChordAnalysisResult(result);
|
|
211
312
|
}
|
|
@@ -217,31 +318,48 @@ export function detectChords(
|
|
|
217
318
|
*
|
|
218
319
|
* @returns One Roman-numeral label (e.g. "I", "IV", "V", "vi") per detected chord
|
|
219
320
|
*/
|
|
321
|
+
export function chordFunctionalAnalysis(request: ChordFunctionalAnalysisRequest): string[];
|
|
220
322
|
export function chordFunctionalAnalysis(
|
|
221
323
|
samples: Float32Array,
|
|
222
324
|
keyRoot: PitchClass,
|
|
223
|
-
keyMode
|
|
325
|
+
keyMode?: Mode,
|
|
326
|
+
sampleRate?: number,
|
|
327
|
+
options?: ChordDetectionOptions,
|
|
328
|
+
): string[];
|
|
329
|
+
export function chordFunctionalAnalysis(
|
|
330
|
+
samples: Float32Array | ChordFunctionalAnalysisRequest,
|
|
331
|
+
keyRoot?: PitchClass,
|
|
332
|
+
keyMode?: Mode,
|
|
224
333
|
sampleRate = 22050,
|
|
225
334
|
options: ChordDetectionOptions = {},
|
|
226
335
|
): string[] {
|
|
227
|
-
|
|
336
|
+
const request =
|
|
337
|
+
samples instanceof Float32Array
|
|
338
|
+
? { samples, keyRoot, keyMode, sampleRate, ...options }
|
|
339
|
+
: samples;
|
|
340
|
+
validateAnalysisInput(
|
|
341
|
+
'chordFunctionalAnalysis',
|
|
342
|
+
request.samples,
|
|
343
|
+
request.sampleRate ?? 22050,
|
|
344
|
+
request,
|
|
345
|
+
);
|
|
228
346
|
return requireModule().chordFunctionalAnalysis(
|
|
229
|
-
samples,
|
|
230
|
-
keyRoot,
|
|
231
|
-
keyMode,
|
|
232
|
-
sampleRate,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
chordChromaMethodValue(
|
|
347
|
+
request.samples,
|
|
348
|
+
request.keyRoot as PitchClass,
|
|
349
|
+
request.keyMode ?? Mode.Major,
|
|
350
|
+
request.sampleRate ?? 22050,
|
|
351
|
+
request.minDuration ?? 0.3,
|
|
352
|
+
request.smoothingWindow ?? 2.0,
|
|
353
|
+
request.threshold ?? 0.5,
|
|
354
|
+
request.useTriadsOnly ?? false,
|
|
355
|
+
request.nFft ?? 2048,
|
|
356
|
+
request.hopLength ?? 512,
|
|
357
|
+
request.useBeatSync ?? true,
|
|
358
|
+
request.useHmm ?? false,
|
|
359
|
+
request.hmmBeamWidth ?? 24,
|
|
360
|
+
request.useKeyContext ?? false,
|
|
361
|
+
request.detectInversions ?? false,
|
|
362
|
+
chordChromaMethodValue(request.chromaMethod ?? 'stft'),
|
|
245
363
|
);
|
|
246
364
|
}
|
|
247
365
|
|
|
@@ -260,43 +378,69 @@ export function chordFunctionalAnalysis(
|
|
|
260
378
|
* the UI responsive for long inputs, drive this from a Web Worker and use
|
|
261
379
|
* {@link analyzeWithProgress} to report progress.
|
|
262
380
|
*/
|
|
381
|
+
export function analyze(request: SamplesRequest): AnalysisResult;
|
|
263
382
|
export function analyze(
|
|
264
383
|
samples: Float32Array,
|
|
384
|
+
sampleRate?: number,
|
|
385
|
+
options?: GuardedOptions,
|
|
386
|
+
): AnalysisResult;
|
|
387
|
+
export function analyze(
|
|
388
|
+
samples: Float32Array | SamplesRequest,
|
|
265
389
|
sampleRate = 22050,
|
|
266
390
|
options: GuardedOptions = {},
|
|
267
391
|
): AnalysisResult {
|
|
268
|
-
|
|
269
|
-
|
|
392
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
393
|
+
validateAnalysisInput('analyze', request.samples, request.sampleRate ?? 22050, request);
|
|
394
|
+
const result = requireModule().analyze(request.samples, request.sampleRate ?? 22050);
|
|
270
395
|
return convertAnalysisResult(result);
|
|
271
396
|
}
|
|
272
397
|
|
|
398
|
+
export function analyzeImpulseResponse(request: AnalyzeImpulseResponseRequest): AcousticResult;
|
|
273
399
|
export function analyzeImpulseResponse(
|
|
274
400
|
samples: Float32Array,
|
|
401
|
+
sampleRate?: number,
|
|
402
|
+
nOctaveBands?: number,
|
|
403
|
+
): AcousticResult;
|
|
404
|
+
export function analyzeImpulseResponse(
|
|
405
|
+
samples: Float32Array | AnalyzeImpulseResponseRequest,
|
|
275
406
|
sampleRate = 48000,
|
|
276
407
|
nOctaveBands = 6,
|
|
277
408
|
): AcousticResult {
|
|
278
|
-
|
|
409
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, nOctaveBands } : samples;
|
|
410
|
+
validateAnalysisInput(
|
|
411
|
+
'analyzeImpulseResponse',
|
|
412
|
+
request.samples,
|
|
413
|
+
request.sampleRate ?? 48000,
|
|
414
|
+
request,
|
|
415
|
+
);
|
|
279
416
|
const result: WasmAcousticResult = requireModule().analyzeImpulseResponse(
|
|
280
|
-
samples,
|
|
281
|
-
sampleRate,
|
|
282
|
-
nOctaveBands,
|
|
417
|
+
request.samples,
|
|
418
|
+
request.sampleRate ?? 48000,
|
|
419
|
+
request.nOctaveBands ?? 6,
|
|
283
420
|
);
|
|
284
421
|
return result;
|
|
285
422
|
}
|
|
286
423
|
|
|
424
|
+
export function detectAcoustic(request: DetectAcousticRequest): AcousticResult;
|
|
287
425
|
export function detectAcoustic(
|
|
288
426
|
samples: Float32Array,
|
|
427
|
+
sampleRate?: number,
|
|
428
|
+
options?: AcousticOptions,
|
|
429
|
+
): AcousticResult;
|
|
430
|
+
export function detectAcoustic(
|
|
431
|
+
samples: Float32Array | DetectAcousticRequest,
|
|
289
432
|
sampleRate = 48000,
|
|
290
433
|
options: AcousticOptions = {},
|
|
291
434
|
): AcousticResult {
|
|
292
|
-
|
|
435
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
436
|
+
validateAnalysisInput('detectAcoustic', request.samples, request.sampleRate ?? 48000, request);
|
|
293
437
|
const result: WasmAcousticResult = requireModule().detectAcoustic(
|
|
294
|
-
samples,
|
|
295
|
-
sampleRate,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
438
|
+
request.samples,
|
|
439
|
+
request.sampleRate ?? 48000,
|
|
440
|
+
request.nOctaveBands ?? 6,
|
|
441
|
+
request.nThirdOctaveSubbands ?? 24,
|
|
442
|
+
request.minDecayDb ?? 30.0,
|
|
443
|
+
request.noiseFloorMarginDb ?? 10.0,
|
|
300
444
|
);
|
|
301
445
|
return result;
|
|
302
446
|
}
|
|
@@ -317,8 +461,14 @@ export function synthesizeRir(options: RirSynthOptions = {}): RirResult {
|
|
|
317
461
|
* Estimate an equivalent room (volume/dimensions/absorption/DRR) from a
|
|
318
462
|
* recording or impulse response.
|
|
319
463
|
*/
|
|
464
|
+
export function estimateRoom(request: EstimateRoomRequest): RoomEstimateResult;
|
|
320
465
|
export function estimateRoom(
|
|
321
466
|
samples: Float32Array,
|
|
467
|
+
sampleRate?: number,
|
|
468
|
+
options?: RoomEstimateOptions,
|
|
469
|
+
): RoomEstimateResult;
|
|
470
|
+
export function estimateRoom(
|
|
471
|
+
samples: Float32Array | EstimateRoomRequest,
|
|
322
472
|
sampleRate = 48000,
|
|
323
473
|
options: RoomEstimateOptions = {},
|
|
324
474
|
): RoomEstimateResult {
|
|
@@ -326,8 +476,9 @@ export function estimateRoom(
|
|
|
326
476
|
if (typeof module.estimateRoom !== 'function') {
|
|
327
477
|
throw new Error('libsonare was built without acoustic-simulation support');
|
|
328
478
|
}
|
|
329
|
-
|
|
330
|
-
|
|
479
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
480
|
+
validateAnalysisInput('estimateRoom', request.samples, request.sampleRate ?? 48000, request);
|
|
481
|
+
return module.estimateRoom(request.samples, request.sampleRate ?? 48000, request);
|
|
331
482
|
}
|
|
332
483
|
|
|
333
484
|
/**
|
|
@@ -335,17 +486,27 @@ export function estimateRoom(
|
|
|
335
486
|
* dereverberation). Returns the morphed samples (input length plus the target
|
|
336
487
|
* room's reverb tail).
|
|
337
488
|
*/
|
|
489
|
+
export function roomMorph(request: RoomMorphRequest): Float32Array;
|
|
338
490
|
export function roomMorph(
|
|
339
491
|
samples: Float32Array,
|
|
340
492
|
sampleRate: number,
|
|
493
|
+
options?: RoomMorphOptions,
|
|
494
|
+
): Float32Array;
|
|
495
|
+
export function roomMorph(
|
|
496
|
+
samples: Float32Array | RoomMorphRequest,
|
|
497
|
+
sampleRate?: number,
|
|
341
498
|
options: RoomMorphOptions = {},
|
|
342
499
|
): Float32Array {
|
|
343
500
|
const module = requireModule();
|
|
344
501
|
if (typeof module.roomMorph !== 'function') {
|
|
345
502
|
throw new Error('libsonare was built without acoustic-simulation support');
|
|
346
503
|
}
|
|
347
|
-
|
|
348
|
-
|
|
504
|
+
const request =
|
|
505
|
+
samples instanceof Float32Array
|
|
506
|
+
? { samples, sampleRate: sampleRate as number, ...options }
|
|
507
|
+
: samples;
|
|
508
|
+
validateAnalysisInput('roomMorph', request.samples, request.sampleRate, request);
|
|
509
|
+
return module.roomMorph(request.samples, request.sampleRate, request);
|
|
349
510
|
}
|
|
350
511
|
|
|
351
512
|
/**
|
|
@@ -356,13 +517,32 @@ export function roomMorph(
|
|
|
356
517
|
* @param onProgress - Progress callback (progress: 0-1, stage: string)
|
|
357
518
|
* @returns Complete analysis result
|
|
358
519
|
*/
|
|
520
|
+
export function analyzeWithProgress(request: AnalyzeWithProgressRequest): AnalysisResult;
|
|
359
521
|
export function analyzeWithProgress(
|
|
360
522
|
samples: Float32Array,
|
|
361
|
-
sampleRate
|
|
523
|
+
sampleRate: number | undefined,
|
|
362
524
|
onProgress: ProgressCallback,
|
|
525
|
+
): AnalysisResult;
|
|
526
|
+
export function analyzeWithProgress(
|
|
527
|
+
samples: Float32Array | AnalyzeWithProgressRequest,
|
|
528
|
+
sampleRate = 22050,
|
|
529
|
+
onProgress?: ProgressCallback,
|
|
363
530
|
): AnalysisResult {
|
|
364
|
-
|
|
365
|
-
|
|
531
|
+
const request: AnalyzeWithProgressRequest =
|
|
532
|
+
samples instanceof Float32Array
|
|
533
|
+
? { samples, sampleRate, onProgress: onProgress as ProgressCallback }
|
|
534
|
+
: samples;
|
|
535
|
+
validateAnalysisInput(
|
|
536
|
+
'analyzeWithProgress',
|
|
537
|
+
request.samples,
|
|
538
|
+
request.sampleRate ?? 22050,
|
|
539
|
+
request,
|
|
540
|
+
);
|
|
541
|
+
const result = requireModule().analyzeWithProgress(
|
|
542
|
+
request.samples,
|
|
543
|
+
request.sampleRate ?? 22050,
|
|
544
|
+
request.onProgress,
|
|
545
|
+
);
|
|
366
546
|
return convertAnalysisResult(result);
|
|
367
547
|
}
|
|
368
548
|
|
|
@@ -423,60 +603,81 @@ export interface TimbreAnalysisResult extends TimbreFrame {
|
|
|
423
603
|
* Detailed BPM analysis (BPM, confidence, alternate candidates, autocorrelation,
|
|
424
604
|
* tempogram). Matches the Node `analyzeBpm` / Python `analyze_bpm` surface.
|
|
425
605
|
*/
|
|
606
|
+
export function analyzeBpm(request: AnalyzeBpmRequest): BpmAnalysisResult;
|
|
426
607
|
export function analyzeBpm(
|
|
427
608
|
samples: Float32Array,
|
|
609
|
+
sampleRate?: number,
|
|
610
|
+
options?: AnalyzeBpmOptions,
|
|
611
|
+
): BpmAnalysisResult;
|
|
612
|
+
export function analyzeBpm(
|
|
613
|
+
samples: Float32Array | AnalyzeBpmRequest,
|
|
428
614
|
sampleRate = 22050,
|
|
429
615
|
options: AnalyzeBpmOptions = {},
|
|
430
616
|
): BpmAnalysisResult {
|
|
431
|
-
|
|
432
|
-
|
|
617
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
618
|
+
validateAnalysisInput('analyzeBpm', request.samples, request.sampleRate ?? 22050, request);
|
|
619
|
+
assertNonNegativeInteger('analyzeBpm', request.maxCandidates ?? 5, 'maxCandidates');
|
|
433
620
|
return requireModule().analyzeBpm(
|
|
434
|
-
samples,
|
|
435
|
-
sampleRate,
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
621
|
+
request.samples,
|
|
622
|
+
request.sampleRate ?? 22050,
|
|
623
|
+
request.bpmMin ?? 30.0,
|
|
624
|
+
request.bpmMax ?? 300.0,
|
|
625
|
+
request.startBpm ?? 120.0,
|
|
626
|
+
request.nFft ?? 2048,
|
|
627
|
+
request.hopLength ?? 512,
|
|
628
|
+
request.maxCandidates ?? 5,
|
|
442
629
|
);
|
|
443
630
|
}
|
|
444
631
|
|
|
445
632
|
/**
|
|
446
633
|
* Detailed rhythm analysis (time signature, groove, syncopation, beat intervals).
|
|
447
634
|
*/
|
|
635
|
+
export function analyzeRhythm(request: AnalyzeRhythmRequest): RhythmAnalysisResult;
|
|
448
636
|
export function analyzeRhythm(
|
|
449
637
|
samples: Float32Array,
|
|
638
|
+
sampleRate?: number,
|
|
639
|
+
options?: AnalyzeRhythmOptions,
|
|
640
|
+
): RhythmAnalysisResult;
|
|
641
|
+
export function analyzeRhythm(
|
|
642
|
+
samples: Float32Array | AnalyzeRhythmRequest,
|
|
450
643
|
sampleRate = 22050,
|
|
451
644
|
options: AnalyzeRhythmOptions = {},
|
|
452
645
|
): RhythmAnalysisResult {
|
|
453
|
-
|
|
646
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
647
|
+
validateAnalysisInput('analyzeRhythm', request.samples, request.sampleRate ?? 22050, request);
|
|
454
648
|
return requireModule().analyzeRhythm(
|
|
455
|
-
samples,
|
|
456
|
-
sampleRate,
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
649
|
+
request.samples,
|
|
650
|
+
request.sampleRate ?? 22050,
|
|
651
|
+
request.bpmMin ?? 60.0,
|
|
652
|
+
request.bpmMax ?? 200.0,
|
|
653
|
+
request.startBpm ?? 120.0,
|
|
654
|
+
request.nFft ?? 2048,
|
|
655
|
+
request.hopLength ?? 512,
|
|
462
656
|
);
|
|
463
657
|
}
|
|
464
658
|
|
|
465
659
|
/**
|
|
466
660
|
* Dynamics analysis (RMS, peak, crest factor, LRA, loudness curve).
|
|
467
661
|
*/
|
|
662
|
+
export function analyzeDynamics(request: AnalyzeDynamicsRequest): DynamicsAnalysisResult;
|
|
468
663
|
export function analyzeDynamics(
|
|
469
664
|
samples: Float32Array,
|
|
665
|
+
sampleRate?: number,
|
|
666
|
+
options?: AnalyzeDynamicsOptions,
|
|
667
|
+
): DynamicsAnalysisResult;
|
|
668
|
+
export function analyzeDynamics(
|
|
669
|
+
samples: Float32Array | AnalyzeDynamicsRequest,
|
|
470
670
|
sampleRate = 22050,
|
|
471
671
|
options: AnalyzeDynamicsOptions = {},
|
|
472
672
|
): DynamicsAnalysisResult {
|
|
473
|
-
|
|
673
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
674
|
+
validateAnalysisInput('analyzeDynamics', request.samples, request.sampleRate ?? 22050, request);
|
|
474
675
|
return requireModule().analyzeDynamics(
|
|
475
|
-
samples,
|
|
476
|
-
sampleRate,
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
676
|
+
request.samples,
|
|
677
|
+
request.sampleRate ?? 22050,
|
|
678
|
+
request.windowSec ?? 0.4,
|
|
679
|
+
request.hopLength ?? 512,
|
|
680
|
+
request.compressionThreshold ?? 6.0,
|
|
480
681
|
);
|
|
481
682
|
}
|
|
482
683
|
|
|
@@ -484,20 +685,27 @@ export function analyzeDynamics(
|
|
|
484
685
|
* Timbre analysis (brightness/warmth/density/roughness/complexity plus spectral
|
|
485
686
|
* features and per-window timbre frames).
|
|
486
687
|
*/
|
|
688
|
+
export function analyzeTimbre(request: AnalyzeTimbreRequest): TimbreAnalysisResult;
|
|
487
689
|
export function analyzeTimbre(
|
|
488
690
|
samples: Float32Array,
|
|
691
|
+
sampleRate?: number,
|
|
692
|
+
options?: AnalyzeTimbreOptions,
|
|
693
|
+
): TimbreAnalysisResult;
|
|
694
|
+
export function analyzeTimbre(
|
|
695
|
+
samples: Float32Array | AnalyzeTimbreRequest,
|
|
489
696
|
sampleRate = 22050,
|
|
490
697
|
options: AnalyzeTimbreOptions = {},
|
|
491
698
|
): TimbreAnalysisResult {
|
|
492
|
-
|
|
699
|
+
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
700
|
+
validateAnalysisInput('analyzeTimbre', request.samples, request.sampleRate ?? 22050, request);
|
|
493
701
|
return requireModule().analyzeTimbre(
|
|
494
|
-
samples,
|
|
495
|
-
sampleRate,
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
702
|
+
request.samples,
|
|
703
|
+
request.sampleRate ?? 22050,
|
|
704
|
+
request.nFft ?? 2048,
|
|
705
|
+
request.hopLength ?? 512,
|
|
706
|
+
request.nMels ?? 128,
|
|
707
|
+
request.nMfcc ?? 13,
|
|
708
|
+
request.windowSec ?? 0.5,
|
|
501
709
|
);
|
|
502
710
|
}
|
|
503
711
|
|