@libraz/libsonare 1.7.1 → 1.8.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.
- package/NOTICE +178 -0
- package/README.md +26 -170
- package/dist/_chain_config.d.ts +14 -0
- package/dist/_chain_config.d.ts.map +1 -0
- package/dist/_effects_common.d.ts +6 -0
- package/dist/_effects_common.d.ts.map +1 -0
- package/dist/_feature_validation.d.ts +8 -0
- package/dist/_feature_validation.d.ts.map +1 -0
- package/dist/_fft_options.d.ts +24 -0
- package/dist/_fft_options.d.ts.map +1 -0
- package/dist/align_take.d.ts +50 -0
- package/dist/align_take.d.ts.map +1 -0
- package/dist/analysis.d.ts +29 -5837
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +873 -722
- package/dist/analysis.js.map +1 -1
- package/dist/analysis_helpers.d.ts +9 -0
- package/dist/analysis_helpers.d.ts.map +1 -0
- package/dist/audio.d.ts +163 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/clip_page_streamer.d.ts +133 -0
- package/dist/clip_page_streamer.d.ts.map +1 -0
- package/dist/codes.d.ts +44 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/effects_mastering.d.ts +23 -0
- package/dist/effects_mastering.d.ts.map +1 -0
- package/dist/effects_note_ops.d.ts +477 -0
- package/dist/effects_note_ops.d.ts.map +1 -0
- package/dist/effects_percussive.d.ts +185 -0
- package/dist/effects_percussive.d.ts.map +1 -0
- package/dist/effects_separation.d.ts +65 -0
- package/dist/effects_separation.d.ts.map +1 -0
- package/dist/effects_spectral.d.ts +28 -0
- package/dist/effects_spectral.d.ts.map +1 -0
- package/dist/effects_timepitch.d.ts +129 -0
- package/dist/effects_timepitch.d.ts.map +1 -0
- package/dist/effects_voice_change.d.ts +53 -0
- package/dist/effects_voice_change.d.ts.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/feature_core.d.ts +341 -0
- package/dist/feature_core.d.ts.map +1 -0
- package/dist/feature_decompose.d.ts +278 -0
- package/dist/feature_decompose.d.ts.map +1 -0
- package/dist/feature_inverse.d.ts +128 -0
- package/dist/feature_inverse.d.ts.map +1 -0
- package/dist/feature_loudness.d.ts +66 -0
- package/dist/feature_loudness.d.ts.map +1 -0
- package/dist/feature_music.d.ts +307 -0
- package/dist/feature_music.d.ts.map +1 -0
- package/dist/feature_pitch.d.ts +108 -0
- package/dist/feature_pitch.d.ts.map +1 -0
- package/dist/feature_resample.d.ts +16 -0
- package/dist/feature_resample.d.ts.map +1 -0
- package/dist/feature_spectral.d.ts +137 -0
- package/dist/feature_spectral.d.ts.map +1 -0
- package/dist/feature_spectrogram.d.ts +198 -0
- package/dist/feature_spectrogram.d.ts.map +1 -0
- package/dist/features.d.ts +10 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/hrtf/default.shrf +0 -0
- package/dist/index.d.ts +74 -7329
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3816 -1359
- package/dist/index.js.map +1 -1
- package/dist/instrument_types.d.ts +517 -0
- package/dist/instrument_types.d.ts.map +1 -0
- package/dist/live_audio.d.ts +35 -0
- package/dist/live_audio.d.ts.map +1 -0
- package/dist/mastering_chain.d.ts +213 -0
- package/dist/mastering_chain.d.ts.map +1 -0
- package/dist/mastering_core.d.ts +457 -0
- package/dist/mastering_core.d.ts.map +1 -0
- package/dist/mastering_dynamics.d.ts +80 -0
- package/dist/mastering_dynamics.d.ts.map +1 -0
- package/dist/metering.d.ts +287 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/mixer.d.ts +464 -0
- package/dist/mixer.d.ts.map +1 -0
- package/dist/mixing_assistant.d.ts +62 -0
- package/dist/mixing_assistant.d.ts.map +1 -0
- package/dist/mixing_oneshot.d.ts +40 -0
- package/dist/mixing_oneshot.d.ts.map +1 -0
- package/dist/module_state.d.ts +15 -0
- package/dist/module_state.d.ts.map +1 -0
- package/dist/opfs_clip_pages.d.ts +28 -0
- package/dist/opfs_clip_pages.d.ts.map +1 -0
- package/dist/playback_renderer.d.ts +128 -0
- package/dist/playback_renderer.d.ts.map +1 -0
- package/dist/polyphony.d.ts +202 -0
- package/dist/polyphony.d.ts.map +1 -0
- package/dist/project.d.ts +8 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project_class.d.ts +562 -0
- package/dist/project_class.d.ts.map +1 -0
- package/dist/project_internal.d.ts +194 -0
- package/dist/project_internal.d.ts.map +1 -0
- package/dist/project_synth.d.ts +74 -0
- package/dist/project_synth.d.ts.map +1 -0
- package/dist/project_types.d.ts +652 -0
- package/dist/project_types.d.ts.map +1 -0
- package/dist/public_types.d.ts +185 -0
- package/dist/public_types.d.ts.map +1 -0
- package/dist/public_types_acoustic.d.ts +215 -0
- package/dist/public_types_acoustic.d.ts.map +1 -0
- package/dist/public_types_mastering.d.ts +510 -0
- package/dist/public_types_mastering.d.ts.map +1 -0
- package/dist/public_types_mixing.d.ts +436 -0
- package/dist/public_types_mixing.d.ts.map +1 -0
- package/dist/public_types_music.d.ts +619 -0
- package/dist/public_types_music.d.ts.map +1 -0
- package/dist/public_types_playback.d.ts +164 -0
- package/dist/public_types_playback.d.ts.map +1 -0
- package/dist/public_types_realtime.d.ts +174 -0
- package/dist/public_types_realtime.d.ts.map +1 -0
- package/dist/public_types_repair.d.ts +424 -0
- package/dist/public_types_repair.d.ts.map +1 -0
- package/dist/public_types_spectral.d.ts +697 -0
- package/dist/public_types_spectral.d.ts.map +1 -0
- package/dist/quick_analysis.d.ts +445 -0
- package/dist/quick_analysis.d.ts.map +1 -0
- package/dist/realtime_engine.d.ts +850 -0
- package/dist/realtime_engine.d.ts.map +1 -0
- package/dist/realtime_voice_changer.d.ts +158 -0
- package/dist/realtime_voice_changer.d.ts.map +1 -0
- package/dist/repair_dereverb.d.ts +187 -0
- package/dist/repair_dereverb.d.ts.map +1 -0
- package/dist/repair_impulsive.d.ts +186 -0
- package/dist/repair_impulsive.d.ts.map +1 -0
- package/dist/repair_noise.d.ts +239 -0
- package/dist/repair_noise.d.ts.map +1 -0
- package/dist/repair_trim.d.ts +123 -0
- package/dist/repair_trim.d.ts.map +1 -0
- package/dist/sample_bank.d.ts +84 -0
- package/dist/sample_bank.d.ts.map +1 -0
- package/dist/scale.d.ts +10 -0
- package/dist/scale.d.ts.map +1 -0
- package/dist/schemas/mixer-scene.schema.json +393 -0
- package/dist/schemas/playback-renderer-config.schema.json +392 -0
- package/dist/sonare-analysis.d.ts +8 -0
- package/dist/sonare-analysis.js +2 -2
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.d.ts +3909 -0
- package/dist/sonare.js +2 -2
- package/dist/sonare.wasm +0 -0
- package/dist/stream_analyzer.d.ts +163 -0
- package/dist/stream_analyzer.d.ts.map +1 -0
- package/dist/stream_types.d.ts +214 -0
- package/dist/stream_types.d.ts.map +1 -0
- package/dist/streaming_mixing.d.ts +6 -0
- package/dist/streaming_mixing.d.ts.map +1 -0
- package/dist/streaming_processors.d.ts +335 -0
- package/dist/streaming_processors.d.ts.map +1 -0
- package/dist/transcribe.d.ts +77 -0
- package/dist/transcribe.d.ts.map +1 -0
- package/dist/validation.d.ts +140 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/web_midi.d.ts +77 -0
- package/dist/web_midi.d.ts.map +1 -0
- package/dist/worker.d.ts +5 -48
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +94 -41
- package/dist/worker.js.map +1 -1
- package/dist/worker_client.d.ts +96 -0
- package/dist/worker_client.d.ts.map +1 -0
- package/dist/worker_protocol.d.ts +43 -0
- package/dist/worker_protocol.d.ts.map +1 -0
- package/dist/worklet/audio_types.d.ts +21 -0
- package/dist/worklet/audio_types.d.ts.map +1 -0
- package/dist/worklet/engine-automation.d.ts +29 -0
- package/dist/worklet/engine-automation.d.ts.map +1 -0
- package/dist/worklet/engine-capture-facade.d.ts +35 -0
- package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
- package/dist/worklet/engine-clips.d.ts +23 -0
- package/dist/worklet/engine-clips.d.ts.map +1 -0
- package/dist/worklet/engine-markers.d.ts +40 -0
- package/dist/worklet/engine-markers.d.ts.map +1 -0
- package/dist/worklet/engine-mixer-facade.d.ts +128 -0
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
- package/dist/worklet/engine-node.d.ts +81 -0
- package/dist/worklet/engine-node.d.ts.map +1 -0
- package/dist/worklet/engine-offline.d.ts +81 -0
- package/dist/worklet/engine-offline.d.ts.map +1 -0
- package/dist/worklet/engine-options.d.ts +12 -0
- package/dist/worklet/engine-options.d.ts.map +1 -0
- package/dist/worklet/engine-parameter-facade.d.ts +106 -0
- package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
- package/dist/worklet/engine-processor.d.ts +68 -0
- package/dist/worklet/engine-processor.d.ts.map +1 -0
- package/dist/worklet/engine-register.d.ts +2 -0
- package/dist/worklet/engine-register.d.ts.map +1 -0
- package/dist/worklet/engine-strips.d.ts +73 -0
- package/dist/worklet/engine-strips.d.ts.map +1 -0
- package/dist/worklet/engine-sync.d.ts +37 -0
- package/dist/worklet/engine-sync.d.ts.map +1 -0
- package/dist/worklet/engine-tempo-facade.d.ts +48 -0
- package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
- package/dist/worklet/engine.d.ts +397 -0
- package/dist/worklet/engine.d.ts.map +1 -0
- package/dist/worklet/guards.d.ts +47 -0
- package/dist/worklet/guards.d.ts.map +1 -0
- package/dist/worklet/messages.d.ts +710 -0
- package/dist/worklet/messages.d.ts.map +1 -0
- package/dist/worklet/mixer-processor.d.ts +46 -0
- package/dist/worklet/mixer-processor.d.ts.map +1 -0
- package/dist/worklet/playback-processor.d.ts +62 -0
- package/dist/worklet/playback-processor.d.ts.map +1 -0
- package/dist/worklet/protocol.d.ts +323 -0
- package/dist/worklet/protocol.d.ts.map +1 -0
- package/dist/worklet/voice-changer-processor.d.ts +41 -0
- package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
- package/dist/worklet.d.ts +16 -2142
- package/dist/worklet.d.ts.map +1 -0
- package/dist/worklet.js +2889 -466
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -12
- package/src/_effects_common.ts +17 -0
- package/src/_feature_validation.ts +34 -0
- package/src/_fft_options.ts +39 -0
- package/src/align_take.ts +64 -0
- package/src/analysis.ts +56 -3
- package/src/analysis_helpers.ts +7 -0
- package/src/audio.ts +106 -3
- package/src/codes.ts +39 -2
- package/src/effects_mastering.ts +97 -22
- package/src/effects_note_ops.ts +635 -0
- package/src/effects_percussive.ts +217 -0
- package/src/effects_separation.ts +150 -0
- package/src/effects_spectral.ts +60 -0
- package/src/effects_timepitch.ts +377 -0
- package/src/errors.ts +23 -1
- package/src/feature_core.ts +127 -2
- package/src/feature_decompose.ts +633 -0
- package/src/feature_inverse.ts +454 -0
- package/src/feature_loudness.ts +125 -0
- package/src/feature_music.ts +107 -14
- package/src/feature_pitch.ts +96 -1
- package/src/feature_spectral.ts +16 -611
- package/src/feature_spectrogram.ts +63 -450
- package/src/features.ts +36 -22
- package/src/index.ts +285 -30
- package/src/instrument_types.ts +645 -0
- package/src/live_audio.ts +27 -1
- package/src/mastering_chain.ts +184 -0
- package/src/mastering_core.ts +346 -32
- package/src/mastering_dynamics.ts +22 -11
- package/src/metering.ts +67 -24
- package/src/mixer.ts +212 -3
- package/src/mixing_assistant.ts +138 -0
- package/src/mixing_oneshot.ts +10 -5
- package/src/module_state.ts +24 -2
- package/src/playback_renderer.ts +252 -0
- package/src/polyphony.ts +279 -0
- package/src/project.ts +64 -24
- package/src/project_class.ts +502 -29
- package/src/project_internal.ts +151 -42
- package/src/project_synth.ts +67 -1
- package/src/project_types.ts +302 -270
- package/src/public_types.ts +122 -3
- package/src/public_types_acoustic.ts +112 -3
- package/src/public_types_mastering.ts +254 -73
- package/src/public_types_mixing.ts +363 -1
- package/src/public_types_music.ts +312 -2
- package/src/public_types_playback.ts +195 -0
- package/src/public_types_realtime.ts +39 -7
- package/src/public_types_repair.ts +446 -0
- package/src/public_types_spectral.ts +487 -1
- package/src/quick_analysis.ts +203 -26
- package/src/realtime_engine.ts +750 -28
- package/src/realtime_voice_changer.ts +55 -1
- package/src/repair_dereverb.ts +299 -0
- package/src/repair_impulsive.ts +395 -0
- package/src/repair_noise.ts +425 -0
- package/src/repair_trim.ts +226 -0
- package/src/sample_bank.ts +113 -0
- package/src/sonare.js.d.ts +1125 -30
- package/src/stream_analyzer.ts +36 -4
- package/src/stream_types.ts +37 -0
- package/src/streaming_mixing.ts +1 -1
- package/src/streaming_processors.ts +212 -10
- package/src/transcribe.ts +89 -0
- package/src/validation.ts +285 -11
- package/src/web_midi.ts +1 -6
- package/src/worker.ts +18 -2
- package/src/worklet/audio_types.ts +37 -0
- package/src/worklet/engine-mixer-facade.ts +444 -10
- package/src/worklet/engine-node.ts +85 -28
- package/src/worklet/engine-offline.ts +14 -8
- package/src/worklet/engine-parameter-facade.ts +21 -0
- package/src/worklet/engine-processor.ts +307 -71
- package/src/worklet/engine-register.ts +32 -18
- package/src/worklet/engine-strips.ts +280 -9
- package/src/worklet/engine-sync.ts +14 -6
- package/src/worklet/engine.ts +365 -31
- package/src/worklet/guards.ts +140 -44
- package/src/worklet/messages.ts +239 -2
- package/src/worklet/mixer-processor.ts +109 -47
- package/src/worklet/playback-processor.ts +300 -0
- package/src/worklet/protocol.ts +53 -3
- package/src/worklet/voice-changer-processor.ts +17 -11
- package/src/worklet.ts +22 -0
- package/src/effects_transform.ts +0 -718
- package/src/mastering_repair.ts +0 -273
package/src/feature_music.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { validatePositiveIntegers } from './_feature_validation';
|
|
2
|
+
import { resolveFftOptions } from './_fft_options';
|
|
1
3
|
import { ErrorCode, SonareError } from './errors';
|
|
2
4
|
import { getSonareModule } from './module_state';
|
|
3
5
|
import type {
|
|
4
6
|
AnalyzeSectionsOptions,
|
|
7
|
+
BoundaryOptions,
|
|
8
|
+
BoundaryResult,
|
|
5
9
|
CqtResult,
|
|
6
10
|
LufsResult,
|
|
7
11
|
MelodyResult,
|
|
@@ -16,6 +20,7 @@ import {
|
|
|
16
20
|
assertPositiveInteger,
|
|
17
21
|
assertSampleRate,
|
|
18
22
|
assertSamples,
|
|
23
|
+
assertVqtGamma,
|
|
19
24
|
} from './validation';
|
|
20
25
|
|
|
21
26
|
function requireModule() {
|
|
@@ -24,6 +29,7 @@ function requireModule() {
|
|
|
24
29
|
|
|
25
30
|
type GuardedOptions = ValidateOptions;
|
|
26
31
|
type AnalyzeSectionsGuardedOptions = AnalyzeSectionsOptions & ValidateOptions;
|
|
32
|
+
type BoundaryGuardedOptions = BoundaryOptions & ValidateOptions;
|
|
27
33
|
type MelodyGuardedOptions = MelodyOptions & ValidateOptions;
|
|
28
34
|
|
|
29
35
|
/** Canonical request form shared by the Constant-Q transform variants. */
|
|
@@ -89,6 +95,11 @@ export interface AnalyzeSectionsRequest extends AnalyzeSectionsGuardedOptions {
|
|
|
89
95
|
samples: Float32Array;
|
|
90
96
|
sampleRate?: number;
|
|
91
97
|
}
|
|
98
|
+
/** Canonical (and only) call form for {@link detectBoundaries}. */
|
|
99
|
+
export interface DetectBoundariesRequest extends BoundaryGuardedOptions {
|
|
100
|
+
samples: Float32Array;
|
|
101
|
+
sampleRate?: number;
|
|
102
|
+
}
|
|
92
103
|
export interface AnalyzeMelodyRequest extends MelodyGuardedOptions {
|
|
93
104
|
samples: Float32Array;
|
|
94
105
|
sampleRate?: number;
|
|
@@ -116,12 +127,6 @@ function validateMusicSamples(
|
|
|
116
127
|
assertSamples(fnName, samples, options.validate !== false);
|
|
117
128
|
}
|
|
118
129
|
|
|
119
|
-
function validatePositiveIntegers(fnName: string, values: Record<string, number>): void {
|
|
120
|
-
for (const [name, value] of Object.entries(values)) {
|
|
121
|
-
assertPositiveInteger(fnName, value, name);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
130
|
function validateFrequencyBounds(fnName: string, fmin: number, fmax?: number): void {
|
|
126
131
|
assertFiniteScalar(fnName, fmin, 'fmin');
|
|
127
132
|
if (fmin < 0) {
|
|
@@ -325,8 +330,8 @@ export function hybridCqt(
|
|
|
325
330
|
* @param fmin - Minimum frequency in Hz (default: 32.70319566257483, C1)
|
|
326
331
|
* @param nBins - Number of frequency bins (default: 84)
|
|
327
332
|
* @param binsPerOctave - Bins per octave (default: 12)
|
|
328
|
-
* @param gamma - Bandwidth offset; negative selects the automatic
|
|
329
|
-
* value, while 0 is equivalent to CQT (default: -1)
|
|
333
|
+
* @param gamma - Bandwidth offset; a negative value or NaN selects the automatic
|
|
334
|
+
* ERB-derived value, while 0 is equivalent to CQT (default: -1)
|
|
330
335
|
* @returns VQT magnitude result (same shape as CQT)
|
|
331
336
|
*/
|
|
332
337
|
export function vqt(request: VqtRequest): CqtResult;
|
|
@@ -366,7 +371,7 @@ export function vqt(
|
|
|
366
371
|
validateMusicSamples('vqt', samples, sampleRate, options);
|
|
367
372
|
validatePositiveIntegers('vqt', { hopLength, nBins, binsPerOctave });
|
|
368
373
|
validateFrequencyBounds('vqt', fmin);
|
|
369
|
-
|
|
374
|
+
assertVqtGamma('vqt', gamma);
|
|
370
375
|
return requireModule().vqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave, gamma);
|
|
371
376
|
}
|
|
372
377
|
|
|
@@ -512,7 +517,7 @@ export function vqtToAudio(
|
|
|
512
517
|
nIter,
|
|
513
518
|
options,
|
|
514
519
|
);
|
|
515
|
-
|
|
520
|
+
assertVqtGamma('vqtToAudio', gamma);
|
|
516
521
|
return requireModule().vqtToAudio(
|
|
517
522
|
magnitude,
|
|
518
523
|
nBins,
|
|
@@ -575,6 +580,85 @@ export function analyzeSections(
|
|
|
575
580
|
return Array.from(sections, (s) => ({ ...s, type: s.type as SectionType }));
|
|
576
581
|
}
|
|
577
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Detect structural boundaries and return the novelty curve behind them.
|
|
585
|
+
*
|
|
586
|
+
* This is the unlabelled layer {@link analyzeSections} is built on, not a
|
|
587
|
+
* coarser view of its output: sections are labelled spans, these are the
|
|
588
|
+
* transitions plus the continuous curve they were picked from, so a caller
|
|
589
|
+
* applying its own threshold needs this and cannot derive it from a section
|
|
590
|
+
* list.
|
|
591
|
+
*
|
|
592
|
+
* @param request - Samples, sample rate and {@link BoundaryOptions}
|
|
593
|
+
* @returns The boundaries, the novelty curve, and the analysis grid they live on
|
|
594
|
+
* @throws {@link SonareError} with `InvalidParameter` when both `useMfcc` and
|
|
595
|
+
* `useChroma` are `false`: the two feature streams are combined frame-for-frame,
|
|
596
|
+
* so with neither enabled there is nothing to combine.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* const { boundaries, noveltyCurve, noveltyPeak } = detectBoundaries({
|
|
601
|
+
* samples,
|
|
602
|
+
* sampleRate: 44100,
|
|
603
|
+
* absoluteThreshold: 0.01,
|
|
604
|
+
* });
|
|
605
|
+
* // `noveltyCurve` is scaled by its own maximum; recover the raw response with
|
|
606
|
+
* // `noveltyCurve[i] * noveltyPeak`.
|
|
607
|
+
* ```
|
|
608
|
+
*/
|
|
609
|
+
export function detectBoundaries(request: DetectBoundariesRequest): BoundaryResult {
|
|
610
|
+
const { samples, sampleRate = 22050 } = request;
|
|
611
|
+
validateMusicSamples('detectBoundaries', samples, sampleRate, request);
|
|
612
|
+
// The request IS the options bag: every field is read straight off it, so an
|
|
613
|
+
// omitted one reaches the embind wrapper absent and takes BoundaryConfig's own
|
|
614
|
+
// default. Restating the ten defaults here would make them the effective ones
|
|
615
|
+
// on npm and leave the core's unreachable, and nothing compares the two.
|
|
616
|
+
const sizes: Record<string, number> = {};
|
|
617
|
+
for (const name of ['nFft', 'hopLength', 'kernelSize', 'nMfcc', 'nChroma'] as const) {
|
|
618
|
+
const value = request[name];
|
|
619
|
+
if (value != null) {
|
|
620
|
+
sizes[name] = value;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
validatePositiveIntegers('detectBoundaries', sizes);
|
|
624
|
+
for (const name of ['threshold', 'absoluteThreshold', 'peakDistance'] as const) {
|
|
625
|
+
const value = request[name];
|
|
626
|
+
if (value == null) {
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
assertFiniteScalar('detectBoundaries', value, name);
|
|
630
|
+
if (value < 0) {
|
|
631
|
+
throw new RangeError(`detectBoundaries: ${name} must be non-negative`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
// Only an explicit pair of falses; either one omitted leaves the other stream
|
|
635
|
+
// on, so there is still something to combine.
|
|
636
|
+
if (request.useMfcc === false && request.useChroma === false) {
|
|
637
|
+
throw new SonareError(
|
|
638
|
+
ErrorCode.InvalidParameter,
|
|
639
|
+
'InvalidParameter',
|
|
640
|
+
'detectBoundaries: require useMfcc or useChroma',
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
const result = requireModule().detectBoundaries(samples, sampleRate, request);
|
|
644
|
+
// Re-root the embind array as a plain Array, for the reason analyzeSections
|
|
645
|
+
// spells out: chaining onto it propagates a constructor structuredClone
|
|
646
|
+
// rejects, so a result posted from a Worker would fail to clone.
|
|
647
|
+
return {
|
|
648
|
+
boundaries: Array.from(result.boundaries, (b) => ({
|
|
649
|
+
time: b.time,
|
|
650
|
+
frame: b.frame,
|
|
651
|
+
strength: b.strength,
|
|
652
|
+
})),
|
|
653
|
+
noveltyCurve: result.noveltyCurve,
|
|
654
|
+
noveltyPeak: result.noveltyPeak,
|
|
655
|
+
sampleRate: result.sampleRate,
|
|
656
|
+
hopLength: result.hopLength,
|
|
657
|
+
nFrames: result.nFrames,
|
|
658
|
+
frameStride: result.frameStride,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
|
|
578
662
|
/** Options for {@link analyzeMelody}. All fields are optional. */
|
|
579
663
|
export interface MelodyOptions {
|
|
580
664
|
/** Lowest f0 (Hz) the tracker will consider. Default 65 (≈ C2). */
|
|
@@ -703,8 +787,9 @@ export function onsetEnvelope(
|
|
|
703
787
|
);
|
|
704
788
|
}
|
|
705
789
|
validateMusicSamples('onsetEnvelope', samples, sampleRate, options);
|
|
706
|
-
|
|
707
|
-
|
|
790
|
+
const fft = resolveFftOptions('onsetEnvelope', nFft, hopLength);
|
|
791
|
+
validatePositiveIntegers('onsetEnvelope', { nMels });
|
|
792
|
+
return requireModule().onsetEnvelope(samples, sampleRate, fft.nFft, fft.hopLength, nMels);
|
|
708
793
|
}
|
|
709
794
|
|
|
710
795
|
/**
|
|
@@ -750,8 +835,16 @@ export function onsetStrengthMulti(
|
|
|
750
835
|
);
|
|
751
836
|
}
|
|
752
837
|
validateMusicSamples('onsetStrengthMulti', samples, sampleRate, options);
|
|
753
|
-
|
|
754
|
-
|
|
838
|
+
const fft = resolveFftOptions('onsetStrengthMulti', nFft, hopLength);
|
|
839
|
+
validatePositiveIntegers('onsetStrengthMulti', { nMels, nBands });
|
|
840
|
+
return requireModule().onsetStrengthMulti(
|
|
841
|
+
samples,
|
|
842
|
+
sampleRate,
|
|
843
|
+
fft.nFft,
|
|
844
|
+
fft.hopLength,
|
|
845
|
+
nMels,
|
|
846
|
+
nBands,
|
|
847
|
+
);
|
|
755
848
|
}
|
|
756
849
|
|
|
757
850
|
/**
|
package/src/feature_pitch.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SpectralFrameRequest } from './feature_spectral';
|
|
1
2
|
import { getSonareModule } from './module_state';
|
|
2
3
|
import type { NoteSegment, PiptrackResult, PitchResult } from './public_types';
|
|
3
4
|
|
|
@@ -188,23 +189,117 @@ export function pitchPyin(
|
|
|
188
189
|
/** Parameters for segmenting an F0 track into stable monophonic notes. */
|
|
189
190
|
export interface NoteSegmentsRequest {
|
|
190
191
|
f0Hz: Float32Array;
|
|
192
|
+
/**
|
|
193
|
+
* Per-frame voicing values in `[0, 1]`; anything below `voicedThreshold` is
|
|
194
|
+
* unvoiced.
|
|
195
|
+
*
|
|
196
|
+
* Pass {@link PitchResult.voicedFlag} converted to `0`/`1`. Do **not** pass
|
|
197
|
+
* {@link pitchPyin}'s `voicedProb`: that value is the frame's voiced
|
|
198
|
+
* observation mass and rises with F0 for a fixed `frameLength`, so a fixed
|
|
199
|
+
* threshold silently returns no segments at all for low-register material
|
|
200
|
+
* (a steady tone below roughly C5 never reaches 0.5).
|
|
201
|
+
*/
|
|
191
202
|
voicedProb: Float32Array;
|
|
192
203
|
frameRate: number;
|
|
204
|
+
/** Cents of pitch change that start a new segment. Default 50. */
|
|
193
205
|
segmentationThresholdCents?: number;
|
|
206
|
+
/** Shortest segment kept, in ms. Default 30. */
|
|
194
207
|
minNoteMs?: number;
|
|
208
|
+
/** Reference pitch each segment's cents are measured against. Default 440. */
|
|
195
209
|
referenceHz?: number;
|
|
210
|
+
/** Voicing threshold applied to `voicedProb`; defaults to `0.5`. */
|
|
211
|
+
voicedThreshold?: number;
|
|
196
212
|
}
|
|
197
213
|
|
|
198
214
|
/**
|
|
199
215
|
* Segment a caller-supplied monophonic F0 track into stable note regions.
|
|
200
216
|
*
|
|
201
217
|
* `f0Hz` and `voicedProb` must have the same non-zero length. Zero-Hz frames
|
|
202
|
-
* and
|
|
218
|
+
* and values below `voicedThreshold` (default `0.5`) are treated as unvoiced.
|
|
203
219
|
*/
|
|
204
220
|
export function noteSegments(request: NoteSegmentsRequest): NoteSegment[] {
|
|
205
221
|
return requireModule().noteSegments(request.f0Hz, request.voicedProb, request.frameRate, {
|
|
206
222
|
segmentationThresholdCents: request.segmentationThresholdCents,
|
|
207
223
|
minNoteMs: request.minNoteMs,
|
|
208
224
|
referenceHz: request.referenceHz,
|
|
225
|
+
voicedThreshold: request.voicedThreshold,
|
|
209
226
|
});
|
|
210
227
|
}
|
|
228
|
+
|
|
229
|
+
// ============================================================================
|
|
230
|
+
// Features - Tuning
|
|
231
|
+
// ============================================================================
|
|
232
|
+
|
|
233
|
+
export interface PitchTuningRequest {
|
|
234
|
+
frequencies: Float32Array;
|
|
235
|
+
resolution?: number;
|
|
236
|
+
binsPerOctave?: number;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface EstimateTuningRequest extends SpectralFrameRequest {
|
|
240
|
+
resolution?: number;
|
|
241
|
+
binsPerOctave?: number;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Estimate the global tuning offset from a set of frequencies
|
|
246
|
+
* (librosa.pitch_tuning). Returns a deviation in fractions of a bin.
|
|
247
|
+
*/
|
|
248
|
+
export function pitchTuning(request: PitchTuningRequest): number;
|
|
249
|
+
export function pitchTuning(
|
|
250
|
+
frequencies: Float32Array,
|
|
251
|
+
resolution?: number,
|
|
252
|
+
binsPerOctave?: number,
|
|
253
|
+
): number;
|
|
254
|
+
export function pitchTuning(
|
|
255
|
+
frequencies: Float32Array | PitchTuningRequest,
|
|
256
|
+
resolution = 0.01,
|
|
257
|
+
binsPerOctave = 12,
|
|
258
|
+
): number {
|
|
259
|
+
if (!(frequencies instanceof Float32Array)) {
|
|
260
|
+
const r = frequencies;
|
|
261
|
+
return pitchTuning(r.frequencies, r.resolution, r.binsPerOctave);
|
|
262
|
+
}
|
|
263
|
+
return requireModule().pitchTuning(frequencies, resolution, binsPerOctave);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Estimate the tuning offset of an audio signal (librosa.estimate_tuning).
|
|
268
|
+
*/
|
|
269
|
+
export function estimateTuning(request: EstimateTuningRequest): number;
|
|
270
|
+
export function estimateTuning(
|
|
271
|
+
samples: Float32Array,
|
|
272
|
+
sampleRate?: number,
|
|
273
|
+
nFft?: number,
|
|
274
|
+
hopLength?: number,
|
|
275
|
+
resolution?: number,
|
|
276
|
+
binsPerOctave?: number,
|
|
277
|
+
): number;
|
|
278
|
+
export function estimateTuning(
|
|
279
|
+
samples: Float32Array | EstimateTuningRequest,
|
|
280
|
+
sampleRate = 22050,
|
|
281
|
+
nFft = 2048,
|
|
282
|
+
hopLength = 512,
|
|
283
|
+
resolution = 0.01,
|
|
284
|
+
binsPerOctave = 12,
|
|
285
|
+
): number {
|
|
286
|
+
if (!(samples instanceof Float32Array)) {
|
|
287
|
+
const r = samples;
|
|
288
|
+
return estimateTuning(
|
|
289
|
+
r.samples,
|
|
290
|
+
r.sampleRate,
|
|
291
|
+
r.nFft,
|
|
292
|
+
r.hopLength,
|
|
293
|
+
r.resolution,
|
|
294
|
+
r.binsPerOctave,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return requireModule().estimateTuning(
|
|
298
|
+
samples,
|
|
299
|
+
sampleRate,
|
|
300
|
+
nFft,
|
|
301
|
+
hopLength,
|
|
302
|
+
resolution,
|
|
303
|
+
binsPerOctave,
|
|
304
|
+
);
|
|
305
|
+
}
|