@libraz/libsonare 1.5.5 → 1.6.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/README.md +109 -20
- package/dist/analysis.d.ts +5730 -0
- package/dist/analysis.js +2464 -0
- package/dist/analysis.js.map +1 -0
- package/dist/index.d.ts +759 -35
- package/dist/index.js +904 -209
- package/dist/index.js.map +1 -1
- package/dist/schemas/realtime-voice-changer-preset-pack.schema.json +27 -0
- package/dist/schemas/realtime-voice-changer-preset.schema.json +140 -0
- package/dist/sonare-analysis.js +2 -0
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worker.d.ts +65 -0
- package/dist/worker.js +707 -0
- package/dist/worker.js.map +1 -0
- package/dist/worklet.d.ts +574 -86
- package/dist/worklet.js +1634 -235
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -11
- package/src/_chain_config.ts +5 -3
- package/src/analysis.ts +137 -0
- package/src/analysis_helpers.ts +6 -0
- package/src/clip_page_streamer.ts +62 -8
- package/src/codes.ts +51 -64
- package/src/effects_mastering.ts +1 -0
- package/src/errors.ts +1 -0
- package/src/feature_core.ts +140 -2
- package/src/feature_music.ts +17 -2
- package/src/feature_pitch.ts +70 -1
- package/src/feature_spectral.ts +231 -5
- package/src/feature_spectrogram.ts +159 -0
- package/src/features.ts +16 -1
- package/src/index.ts +101 -7
- package/src/mastering_chain.ts +20 -8
- package/src/mastering_core.ts +5 -0
- package/src/mastering_dynamics.ts +7 -1
- package/src/metering.ts +6 -1
- package/src/opfs_clip_pages.ts +26 -1
- package/src/project.ts +7 -0
- package/src/project_class.ts +62 -8
- package/src/project_internal.ts +24 -29
- package/src/project_types.ts +69 -10
- package/src/public_types.ts +68 -0
- package/src/public_types_mastering.ts +22 -0
- package/src/public_types_mixing.ts +11 -2
- package/src/public_types_music.ts +9 -0
- package/src/public_types_spectral.ts +33 -0
- package/src/quick_analysis.ts +25 -7
- package/src/realtime_engine.ts +153 -3
- package/src/realtime_voice_changer.ts +51 -77
- package/src/sonare-analysis.js.d.ts +8 -0
- package/src/sonare.js.d.ts +276 -6
- package/src/streaming_processors.ts +15 -0
- package/src/web_midi.ts +36 -4
- package/src/worker.ts +196 -0
- package/src/worker_client.ts +352 -0
- package/src/worker_protocol.ts +59 -0
- package/src/worklet/engine-automation.ts +2 -1
- package/src/worklet/engine-capture-facade.ts +13 -4
- package/src/worklet/engine-clips.ts +12 -3
- package/src/worklet/engine-node.ts +212 -4
- package/src/worklet/engine-offline.ts +7 -2
- package/src/worklet/engine-parameter-facade.ts +26 -5
- package/src/worklet/engine-processor.ts +383 -42
- package/src/worklet/engine-register.ts +8 -0
- package/src/worklet/engine-strips.ts +17 -1
- package/src/worklet/engine-sync.ts +2 -6
- package/src/worklet/engine-tempo-facade.ts +8 -6
- package/src/worklet/engine.ts +380 -13
- package/src/worklet/guards.ts +22 -1
- package/src/worklet/messages.ts +125 -7
- package/src/worklet/protocol.ts +301 -17
- package/src/worklet/voice-changer-processor.ts +12 -15
- package/src/worklet.ts +20 -1
package/src/feature_core.ts
CHANGED
|
@@ -11,6 +11,85 @@ function requireModule() {
|
|
|
11
11
|
return getSonareModule();
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export function tone(request?: ToneRequest): Float32Array;
|
|
15
|
+
export function tone(
|
|
16
|
+
frequency?: number,
|
|
17
|
+
sampleRate?: number,
|
|
18
|
+
duration?: number,
|
|
19
|
+
phase?: number,
|
|
20
|
+
amplitude?: number,
|
|
21
|
+
): Float32Array;
|
|
22
|
+
export function tone(
|
|
23
|
+
frequency: number | ToneRequest = 440,
|
|
24
|
+
sampleRate = 22050,
|
|
25
|
+
duration = 1,
|
|
26
|
+
phase = 0,
|
|
27
|
+
amplitude = 1,
|
|
28
|
+
): Float32Array {
|
|
29
|
+
const request =
|
|
30
|
+
typeof frequency === 'number'
|
|
31
|
+
? { frequency, sampleRate, duration, phase, amplitude }
|
|
32
|
+
: frequency;
|
|
33
|
+
return requireModule().tone(
|
|
34
|
+
request.frequency ?? 440,
|
|
35
|
+
request.sampleRate ?? 22050,
|
|
36
|
+
request.duration ?? 1,
|
|
37
|
+
request.phase ?? 0,
|
|
38
|
+
request.amplitude ?? 1,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function chirp(request?: ChirpRequest): Float32Array;
|
|
43
|
+
export function chirp(
|
|
44
|
+
fmin?: number,
|
|
45
|
+
fmax?: number,
|
|
46
|
+
sampleRate?: number,
|
|
47
|
+
duration?: number,
|
|
48
|
+
linear?: boolean,
|
|
49
|
+
): Float32Array;
|
|
50
|
+
export function chirp(
|
|
51
|
+
fmin: number | ChirpRequest = 440,
|
|
52
|
+
fmax = 880,
|
|
53
|
+
sampleRate = 22050,
|
|
54
|
+
duration = 1,
|
|
55
|
+
linear = true,
|
|
56
|
+
): Float32Array {
|
|
57
|
+
const request = typeof fmin === 'number' ? { fmin, fmax, sampleRate, duration, linear } : fmin;
|
|
58
|
+
return requireModule().chirp(
|
|
59
|
+
request.fmin ?? 440,
|
|
60
|
+
request.fmax ?? 880,
|
|
61
|
+
request.sampleRate ?? 22050,
|
|
62
|
+
request.duration ?? 1,
|
|
63
|
+
request.linear ?? true,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function clicks(request: ClicksRequest): Float32Array;
|
|
68
|
+
export function clicks(
|
|
69
|
+
times: Float32Array,
|
|
70
|
+
sampleRate?: number,
|
|
71
|
+
length?: number,
|
|
72
|
+
frequency?: number,
|
|
73
|
+
clickDuration?: number,
|
|
74
|
+
): Float32Array;
|
|
75
|
+
export function clicks(
|
|
76
|
+
times: Float32Array | ClicksRequest,
|
|
77
|
+
sampleRate = 22050,
|
|
78
|
+
length = 0,
|
|
79
|
+
frequency = 1000,
|
|
80
|
+
clickDuration = 0.1,
|
|
81
|
+
): Float32Array {
|
|
82
|
+
const request =
|
|
83
|
+
times instanceof Float32Array ? { times, sampleRate, length, frequency, clickDuration } : times;
|
|
84
|
+
return requireModule().clicks(
|
|
85
|
+
request.times,
|
|
86
|
+
request.sampleRate ?? 22050,
|
|
87
|
+
request.length ?? 0,
|
|
88
|
+
request.frequency ?? 1000,
|
|
89
|
+
request.clickDuration ?? 0.1,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
14
93
|
export interface DbConversionRequest {
|
|
15
94
|
values: Float32Array;
|
|
16
95
|
ref?: number;
|
|
@@ -30,6 +109,27 @@ export interface FrameSignalRequest {
|
|
|
30
109
|
frameLength: number;
|
|
31
110
|
hopLength: number;
|
|
32
111
|
}
|
|
112
|
+
export interface ToneRequest {
|
|
113
|
+
frequency?: number;
|
|
114
|
+
sampleRate?: number;
|
|
115
|
+
duration?: number;
|
|
116
|
+
phase?: number;
|
|
117
|
+
amplitude?: number;
|
|
118
|
+
}
|
|
119
|
+
export interface ChirpRequest {
|
|
120
|
+
fmin?: number;
|
|
121
|
+
fmax?: number;
|
|
122
|
+
sampleRate?: number;
|
|
123
|
+
duration?: number;
|
|
124
|
+
linear?: boolean;
|
|
125
|
+
}
|
|
126
|
+
export interface ClicksRequest {
|
|
127
|
+
times: Float32Array;
|
|
128
|
+
sampleRate?: number;
|
|
129
|
+
length?: number;
|
|
130
|
+
frequency?: number;
|
|
131
|
+
clickDuration?: number;
|
|
132
|
+
}
|
|
33
133
|
/** Canonical request form for pre/de-emphasis filters. */
|
|
34
134
|
export interface EmphasisRequest {
|
|
35
135
|
samples: Float32Array;
|
|
@@ -55,6 +155,10 @@ export interface FixFramesRequest {
|
|
|
55
155
|
xMax?: number;
|
|
56
156
|
pad?: boolean;
|
|
57
157
|
}
|
|
158
|
+
export interface OnsetBacktrackRequest {
|
|
159
|
+
events: Int32Array;
|
|
160
|
+
energy: Float32Array;
|
|
161
|
+
}
|
|
58
162
|
/** Canonical request form for peak selection. */
|
|
59
163
|
export interface PeakPickRequest {
|
|
60
164
|
values: Float32Array;
|
|
@@ -97,6 +201,8 @@ export interface TempogramRequest {
|
|
|
97
201
|
hopLength?: number;
|
|
98
202
|
winLength?: number;
|
|
99
203
|
mode?: TempogramMode;
|
|
204
|
+
center?: boolean;
|
|
205
|
+
norm?: boolean;
|
|
100
206
|
}
|
|
101
207
|
export interface CyclicTempogramRequest {
|
|
102
208
|
onsetEnvelope: Float32Array;
|
|
@@ -391,6 +497,18 @@ export function fixFrames(
|
|
|
391
497
|
return requireModule().fixFrames(frames, xMin, xMax, pad);
|
|
392
498
|
}
|
|
393
499
|
|
|
500
|
+
export function onsetBacktrack(request: OnsetBacktrackRequest): Int32Array;
|
|
501
|
+
export function onsetBacktrack(events: Int32Array, energy: Float32Array): Int32Array;
|
|
502
|
+
export function onsetBacktrack(
|
|
503
|
+
events: Int32Array | OnsetBacktrackRequest,
|
|
504
|
+
energy?: Float32Array,
|
|
505
|
+
): Int32Array {
|
|
506
|
+
if (!(events instanceof Int32Array)) {
|
|
507
|
+
return onsetBacktrack(events.events, events.energy);
|
|
508
|
+
}
|
|
509
|
+
return requireModule().onsetBacktrack(events, energy as Float32Array);
|
|
510
|
+
}
|
|
511
|
+
|
|
394
512
|
export function peakPick(request: PeakPickRequest): Int32Array;
|
|
395
513
|
export function peakPick(
|
|
396
514
|
values: Float32Array,
|
|
@@ -492,6 +610,8 @@ export function tempogram(
|
|
|
492
610
|
hopLength?: number,
|
|
493
611
|
winLength?: number,
|
|
494
612
|
mode?: TempogramMode,
|
|
613
|
+
center?: boolean,
|
|
614
|
+
norm?: boolean,
|
|
495
615
|
): WasmTempogramResult;
|
|
496
616
|
export function tempogram(
|
|
497
617
|
onsetEnvelope: Float32Array | TempogramRequest,
|
|
@@ -499,12 +619,30 @@ export function tempogram(
|
|
|
499
619
|
hopLength = 512,
|
|
500
620
|
winLength = 384,
|
|
501
621
|
mode: TempogramMode = 'autocorrelation',
|
|
622
|
+
center = true,
|
|
623
|
+
norm = true,
|
|
502
624
|
): WasmTempogramResult {
|
|
503
625
|
if (!(onsetEnvelope instanceof Float32Array)) {
|
|
504
626
|
const r = onsetEnvelope;
|
|
505
|
-
return tempogram(
|
|
627
|
+
return tempogram(
|
|
628
|
+
r.onsetEnvelope,
|
|
629
|
+
r.sampleRate,
|
|
630
|
+
r.hopLength,
|
|
631
|
+
r.winLength,
|
|
632
|
+
r.mode,
|
|
633
|
+
r.center,
|
|
634
|
+
r.norm,
|
|
635
|
+
);
|
|
506
636
|
}
|
|
507
|
-
return requireModule().tempogram(
|
|
637
|
+
return requireModule().tempogram(
|
|
638
|
+
onsetEnvelope,
|
|
639
|
+
sampleRate,
|
|
640
|
+
hopLength,
|
|
641
|
+
winLength,
|
|
642
|
+
mode,
|
|
643
|
+
center,
|
|
644
|
+
norm,
|
|
645
|
+
);
|
|
508
646
|
}
|
|
509
647
|
|
|
510
648
|
export function cyclicTempogram(request: CyclicTempogramRequest): WasmCyclicTempogramResult;
|
package/src/feature_music.ts
CHANGED
|
@@ -58,6 +58,8 @@ export interface FourierTempogramRequest extends GuardedOptions {
|
|
|
58
58
|
sampleRate?: number;
|
|
59
59
|
hopLength?: number;
|
|
60
60
|
winLength?: number;
|
|
61
|
+
center?: boolean;
|
|
62
|
+
norm?: boolean;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export interface TempogramRatioRequest extends GuardedOptions {
|
|
@@ -584,7 +586,7 @@ export interface MelodyOptions {
|
|
|
584
586
|
*/
|
|
585
587
|
usePyin?: boolean;
|
|
586
588
|
/**
|
|
587
|
-
* When {@link usePyin} is `true`,
|
|
589
|
+
* When {@link usePyin} is `true`, zero-pad by `frameLength / 2` so frame
|
|
588
590
|
* `i` is centered at `i * hopLength` (matches `librosa.pyin(center=True)`).
|
|
589
591
|
* Ignored by the plain-YIN path. Defaults to `true`.
|
|
590
592
|
*/
|
|
@@ -760,6 +762,8 @@ export function fourierTempogram(
|
|
|
760
762
|
sampleRate?: number,
|
|
761
763
|
hopLength?: number,
|
|
762
764
|
winLength?: number,
|
|
765
|
+
center?: boolean,
|
|
766
|
+
norm?: boolean,
|
|
763
767
|
options?: GuardedOptions,
|
|
764
768
|
): WasmFourierTempogramResult;
|
|
765
769
|
export function fourierTempogram(
|
|
@@ -767,6 +771,8 @@ export function fourierTempogram(
|
|
|
767
771
|
sampleRate = 22050,
|
|
768
772
|
hopLength = 512,
|
|
769
773
|
winLength = 384,
|
|
774
|
+
center = true,
|
|
775
|
+
norm = true,
|
|
770
776
|
options: GuardedOptions = {},
|
|
771
777
|
): WasmFourierTempogramResult {
|
|
772
778
|
if (!(onsetEnvelope instanceof Float32Array)) {
|
|
@@ -776,13 +782,22 @@ export function fourierTempogram(
|
|
|
776
782
|
request.sampleRate,
|
|
777
783
|
request.hopLength,
|
|
778
784
|
request.winLength,
|
|
785
|
+
request.center,
|
|
786
|
+
request.norm,
|
|
779
787
|
request,
|
|
780
788
|
);
|
|
781
789
|
}
|
|
782
790
|
assertSampleRate('fourierTempogram', sampleRate);
|
|
783
791
|
assertSamples('fourierTempogram', onsetEnvelope, options.validate !== false, 'onsetEnvelope');
|
|
784
792
|
validatePositiveIntegers('fourierTempogram', { hopLength, winLength });
|
|
785
|
-
return requireModule().fourierTempogram(
|
|
793
|
+
return requireModule().fourierTempogram(
|
|
794
|
+
onsetEnvelope,
|
|
795
|
+
sampleRate,
|
|
796
|
+
hopLength,
|
|
797
|
+
winLength,
|
|
798
|
+
center,
|
|
799
|
+
norm,
|
|
800
|
+
);
|
|
786
801
|
}
|
|
787
802
|
|
|
788
803
|
/**
|
package/src/feature_pitch.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSonareModule } from './module_state';
|
|
2
|
-
import type { PitchResult } from './public_types';
|
|
2
|
+
import type { NoteSegment, PiptrackResult, PitchResult } from './public_types';
|
|
3
3
|
|
|
4
4
|
function requireModule() {
|
|
5
5
|
return getSonareModule();
|
|
@@ -33,6 +33,51 @@ export interface PitchYinRequest {
|
|
|
33
33
|
fillNa?: boolean;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface PiptrackRequest {
|
|
37
|
+
samples: Float32Array;
|
|
38
|
+
sampleRate?: number;
|
|
39
|
+
nFft?: number;
|
|
40
|
+
hopLength?: number;
|
|
41
|
+
fmin?: number;
|
|
42
|
+
fmax?: number;
|
|
43
|
+
threshold?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Per-bin spectral pitch candidates and peak magnitudes (librosa.piptrack). */
|
|
47
|
+
export function piptrack(request: PiptrackRequest): PiptrackResult;
|
|
48
|
+
export function piptrack(
|
|
49
|
+
samples: Float32Array,
|
|
50
|
+
sampleRate?: number,
|
|
51
|
+
nFft?: number,
|
|
52
|
+
hopLength?: number,
|
|
53
|
+
fmin?: number,
|
|
54
|
+
fmax?: number,
|
|
55
|
+
threshold?: number,
|
|
56
|
+
): PiptrackResult;
|
|
57
|
+
export function piptrack(
|
|
58
|
+
samples: Float32Array | PiptrackRequest,
|
|
59
|
+
sampleRate = 22050,
|
|
60
|
+
nFft = 2048,
|
|
61
|
+
hopLength = 512,
|
|
62
|
+
fmin = 150,
|
|
63
|
+
fmax = 4000,
|
|
64
|
+
threshold = 0.1,
|
|
65
|
+
): PiptrackResult {
|
|
66
|
+
if (!(samples instanceof Float32Array)) {
|
|
67
|
+
const request = samples;
|
|
68
|
+
return piptrack(
|
|
69
|
+
request.samples,
|
|
70
|
+
request.sampleRate,
|
|
71
|
+
request.nFft,
|
|
72
|
+
request.hopLength,
|
|
73
|
+
request.fmin,
|
|
74
|
+
request.fmax,
|
|
75
|
+
request.threshold,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return requireModule().piptrack(samples, sampleRate, nFft, hopLength, fmin, fmax, threshold);
|
|
79
|
+
}
|
|
80
|
+
|
|
36
81
|
export function pitchYin(request: PitchYinRequest): PitchResult;
|
|
37
82
|
export function pitchYin(
|
|
38
83
|
samples: Float32Array,
|
|
@@ -139,3 +184,27 @@ export function pitchPyin(
|
|
|
139
184
|
fillNa,
|
|
140
185
|
);
|
|
141
186
|
}
|
|
187
|
+
|
|
188
|
+
/** Parameters for segmenting an F0 track into stable monophonic notes. */
|
|
189
|
+
export interface NoteSegmentsRequest {
|
|
190
|
+
f0Hz: Float32Array;
|
|
191
|
+
voicedProb: Float32Array;
|
|
192
|
+
frameRate: number;
|
|
193
|
+
segmentationThresholdCents?: number;
|
|
194
|
+
minNoteMs?: number;
|
|
195
|
+
referenceHz?: number;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Segment a caller-supplied monophonic F0 track into stable note regions.
|
|
200
|
+
*
|
|
201
|
+
* `f0Hz` and `voicedProb` must have the same non-zero length. Zero-Hz frames
|
|
202
|
+
* and probabilities below 0.5 are treated as unvoiced.
|
|
203
|
+
*/
|
|
204
|
+
export function noteSegments(request: NoteSegmentsRequest): NoteSegment[] {
|
|
205
|
+
return requireModule().noteSegments(request.f0Hz, request.voicedProb, request.frameRate, {
|
|
206
|
+
segmentationThresholdCents: request.segmentationThresholdCents,
|
|
207
|
+
minNoteMs: request.minNoteMs,
|
|
208
|
+
referenceHz: request.referenceHz,
|
|
209
|
+
});
|
|
210
|
+
}
|
package/src/feature_spectral.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSonareModule } from './module_state';
|
|
2
|
+
import type { SegmentMatrix } from './public_types';
|
|
2
3
|
import type {
|
|
3
4
|
WasmDecomposeResult,
|
|
4
5
|
WasmHpssWithResidualResult,
|
|
@@ -6,7 +7,13 @@ import type {
|
|
|
6
7
|
WasmMatrix2dResult,
|
|
7
8
|
} from './sonare.js';
|
|
8
9
|
import type { ValidateOptions } from './validation';
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
assertInterleavedSamples,
|
|
12
|
+
assertNonNegativeInteger,
|
|
13
|
+
assertPositiveInteger,
|
|
14
|
+
assertSampleRate,
|
|
15
|
+
assertSamples,
|
|
16
|
+
} from './validation';
|
|
10
17
|
|
|
11
18
|
function requireModule() {
|
|
12
19
|
return getSonareModule();
|
|
@@ -76,6 +83,75 @@ export interface NnFilterRequest {
|
|
|
76
83
|
k?: number;
|
|
77
84
|
width?: number;
|
|
78
85
|
}
|
|
86
|
+
export interface SegmentCrossSimilarityRequest {
|
|
87
|
+
x: Float32Array;
|
|
88
|
+
xRows: number;
|
|
89
|
+
xCols: number;
|
|
90
|
+
y: Float32Array;
|
|
91
|
+
yRows: number;
|
|
92
|
+
yCols: number;
|
|
93
|
+
k?: number;
|
|
94
|
+
metric?: 'cosine' | 'euclidean';
|
|
95
|
+
mode?: 'connectivity' | 'affinity';
|
|
96
|
+
}
|
|
97
|
+
export interface SegmentRecurrenceMatrixRequest {
|
|
98
|
+
data: Float32Array;
|
|
99
|
+
rows: number;
|
|
100
|
+
cols: number;
|
|
101
|
+
k?: number;
|
|
102
|
+
width?: number;
|
|
103
|
+
sym?: boolean;
|
|
104
|
+
metric?: 'cosine' | 'euclidean';
|
|
105
|
+
mode?: 'connectivity' | 'affinity';
|
|
106
|
+
}
|
|
107
|
+
export interface SegmentRecurrenceToLagRequest {
|
|
108
|
+
recurrence: Float32Array;
|
|
109
|
+
n: number;
|
|
110
|
+
pad?: boolean;
|
|
111
|
+
}
|
|
112
|
+
export interface SegmentLagToRecurrenceRequest {
|
|
113
|
+
lag: Float32Array;
|
|
114
|
+
rows: number;
|
|
115
|
+
lags: number;
|
|
116
|
+
}
|
|
117
|
+
export interface SegmentSubsegmentRequest {
|
|
118
|
+
data: Float32Array;
|
|
119
|
+
rows: number;
|
|
120
|
+
cols: number;
|
|
121
|
+
boundaries: Int32Array;
|
|
122
|
+
nSegments?: number;
|
|
123
|
+
}
|
|
124
|
+
export interface SegmentAgglomerativeRequest {
|
|
125
|
+
data: Float32Array;
|
|
126
|
+
rows: number;
|
|
127
|
+
cols: number;
|
|
128
|
+
k: number;
|
|
129
|
+
linkage?: 'average' | 'single' | 'complete' | 'ward';
|
|
130
|
+
}
|
|
131
|
+
export interface SegmentPathEnhanceRequest {
|
|
132
|
+
recurrence: Float32Array;
|
|
133
|
+
n: number;
|
|
134
|
+
win: number;
|
|
135
|
+
maxRatio?: number;
|
|
136
|
+
minRatio?: number;
|
|
137
|
+
nFilters?: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function validateSegmentMatrix(
|
|
141
|
+
fnName: string,
|
|
142
|
+
data: Float32Array,
|
|
143
|
+
rows: number,
|
|
144
|
+
cols: number,
|
|
145
|
+
dataName: string,
|
|
146
|
+
): void {
|
|
147
|
+
assertPositiveInteger(fnName, rows, 'rows');
|
|
148
|
+
assertPositiveInteger(fnName, cols, 'cols');
|
|
149
|
+
assertSamples(fnName, data, true, dataName);
|
|
150
|
+
const expected = rows * cols;
|
|
151
|
+
if (!Number.isSafeInteger(expected) || data.length !== expected) {
|
|
152
|
+
throw new RangeError(`${fnName}: ${dataName} length must equal rows * cols`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
79
155
|
export interface RemixRequest {
|
|
80
156
|
samples: Float32Array;
|
|
81
157
|
intervals: Int32Array | ArrayLike<number>;
|
|
@@ -537,23 +613,31 @@ export function ebur128LoudnessRange(
|
|
|
537
613
|
* @param hopLength - Hop length (default: 512)
|
|
538
614
|
* @returns Spectral bandwidth in Hz for each frame
|
|
539
615
|
*/
|
|
540
|
-
export function spectralBandwidth(request: SpectralFrameRequest): Float32Array;
|
|
616
|
+
export function spectralBandwidth(request: SpectralFrameRequest & { p?: number }): Float32Array;
|
|
541
617
|
export function spectralBandwidth(
|
|
542
618
|
samples: Float32Array,
|
|
543
619
|
sampleRate?: number,
|
|
544
620
|
nFft?: number,
|
|
545
621
|
hopLength?: number,
|
|
622
|
+
p?: number,
|
|
546
623
|
): Float32Array;
|
|
547
624
|
export function spectralBandwidth(
|
|
548
|
-
samples: Float32Array | SpectralFrameRequest,
|
|
625
|
+
samples: Float32Array | (SpectralFrameRequest & { p?: number }),
|
|
549
626
|
sampleRate = 22050,
|
|
550
627
|
nFft = 2048,
|
|
551
628
|
hopLength = 512,
|
|
629
|
+
p = 2,
|
|
552
630
|
): Float32Array {
|
|
553
631
|
if (!(samples instanceof Float32Array)) {
|
|
554
|
-
return spectralBandwidth(
|
|
632
|
+
return spectralBandwidth(
|
|
633
|
+
samples.samples,
|
|
634
|
+
samples.sampleRate,
|
|
635
|
+
samples.nFft,
|
|
636
|
+
samples.hopLength,
|
|
637
|
+
samples.p,
|
|
638
|
+
);
|
|
555
639
|
}
|
|
556
|
-
return requireModule().spectralBandwidth(samples, sampleRate, nFft, hopLength);
|
|
640
|
+
return requireModule().spectralBandwidth(samples, sampleRate, nFft, hopLength, p);
|
|
557
641
|
}
|
|
558
642
|
|
|
559
643
|
/**
|
|
@@ -621,6 +705,33 @@ export function spectralFlatness(
|
|
|
621
705
|
return requireModule().spectralFlatness(samples, sampleRate, nFft, hopLength);
|
|
622
706
|
}
|
|
623
707
|
|
|
708
|
+
export function spectralFlux(request: SpectralFrameRequest & { lag?: number }): Float32Array;
|
|
709
|
+
export function spectralFlux(
|
|
710
|
+
samples: Float32Array,
|
|
711
|
+
sampleRate?: number,
|
|
712
|
+
nFft?: number,
|
|
713
|
+
hopLength?: number,
|
|
714
|
+
lag?: number,
|
|
715
|
+
): Float32Array;
|
|
716
|
+
export function spectralFlux(
|
|
717
|
+
samples: Float32Array | (SpectralFrameRequest & { lag?: number }),
|
|
718
|
+
sampleRate = 22050,
|
|
719
|
+
nFft = 2048,
|
|
720
|
+
hopLength = 512,
|
|
721
|
+
lag = 1,
|
|
722
|
+
): Float32Array {
|
|
723
|
+
if (!(samples instanceof Float32Array)) {
|
|
724
|
+
return spectralFlux(
|
|
725
|
+
samples.samples,
|
|
726
|
+
samples.sampleRate,
|
|
727
|
+
samples.nFft,
|
|
728
|
+
samples.hopLength,
|
|
729
|
+
samples.lag,
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
return requireModule().spectralFlux(samples, sampleRate, nFft, hopLength, lag);
|
|
733
|
+
}
|
|
734
|
+
|
|
624
735
|
/**
|
|
625
736
|
* Compute zero crossing rate.
|
|
626
737
|
*
|
|
@@ -681,3 +792,118 @@ export function rmsEnergy(
|
|
|
681
792
|
}
|
|
682
793
|
return requireModule().rmsEnergy(samples, sampleRate, frameLength, hopLength);
|
|
683
794
|
}
|
|
795
|
+
|
|
796
|
+
/** Column-wise cross-similarity (librosa.segment.cross_similarity). */
|
|
797
|
+
export function segmentCrossSimilarity(request: SegmentCrossSimilarityRequest): SegmentMatrix {
|
|
798
|
+
validateSegmentMatrix('segmentCrossSimilarity', request.x, request.xRows, request.xCols, 'x');
|
|
799
|
+
validateSegmentMatrix('segmentCrossSimilarity', request.y, request.yRows, request.yCols, 'y');
|
|
800
|
+
if (request.xRows !== request.yRows) {
|
|
801
|
+
throw new RangeError('segmentCrossSimilarity: feature dimensions must match');
|
|
802
|
+
}
|
|
803
|
+
assertNonNegativeInteger('segmentCrossSimilarity', request.k ?? 0, 'k');
|
|
804
|
+
return requireModule().segmentCrossSimilarity(
|
|
805
|
+
request.x,
|
|
806
|
+
request.xRows,
|
|
807
|
+
request.xCols,
|
|
808
|
+
request.y,
|
|
809
|
+
request.yRows,
|
|
810
|
+
request.yCols,
|
|
811
|
+
request.k ?? 0,
|
|
812
|
+
request.metric ?? 'cosine',
|
|
813
|
+
request.mode ?? 'connectivity',
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/** Self-similarity recurrence matrix (librosa.segment.recurrence_matrix). */
|
|
818
|
+
export function segmentRecurrenceMatrix(request: SegmentRecurrenceMatrixRequest): SegmentMatrix {
|
|
819
|
+
validateSegmentMatrix(
|
|
820
|
+
'segmentRecurrenceMatrix',
|
|
821
|
+
request.data,
|
|
822
|
+
request.rows,
|
|
823
|
+
request.cols,
|
|
824
|
+
'data',
|
|
825
|
+
);
|
|
826
|
+
assertNonNegativeInteger('segmentRecurrenceMatrix', request.k ?? 0, 'k');
|
|
827
|
+
assertNonNegativeInteger('segmentRecurrenceMatrix', request.width ?? 1, 'width');
|
|
828
|
+
return requireModule().segmentRecurrenceMatrix(
|
|
829
|
+
request.data,
|
|
830
|
+
request.rows,
|
|
831
|
+
request.cols,
|
|
832
|
+
request.k ?? 0,
|
|
833
|
+
request.width ?? 1,
|
|
834
|
+
request.sym ?? false,
|
|
835
|
+
request.metric ?? 'euclidean',
|
|
836
|
+
request.mode ?? 'connectivity',
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/** Convert an `n × n` recurrence matrix to a lag matrix. */
|
|
841
|
+
export function segmentRecurrenceToLag(request: SegmentRecurrenceToLagRequest): SegmentMatrix {
|
|
842
|
+
validateSegmentMatrix(
|
|
843
|
+
'segmentRecurrenceToLag',
|
|
844
|
+
request.recurrence,
|
|
845
|
+
request.n,
|
|
846
|
+
request.n,
|
|
847
|
+
'recurrence',
|
|
848
|
+
);
|
|
849
|
+
return requireModule().segmentRecurrenceToLag(
|
|
850
|
+
request.recurrence,
|
|
851
|
+
request.n,
|
|
852
|
+
request.pad ?? false,
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/** Convert a lag matrix back to an `n × n` recurrence matrix. */
|
|
857
|
+
export function segmentLagToRecurrence(request: SegmentLagToRecurrenceRequest): SegmentMatrix {
|
|
858
|
+
validateSegmentMatrix('segmentLagToRecurrence', request.lag, request.rows, request.lags, 'lag');
|
|
859
|
+
return requireModule().segmentLagToRecurrence(request.lag, request.rows, request.lags);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/** Refine frame boundaries by clustering within each parent segment. */
|
|
863
|
+
export function segmentSubsegment(request: SegmentSubsegmentRequest): Int32Array {
|
|
864
|
+
validateSegmentMatrix('segmentSubsegment', request.data, request.rows, request.cols, 'data');
|
|
865
|
+
assertPositiveInteger('segmentSubsegment', request.nSegments ?? 4, 'nSegments');
|
|
866
|
+
return requireModule().segmentSubsegment(
|
|
867
|
+
request.data,
|
|
868
|
+
request.rows,
|
|
869
|
+
request.cols,
|
|
870
|
+
request.boundaries,
|
|
871
|
+
request.nSegments ?? 4,
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/** Cluster feature columns and return one label per column. */
|
|
876
|
+
export function segmentAgglomerative(request: SegmentAgglomerativeRequest): Int32Array {
|
|
877
|
+
validateSegmentMatrix('segmentAgglomerative', request.data, request.rows, request.cols, 'data');
|
|
878
|
+
assertPositiveInteger('segmentAgglomerative', request.k, 'k');
|
|
879
|
+
return requireModule().segmentAgglomerative(
|
|
880
|
+
request.data,
|
|
881
|
+
request.rows,
|
|
882
|
+
request.cols,
|
|
883
|
+
request.k,
|
|
884
|
+
request.linkage ?? 'average',
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/** Enhance diagonal paths in an `n × n` recurrence matrix. */
|
|
889
|
+
export function segmentPathEnhance(request: SegmentPathEnhanceRequest): SegmentMatrix {
|
|
890
|
+
validateSegmentMatrix(
|
|
891
|
+
'segmentPathEnhance',
|
|
892
|
+
request.recurrence,
|
|
893
|
+
request.n,
|
|
894
|
+
request.n,
|
|
895
|
+
'recurrence',
|
|
896
|
+
);
|
|
897
|
+
assertPositiveInteger('segmentPathEnhance', request.win, 'win');
|
|
898
|
+
assertPositiveInteger('segmentPathEnhance', request.maxRatio ?? 2, 'maxRatio');
|
|
899
|
+
assertNonNegativeInteger('segmentPathEnhance', request.minRatio ?? 0, 'minRatio');
|
|
900
|
+
assertPositiveInteger('segmentPathEnhance', request.nFilters ?? 7, 'nFilters');
|
|
901
|
+
return requireModule().segmentPathEnhance(
|
|
902
|
+
request.recurrence,
|
|
903
|
+
request.n,
|
|
904
|
+
request.win,
|
|
905
|
+
request.maxRatio ?? 2,
|
|
906
|
+
request.minRatio ?? 0,
|
|
907
|
+
request.nFilters ?? 7,
|
|
908
|
+
);
|
|
909
|
+
}
|