@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.
Files changed (75) hide show
  1. package/README.md +109 -20
  2. package/dist/analysis.d.ts +5730 -0
  3. package/dist/analysis.js +2464 -0
  4. package/dist/analysis.js.map +1 -0
  5. package/dist/index.d.ts +759 -35
  6. package/dist/index.js +904 -209
  7. package/dist/index.js.map +1 -1
  8. package/dist/schemas/realtime-voice-changer-preset-pack.schema.json +27 -0
  9. package/dist/schemas/realtime-voice-changer-preset.schema.json +140 -0
  10. package/dist/sonare-analysis.js +2 -0
  11. package/dist/sonare-analysis.wasm +0 -0
  12. package/dist/sonare.js +1 -1
  13. package/dist/sonare.wasm +0 -0
  14. package/dist/worker.d.ts +65 -0
  15. package/dist/worker.js +707 -0
  16. package/dist/worker.js.map +1 -0
  17. package/dist/worklet.d.ts +574 -86
  18. package/dist/worklet.js +1634 -235
  19. package/dist/worklet.js.map +1 -1
  20. package/package.json +23 -11
  21. package/src/_chain_config.ts +5 -3
  22. package/src/analysis.ts +137 -0
  23. package/src/analysis_helpers.ts +6 -0
  24. package/src/clip_page_streamer.ts +62 -8
  25. package/src/codes.ts +51 -64
  26. package/src/effects_mastering.ts +1 -0
  27. package/src/errors.ts +1 -0
  28. package/src/feature_core.ts +140 -2
  29. package/src/feature_music.ts +17 -2
  30. package/src/feature_pitch.ts +70 -1
  31. package/src/feature_spectral.ts +231 -5
  32. package/src/feature_spectrogram.ts +159 -0
  33. package/src/features.ts +16 -1
  34. package/src/index.ts +101 -7
  35. package/src/mastering_chain.ts +20 -8
  36. package/src/mastering_core.ts +5 -0
  37. package/src/mastering_dynamics.ts +7 -1
  38. package/src/metering.ts +6 -1
  39. package/src/opfs_clip_pages.ts +26 -1
  40. package/src/project.ts +7 -0
  41. package/src/project_class.ts +62 -8
  42. package/src/project_internal.ts +24 -29
  43. package/src/project_types.ts +69 -10
  44. package/src/public_types.ts +68 -0
  45. package/src/public_types_mastering.ts +22 -0
  46. package/src/public_types_mixing.ts +11 -2
  47. package/src/public_types_music.ts +9 -0
  48. package/src/public_types_spectral.ts +33 -0
  49. package/src/quick_analysis.ts +25 -7
  50. package/src/realtime_engine.ts +153 -3
  51. package/src/realtime_voice_changer.ts +51 -77
  52. package/src/sonare-analysis.js.d.ts +8 -0
  53. package/src/sonare.js.d.ts +276 -6
  54. package/src/streaming_processors.ts +15 -0
  55. package/src/web_midi.ts +36 -4
  56. package/src/worker.ts +196 -0
  57. package/src/worker_client.ts +352 -0
  58. package/src/worker_protocol.ts +59 -0
  59. package/src/worklet/engine-automation.ts +2 -1
  60. package/src/worklet/engine-capture-facade.ts +13 -4
  61. package/src/worklet/engine-clips.ts +12 -3
  62. package/src/worklet/engine-node.ts +212 -4
  63. package/src/worklet/engine-offline.ts +7 -2
  64. package/src/worklet/engine-parameter-facade.ts +26 -5
  65. package/src/worklet/engine-processor.ts +383 -42
  66. package/src/worklet/engine-register.ts +8 -0
  67. package/src/worklet/engine-strips.ts +17 -1
  68. package/src/worklet/engine-sync.ts +2 -6
  69. package/src/worklet/engine-tempo-facade.ts +8 -6
  70. package/src/worklet/engine.ts +380 -13
  71. package/src/worklet/guards.ts +22 -1
  72. package/src/worklet/messages.ts +125 -7
  73. package/src/worklet/protocol.ts +301 -17
  74. package/src/worklet/voice-changer-processor.ts +12 -15
  75. package/src/worklet.ts +20 -1
@@ -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(r.onsetEnvelope, r.sampleRate, r.hopLength, r.winLength, r.mode);
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(onsetEnvelope, sampleRate, hopLength, winLength, mode);
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;
@@ -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`, reflect-pad by `frameLength / 2` so frame
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(onsetEnvelope, sampleRate, hopLength, winLength);
793
+ return requireModule().fourierTempogram(
794
+ onsetEnvelope,
795
+ sampleRate,
796
+ hopLength,
797
+ winLength,
798
+ center,
799
+ norm,
800
+ );
786
801
  }
787
802
 
788
803
  /**
@@ -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
+ }
@@ -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 { assertInterleavedSamples, assertSampleRate } from './validation';
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(samples.samples, samples.sampleRate, samples.nFft, samples.hopLength);
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
+ }