@libraz/libsonare 1.7.2 → 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.
Files changed (303) hide show
  1. package/NOTICE +178 -0
  2. package/README.md +26 -203
  3. package/dist/_chain_config.d.ts +14 -0
  4. package/dist/_chain_config.d.ts.map +1 -0
  5. package/dist/_effects_common.d.ts +6 -0
  6. package/dist/_effects_common.d.ts.map +1 -0
  7. package/dist/_feature_validation.d.ts +8 -0
  8. package/dist/_feature_validation.d.ts.map +1 -0
  9. package/dist/_fft_options.d.ts +24 -0
  10. package/dist/_fft_options.d.ts.map +1 -0
  11. package/dist/align_take.d.ts +50 -0
  12. package/dist/align_take.d.ts.map +1 -0
  13. package/dist/analysis.d.ts +29 -5840
  14. package/dist/analysis.d.ts.map +1 -0
  15. package/dist/analysis.js +873 -722
  16. package/dist/analysis.js.map +1 -1
  17. package/dist/analysis_helpers.d.ts +9 -0
  18. package/dist/analysis_helpers.d.ts.map +1 -0
  19. package/dist/audio.d.ts +163 -0
  20. package/dist/audio.d.ts.map +1 -0
  21. package/dist/clip_page_streamer.d.ts +133 -0
  22. package/dist/clip_page_streamer.d.ts.map +1 -0
  23. package/dist/codes.d.ts +44 -0
  24. package/dist/codes.d.ts.map +1 -0
  25. package/dist/effects_mastering.d.ts +23 -0
  26. package/dist/effects_mastering.d.ts.map +1 -0
  27. package/dist/effects_note_ops.d.ts +477 -0
  28. package/dist/effects_note_ops.d.ts.map +1 -0
  29. package/dist/effects_percussive.d.ts +185 -0
  30. package/dist/effects_percussive.d.ts.map +1 -0
  31. package/dist/effects_separation.d.ts +65 -0
  32. package/dist/effects_separation.d.ts.map +1 -0
  33. package/dist/effects_spectral.d.ts +28 -0
  34. package/dist/effects_spectral.d.ts.map +1 -0
  35. package/dist/effects_timepitch.d.ts +129 -0
  36. package/dist/effects_timepitch.d.ts.map +1 -0
  37. package/dist/effects_voice_change.d.ts +53 -0
  38. package/dist/effects_voice_change.d.ts.map +1 -0
  39. package/dist/errors.d.ts +51 -0
  40. package/dist/errors.d.ts.map +1 -0
  41. package/dist/feature_core.d.ts +341 -0
  42. package/dist/feature_core.d.ts.map +1 -0
  43. package/dist/feature_decompose.d.ts +278 -0
  44. package/dist/feature_decompose.d.ts.map +1 -0
  45. package/dist/feature_inverse.d.ts +128 -0
  46. package/dist/feature_inverse.d.ts.map +1 -0
  47. package/dist/feature_loudness.d.ts +66 -0
  48. package/dist/feature_loudness.d.ts.map +1 -0
  49. package/dist/feature_music.d.ts +307 -0
  50. package/dist/feature_music.d.ts.map +1 -0
  51. package/dist/feature_pitch.d.ts +108 -0
  52. package/dist/feature_pitch.d.ts.map +1 -0
  53. package/dist/feature_resample.d.ts +16 -0
  54. package/dist/feature_resample.d.ts.map +1 -0
  55. package/dist/feature_spectral.d.ts +137 -0
  56. package/dist/feature_spectral.d.ts.map +1 -0
  57. package/dist/feature_spectrogram.d.ts +198 -0
  58. package/dist/feature_spectrogram.d.ts.map +1 -0
  59. package/dist/features.d.ts +10 -0
  60. package/dist/features.d.ts.map +1 -0
  61. package/dist/hrtf/default.shrf +0 -0
  62. package/dist/index.d.ts +74 -7431
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +3758 -1362
  65. package/dist/index.js.map +1 -1
  66. package/dist/instrument_types.d.ts +517 -0
  67. package/dist/instrument_types.d.ts.map +1 -0
  68. package/dist/live_audio.d.ts +35 -0
  69. package/dist/live_audio.d.ts.map +1 -0
  70. package/dist/mastering_chain.d.ts +213 -0
  71. package/dist/mastering_chain.d.ts.map +1 -0
  72. package/dist/mastering_core.d.ts +457 -0
  73. package/dist/mastering_core.d.ts.map +1 -0
  74. package/dist/mastering_dynamics.d.ts +80 -0
  75. package/dist/mastering_dynamics.d.ts.map +1 -0
  76. package/dist/metering.d.ts +287 -0
  77. package/dist/metering.d.ts.map +1 -0
  78. package/dist/mixer.d.ts +464 -0
  79. package/dist/mixer.d.ts.map +1 -0
  80. package/dist/mixing_assistant.d.ts +62 -0
  81. package/dist/mixing_assistant.d.ts.map +1 -0
  82. package/dist/mixing_oneshot.d.ts +40 -0
  83. package/dist/mixing_oneshot.d.ts.map +1 -0
  84. package/dist/module_state.d.ts +15 -0
  85. package/dist/module_state.d.ts.map +1 -0
  86. package/dist/opfs_clip_pages.d.ts +28 -0
  87. package/dist/opfs_clip_pages.d.ts.map +1 -0
  88. package/dist/playback_renderer.d.ts +128 -0
  89. package/dist/playback_renderer.d.ts.map +1 -0
  90. package/dist/polyphony.d.ts +202 -0
  91. package/dist/polyphony.d.ts.map +1 -0
  92. package/dist/project.d.ts +8 -0
  93. package/dist/project.d.ts.map +1 -0
  94. package/dist/project_class.d.ts +562 -0
  95. package/dist/project_class.d.ts.map +1 -0
  96. package/dist/project_internal.d.ts +194 -0
  97. package/dist/project_internal.d.ts.map +1 -0
  98. package/dist/project_synth.d.ts +74 -0
  99. package/dist/project_synth.d.ts.map +1 -0
  100. package/dist/project_types.d.ts +652 -0
  101. package/dist/project_types.d.ts.map +1 -0
  102. package/dist/public_types.d.ts +185 -0
  103. package/dist/public_types.d.ts.map +1 -0
  104. package/dist/public_types_acoustic.d.ts +215 -0
  105. package/dist/public_types_acoustic.d.ts.map +1 -0
  106. package/dist/public_types_mastering.d.ts +510 -0
  107. package/dist/public_types_mastering.d.ts.map +1 -0
  108. package/dist/public_types_mixing.d.ts +436 -0
  109. package/dist/public_types_mixing.d.ts.map +1 -0
  110. package/dist/public_types_music.d.ts +619 -0
  111. package/dist/public_types_music.d.ts.map +1 -0
  112. package/dist/public_types_playback.d.ts +164 -0
  113. package/dist/public_types_playback.d.ts.map +1 -0
  114. package/dist/public_types_realtime.d.ts +174 -0
  115. package/dist/public_types_realtime.d.ts.map +1 -0
  116. package/dist/public_types_repair.d.ts +424 -0
  117. package/dist/public_types_repair.d.ts.map +1 -0
  118. package/dist/public_types_spectral.d.ts +697 -0
  119. package/dist/public_types_spectral.d.ts.map +1 -0
  120. package/dist/quick_analysis.d.ts +445 -0
  121. package/dist/quick_analysis.d.ts.map +1 -0
  122. package/dist/realtime_engine.d.ts +850 -0
  123. package/dist/realtime_engine.d.ts.map +1 -0
  124. package/dist/realtime_voice_changer.d.ts +158 -0
  125. package/dist/realtime_voice_changer.d.ts.map +1 -0
  126. package/dist/repair_dereverb.d.ts +187 -0
  127. package/dist/repair_dereverb.d.ts.map +1 -0
  128. package/dist/repair_impulsive.d.ts +186 -0
  129. package/dist/repair_impulsive.d.ts.map +1 -0
  130. package/dist/repair_noise.d.ts +239 -0
  131. package/dist/repair_noise.d.ts.map +1 -0
  132. package/dist/repair_trim.d.ts +123 -0
  133. package/dist/repair_trim.d.ts.map +1 -0
  134. package/dist/sample_bank.d.ts +84 -0
  135. package/dist/sample_bank.d.ts.map +1 -0
  136. package/dist/scale.d.ts +10 -0
  137. package/dist/scale.d.ts.map +1 -0
  138. package/dist/schemas/mixer-scene.schema.json +393 -0
  139. package/dist/schemas/playback-renderer-config.schema.json +392 -0
  140. package/dist/sonare-analysis.d.ts +8 -0
  141. package/dist/sonare-analysis.js +2 -2
  142. package/dist/sonare-analysis.wasm +0 -0
  143. package/dist/sonare.d.ts +3909 -0
  144. package/dist/sonare.js +2 -2
  145. package/dist/sonare.wasm +0 -0
  146. package/dist/stream_analyzer.d.ts +163 -0
  147. package/dist/stream_analyzer.d.ts.map +1 -0
  148. package/dist/stream_types.d.ts +214 -0
  149. package/dist/stream_types.d.ts.map +1 -0
  150. package/dist/streaming_mixing.d.ts +6 -0
  151. package/dist/streaming_mixing.d.ts.map +1 -0
  152. package/dist/streaming_processors.d.ts +335 -0
  153. package/dist/streaming_processors.d.ts.map +1 -0
  154. package/dist/transcribe.d.ts +77 -0
  155. package/dist/transcribe.d.ts.map +1 -0
  156. package/dist/validation.d.ts +140 -0
  157. package/dist/validation.d.ts.map +1 -0
  158. package/dist/web_midi.d.ts +77 -0
  159. package/dist/web_midi.d.ts.map +1 -0
  160. package/dist/worker.d.ts +5 -48
  161. package/dist/worker.d.ts.map +1 -0
  162. package/dist/worker.js +94 -41
  163. package/dist/worker.js.map +1 -1
  164. package/dist/worker_client.d.ts +96 -0
  165. package/dist/worker_client.d.ts.map +1 -0
  166. package/dist/worker_protocol.d.ts +43 -0
  167. package/dist/worker_protocol.d.ts.map +1 -0
  168. package/dist/worklet/audio_types.d.ts +21 -0
  169. package/dist/worklet/audio_types.d.ts.map +1 -0
  170. package/dist/worklet/engine-automation.d.ts +29 -0
  171. package/dist/worklet/engine-automation.d.ts.map +1 -0
  172. package/dist/worklet/engine-capture-facade.d.ts +35 -0
  173. package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
  174. package/dist/worklet/engine-clips.d.ts +23 -0
  175. package/dist/worklet/engine-clips.d.ts.map +1 -0
  176. package/dist/worklet/engine-markers.d.ts +40 -0
  177. package/dist/worklet/engine-markers.d.ts.map +1 -0
  178. package/dist/worklet/engine-mixer-facade.d.ts +128 -0
  179. package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
  180. package/dist/worklet/engine-node.d.ts +81 -0
  181. package/dist/worklet/engine-node.d.ts.map +1 -0
  182. package/dist/worklet/engine-offline.d.ts +81 -0
  183. package/dist/worklet/engine-offline.d.ts.map +1 -0
  184. package/dist/worklet/engine-options.d.ts +12 -0
  185. package/dist/worklet/engine-options.d.ts.map +1 -0
  186. package/dist/worklet/engine-parameter-facade.d.ts +106 -0
  187. package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
  188. package/dist/worklet/engine-processor.d.ts +68 -0
  189. package/dist/worklet/engine-processor.d.ts.map +1 -0
  190. package/dist/worklet/engine-register.d.ts +2 -0
  191. package/dist/worklet/engine-register.d.ts.map +1 -0
  192. package/dist/worklet/engine-strips.d.ts +73 -0
  193. package/dist/worklet/engine-strips.d.ts.map +1 -0
  194. package/dist/worklet/engine-sync.d.ts +37 -0
  195. package/dist/worklet/engine-sync.d.ts.map +1 -0
  196. package/dist/worklet/engine-tempo-facade.d.ts +48 -0
  197. package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
  198. package/dist/worklet/engine.d.ts +397 -0
  199. package/dist/worklet/engine.d.ts.map +1 -0
  200. package/dist/worklet/guards.d.ts +47 -0
  201. package/dist/worklet/guards.d.ts.map +1 -0
  202. package/dist/worklet/messages.d.ts +710 -0
  203. package/dist/worklet/messages.d.ts.map +1 -0
  204. package/dist/worklet/mixer-processor.d.ts +46 -0
  205. package/dist/worklet/mixer-processor.d.ts.map +1 -0
  206. package/dist/worklet/playback-processor.d.ts +62 -0
  207. package/dist/worklet/playback-processor.d.ts.map +1 -0
  208. package/dist/worklet/protocol.d.ts +323 -0
  209. package/dist/worklet/protocol.d.ts.map +1 -0
  210. package/dist/worklet/voice-changer-processor.d.ts +41 -0
  211. package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
  212. package/dist/worklet.d.ts +16 -2515
  213. package/dist/worklet.d.ts.map +1 -0
  214. package/dist/worklet.js +2763 -501
  215. package/dist/worklet.js.map +1 -1
  216. package/package.json +23 -12
  217. package/src/_effects_common.ts +17 -0
  218. package/src/_feature_validation.ts +34 -0
  219. package/src/_fft_options.ts +39 -0
  220. package/src/align_take.ts +64 -0
  221. package/src/analysis.ts +56 -3
  222. package/src/analysis_helpers.ts +7 -0
  223. package/src/audio.ts +106 -3
  224. package/src/codes.ts +39 -2
  225. package/src/effects_mastering.ts +97 -22
  226. package/src/effects_note_ops.ts +635 -0
  227. package/src/effects_percussive.ts +217 -0
  228. package/src/effects_separation.ts +150 -0
  229. package/src/effects_spectral.ts +60 -0
  230. package/src/effects_timepitch.ts +377 -0
  231. package/src/errors.ts +23 -1
  232. package/src/feature_core.ts +127 -2
  233. package/src/feature_decompose.ts +633 -0
  234. package/src/feature_inverse.ts +454 -0
  235. package/src/feature_loudness.ts +125 -0
  236. package/src/feature_music.ts +107 -14
  237. package/src/feature_pitch.ts +96 -1
  238. package/src/feature_spectral.ts +16 -611
  239. package/src/feature_spectrogram.ts +63 -450
  240. package/src/features.ts +36 -22
  241. package/src/index.ts +282 -30
  242. package/src/instrument_types.ts +645 -0
  243. package/src/live_audio.ts +27 -1
  244. package/src/mastering_chain.ts +184 -0
  245. package/src/mastering_core.ts +346 -32
  246. package/src/mastering_dynamics.ts +22 -11
  247. package/src/metering.ts +67 -24
  248. package/src/mixer.ts +212 -3
  249. package/src/mixing_assistant.ts +138 -0
  250. package/src/mixing_oneshot.ts +10 -5
  251. package/src/module_state.ts +24 -2
  252. package/src/playback_renderer.ts +252 -0
  253. package/src/polyphony.ts +279 -0
  254. package/src/project.ts +61 -24
  255. package/src/project_class.ts +450 -27
  256. package/src/project_internal.ts +149 -42
  257. package/src/project_synth.ts +67 -1
  258. package/src/project_types.ts +268 -270
  259. package/src/public_types.ts +122 -3
  260. package/src/public_types_acoustic.ts +112 -3
  261. package/src/public_types_mastering.ts +254 -73
  262. package/src/public_types_mixing.ts +363 -1
  263. package/src/public_types_music.ts +312 -2
  264. package/src/public_types_playback.ts +195 -0
  265. package/src/public_types_realtime.ts +39 -7
  266. package/src/public_types_repair.ts +446 -0
  267. package/src/public_types_spectral.ts +487 -1
  268. package/src/quick_analysis.ts +203 -26
  269. package/src/realtime_engine.ts +711 -28
  270. package/src/realtime_voice_changer.ts +55 -1
  271. package/src/repair_dereverb.ts +299 -0
  272. package/src/repair_impulsive.ts +395 -0
  273. package/src/repair_noise.ts +425 -0
  274. package/src/repair_trim.ts +226 -0
  275. package/src/sample_bank.ts +113 -0
  276. package/src/sonare.js.d.ts +1122 -30
  277. package/src/stream_analyzer.ts +36 -4
  278. package/src/stream_types.ts +37 -0
  279. package/src/streaming_mixing.ts +1 -1
  280. package/src/streaming_processors.ts +194 -10
  281. package/src/transcribe.ts +89 -0
  282. package/src/validation.ts +285 -11
  283. package/src/web_midi.ts +1 -6
  284. package/src/worker.ts +18 -2
  285. package/src/worklet/audio_types.ts +37 -0
  286. package/src/worklet/engine-mixer-facade.ts +444 -10
  287. package/src/worklet/engine-node.ts +78 -26
  288. package/src/worklet/engine-offline.ts +14 -8
  289. package/src/worklet/engine-parameter-facade.ts +21 -0
  290. package/src/worklet/engine-processor.ts +272 -83
  291. package/src/worklet/engine-register.ts +32 -18
  292. package/src/worklet/engine-strips.ts +280 -9
  293. package/src/worklet/engine-sync.ts +14 -6
  294. package/src/worklet/engine.ts +365 -31
  295. package/src/worklet/guards.ts +140 -44
  296. package/src/worklet/messages.ts +227 -2
  297. package/src/worklet/mixer-processor.ts +109 -47
  298. package/src/worklet/playback-processor.ts +300 -0
  299. package/src/worklet/protocol.ts +53 -3
  300. package/src/worklet/voice-changer-processor.ts +17 -11
  301. package/src/worklet.ts +17 -0
  302. package/src/effects_transform.ts +0 -718
  303. package/src/mastering_repair.ts +0 -273
@@ -0,0 +1,633 @@
1
+ /**
2
+ * Source decomposition and self-similarity segmentation: NMF factorisation and
3
+ * the masks built over it, and the recurrence structure of a track.
4
+ */
5
+
6
+ import { resolveFftOptions } from './_fft_options';
7
+ import { getSonareModule } from './module_state';
8
+ import type { SegmentMatrix } from './public_types';
9
+ import type {
10
+ WasmDecomposeResult,
11
+ WasmHpssWithResidualResult,
12
+ WasmMatrix2dResult,
13
+ } from './sonare.js';
14
+ import {
15
+ assertHpssKernels,
16
+ assertNonNegativeInteger,
17
+ assertPositiveInteger,
18
+ assertSamples,
19
+ toInt32Array,
20
+ } from './validation';
21
+
22
+ function requireModule() {
23
+ return getSonareModule();
24
+ }
25
+
26
+ function resolveHardMask(fnName: string, value: unknown): boolean {
27
+ if (value === undefined) {
28
+ return false;
29
+ }
30
+ if (typeof value !== 'boolean') {
31
+ throw new TypeError(`${fnName}: hardMask must be a boolean`);
32
+ }
33
+ return value;
34
+ }
35
+
36
+ export interface DecomposeRequest {
37
+ s: Float32Array;
38
+ nFeatures: number;
39
+ nFrames: number;
40
+ nComponents: number;
41
+ nIter?: number;
42
+ beta?: number;
43
+ }
44
+
45
+ export interface DecomposeWithInitRequest extends DecomposeRequest {
46
+ init?: 'random' | 'nndsvd';
47
+ }
48
+
49
+ export interface NnFilterRequest {
50
+ s: Float32Array;
51
+ nFeatures: number;
52
+ nFrames: number;
53
+ aggregate?: string;
54
+ k?: number;
55
+ width?: number;
56
+ }
57
+
58
+ export interface SegmentCrossSimilarityRequest {
59
+ x: Float32Array;
60
+ xRows: number;
61
+ xCols: number;
62
+ y: Float32Array;
63
+ yRows: number;
64
+ yCols: number;
65
+ k?: number;
66
+ metric?: 'cosine' | 'euclidean';
67
+ mode?: 'connectivity' | 'affinity';
68
+ }
69
+
70
+ export interface SegmentRecurrenceMatrixRequest {
71
+ data: Float32Array;
72
+ rows: number;
73
+ cols: number;
74
+ k?: number;
75
+ width?: number;
76
+ sym?: boolean;
77
+ metric?: 'cosine' | 'euclidean';
78
+ mode?: 'connectivity' | 'affinity';
79
+ }
80
+
81
+ export interface SegmentRecurrenceToLagRequest {
82
+ recurrence: Float32Array;
83
+ n: number;
84
+ pad?: boolean;
85
+ }
86
+
87
+ export interface SegmentLagToRecurrenceRequest {
88
+ lag: Float32Array;
89
+ rows: number;
90
+ lags: number;
91
+ }
92
+
93
+ export interface SegmentSubsegmentRequest {
94
+ data: Float32Array;
95
+ rows: number;
96
+ cols: number;
97
+ boundaries: Int32Array;
98
+ nSegments?: number;
99
+ }
100
+
101
+ export interface SegmentAgglomerativeRequest {
102
+ data: Float32Array;
103
+ rows: number;
104
+ cols: number;
105
+ k: number;
106
+ linkage?: 'average' | 'single' | 'complete' | 'ward';
107
+ }
108
+
109
+ export interface SegmentPathEnhanceRequest {
110
+ recurrence: Float32Array;
111
+ n: number;
112
+ win: number;
113
+ maxRatio?: number;
114
+ minRatio?: number;
115
+ nFilters?: number;
116
+ }
117
+
118
+ function validateSegmentMatrix(
119
+ fnName: string,
120
+ data: Float32Array,
121
+ rows: number,
122
+ cols: number,
123
+ dataName: string,
124
+ ): void {
125
+ assertPositiveInteger(fnName, rows, 'rows');
126
+ assertPositiveInteger(fnName, cols, 'cols');
127
+ assertSamples(fnName, data, true, dataName);
128
+ const expected = rows * cols;
129
+ if (!Number.isSafeInteger(expected) || data.length !== expected) {
130
+ throw new RangeError(`${fnName}: ${dataName} length must equal rows * cols`);
131
+ }
132
+ }
133
+
134
+ export interface RemixRequest {
135
+ samples: Float32Array;
136
+ intervals: Int32Array | ArrayLike<number>;
137
+ sampleRate?: number;
138
+ alignZeros?: boolean;
139
+ }
140
+
141
+ export interface HpssWithResidualRequest {
142
+ samples: Float32Array;
143
+ sampleRate?: number;
144
+ /**
145
+ * Horizontal median filter size, in STFT frames: a positive odd integer at
146
+ * most 524287. Default 31. The ceiling is 524288 and an even kernel is
147
+ * refused, so 524287 is the largest legal value.
148
+ */
149
+ kernelHarmonic?: number;
150
+ /** Vertical median filter size, in STFT bins, under the same rule. Default 31. */
151
+ kernelPercussive?: number;
152
+ nFft?: number;
153
+ hopLength?: number;
154
+ hardMask?: boolean;
155
+ }
156
+
157
+ /**
158
+ * Non-negative matrix factorisation of a flattened [nFeatures x nFrames]
159
+ * spectrogram (librosa.decompose.decompose). Returns the W and H factors.
160
+ */
161
+ export function decompose(request: DecomposeRequest): WasmDecomposeResult;
162
+ export function decompose(
163
+ s: Float32Array,
164
+ nFeatures: number,
165
+ nFrames: number,
166
+ nComponents: number,
167
+ nIter?: number,
168
+ beta?: number,
169
+ ): WasmDecomposeResult;
170
+ export function decompose(
171
+ s: Float32Array | DecomposeRequest,
172
+ nFeatures = 0,
173
+ nFrames = 0,
174
+ nComponents = 0,
175
+ nIter = 50,
176
+ beta = 2.0,
177
+ ): WasmDecomposeResult {
178
+ if (!(s instanceof Float32Array)) {
179
+ const request = s;
180
+ return decompose(
181
+ request.s,
182
+ request.nFeatures,
183
+ request.nFrames,
184
+ request.nComponents,
185
+ request.nIter,
186
+ request.beta,
187
+ );
188
+ }
189
+ return requireModule().decompose(s, nFeatures, nFrames, nComponents, nIter, beta);
190
+ }
191
+
192
+ /**
193
+ * Non-negative matrix factorisation with a selectable initialiser
194
+ * (librosa.decompose.decompose, `init`). Identical to {@link decompose} but
195
+ * exposes the initialisation strategy: `'random'` (default, deterministic seed)
196
+ * or `'nndsvd'` (SVD-based warm start, which tends to converge in fewer
197
+ * iterations). Returns the W and H factors.
198
+ */
199
+ export function decomposeWithInit(request: DecomposeWithInitRequest): WasmDecomposeResult;
200
+ export function decomposeWithInit(
201
+ s: Float32Array,
202
+ nFeatures: number,
203
+ nFrames: number,
204
+ nComponents: number,
205
+ nIter?: number,
206
+ beta?: number,
207
+ init?: 'random' | 'nndsvd',
208
+ ): WasmDecomposeResult;
209
+ export function decomposeWithInit(
210
+ s: Float32Array | DecomposeWithInitRequest,
211
+ nFeatures = 0,
212
+ nFrames = 0,
213
+ nComponents = 0,
214
+ nIter = 50,
215
+ beta = 2.0,
216
+ init: 'random' | 'nndsvd' = 'random',
217
+ ): WasmDecomposeResult {
218
+ if (!(s instanceof Float32Array)) {
219
+ const request = s;
220
+ return decomposeWithInit(
221
+ request.s,
222
+ request.nFeatures,
223
+ request.nFrames,
224
+ request.nComponents,
225
+ request.nIter,
226
+ request.beta,
227
+ request.init,
228
+ );
229
+ }
230
+ return requireModule().decomposeWithInit(s, nFeatures, nFrames, nComponents, nIter, beta, init);
231
+ }
232
+
233
+ /** Options for {@link decomposeStems}. */
234
+ export interface DecomposeStemsRequest {
235
+ samples: Float32Array;
236
+ sampleRate: number;
237
+ /** Number of NMF components (default 4). */
238
+ nComponents?: number;
239
+ /** STFT size (default 2048). */
240
+ nFft?: number;
241
+ /** STFT hop (default 512). */
242
+ hopLength?: number;
243
+ /** NMF multiplicative-update iterations (default 100). */
244
+ nIter?: number;
245
+ /** Beta divergence: 2 = Frobenius (default), 1 = Kullback-Leibler. */
246
+ beta?: number;
247
+ /** NMF initialisation (default `'random'`). */
248
+ init?: 'random' | 'nndsvd';
249
+ /**
250
+ * Soft-mask exponent (default 1). 1 keeps the magnitude ratio; 2 is the
251
+ * Wiener-style power ratio, which separates harder at the cost of more
252
+ * artefacts on overlapping partials. Must be >= 1.
253
+ */
254
+ maskPower?: number;
255
+ }
256
+
257
+ /** One time-domain signal per NMF component, plus the factorisation. */
258
+ export interface DecomposeStemsResult {
259
+ /** Component signals, each the length of the input. */
260
+ components: Float32Array[];
261
+ /** Component matrix [nBins x nComponents], row-major. */
262
+ w: Float32Array;
263
+ /** Activation matrix [nComponents x nFrames], row-major. */
264
+ h: Float32Array;
265
+ sampleRate: number;
266
+ }
267
+
268
+ /**
269
+ * NMF separation that **carries the original phase**, so each component is
270
+ * directly listenable.
271
+ *
272
+ * {@link decompose} returns the W/H factors of a magnitude spectrogram, which
273
+ * have no phase; reconstructing from them needs a phase estimator
274
+ * ({@link griffinLim}), and an estimated phase does not hold up as a stem. This
275
+ * instead builds a per-component soft mask from the factorisation and applies
276
+ * it to the original complex spectrogram. The masks sum to one wherever the
277
+ * model has energy and the inverse STFT is linear, so the components sum back
278
+ * to the input.
279
+ */
280
+ export function decomposeStems(request: DecomposeStemsRequest): DecomposeStemsResult {
281
+ return requireModule().decomposeStems(request.samples, request.sampleRate, {
282
+ nComponents: request.nComponents,
283
+ nFft: request.nFft,
284
+ hopLength: request.hopLength,
285
+ nIter: request.nIter,
286
+ beta: request.beta,
287
+ init: request.init,
288
+ maskPower: request.maskPower,
289
+ });
290
+ }
291
+
292
+ /** Request form of {@link decomposeStemsLinked}. */
293
+ export interface DecomposeStemsLinkedRequest {
294
+ /** At least one channel; all the same length. */
295
+ channels: Float32Array[];
296
+ sampleRate?: number;
297
+ /** Number of NMF components (default 4). */
298
+ nComponents?: number;
299
+ /** STFT size (default 2048). */
300
+ nFft?: number;
301
+ /** STFT hop (default 512). */
302
+ hopLength?: number;
303
+ /** NMF multiplicative-update iterations (default 100). */
304
+ nIter?: number;
305
+ /** Beta divergence: 2 = Frobenius (default), 1 = Kullback-Leibler. */
306
+ beta?: number;
307
+ /** NMF initialisation (default `'random'`). */
308
+ init?: 'random' | 'nndsvd';
309
+ /** Soft-mask exponent (default 1); see {@link DecomposeStemsRequest.maskPower}. */
310
+ maskPower?: number;
311
+ }
312
+
313
+ /** One time-domain signal per (component, channel), plus the factorisation. */
314
+ export interface DecomposeStemsLinkedResult {
315
+ /**
316
+ * Component signals: `components[k][c]` is component `k`'s signal on
317
+ * channel `c`, each the length of the input.
318
+ */
319
+ components: Float32Array[][];
320
+ /** Component matrix [nBins x nComponents], row-major. */
321
+ w: Float32Array;
322
+ /** Activation matrix [nComponents x nFrames], row-major. */
323
+ h: Float32Array;
324
+ sampleRate: number;
325
+ }
326
+
327
+ /**
328
+ * Multi-channel form of {@link decomposeStems}: one NMF model and one soft
329
+ * mask shared across every channel, built from the channels' averaged
330
+ * magnitude spectrogram and applied UNCHANGED to each channel's own complex
331
+ * spectrum, so no interchannel level or phase difference moves. A single
332
+ * channel reproduces {@link decomposeStems} bit for bit.
333
+ *
334
+ * @throws On a null/empty channel set, mismatched channel lengths, a channel
335
+ * count above the core's ceiling, or an invalid option.
336
+ */
337
+ export function decomposeStemsLinked(
338
+ request: DecomposeStemsLinkedRequest,
339
+ ): DecomposeStemsLinkedResult {
340
+ return requireModule().decomposeStemsLinked(request.channels, request.sampleRate ?? 22050, {
341
+ nComponents: request.nComponents,
342
+ nFft: request.nFft,
343
+ hopLength: request.hopLength,
344
+ nIter: request.nIter,
345
+ beta: request.beta,
346
+ init: request.init,
347
+ maskPower: request.maskPower,
348
+ });
349
+ }
350
+
351
+ /**
352
+ * Nearest-neighbour filtering of a flattened [nFeatures x nFrames] spectrogram
353
+ * (librosa.decompose.nn_filter).
354
+ */
355
+ export function nnFilter(request: NnFilterRequest): WasmMatrix2dResult;
356
+ export function nnFilter(
357
+ s: Float32Array,
358
+ nFeatures: number,
359
+ nFrames: number,
360
+ aggregate?: string,
361
+ k?: number,
362
+ width?: number,
363
+ ): WasmMatrix2dResult;
364
+ export function nnFilter(
365
+ s: Float32Array | NnFilterRequest,
366
+ nFeatures = 0,
367
+ nFrames = 0,
368
+ aggregate = 'mean',
369
+ k = 7,
370
+ width = 1,
371
+ ): WasmMatrix2dResult {
372
+ if (!(s instanceof Float32Array)) {
373
+ const r = s;
374
+ return nnFilter(r.s, r.nFeatures, r.nFrames, r.aggregate, r.k, r.width);
375
+ }
376
+ return requireModule().nnFilter(s, nFeatures, nFrames, aggregate, k, width);
377
+ }
378
+
379
+ /**
380
+ * Reorder/concatenate a signal by interval slices (librosa.effects.remix).
381
+ *
382
+ * With `alignZeros` the boundaries snap to the signal's zero-crossings. That is
383
+ * a per-signal decision, so calling this per channel snaps each channel to a
384
+ * different frame and drifts a stereo take apart; resolve one cut set with
385
+ * {@link remixAlignedIntervals} and apply it to every channel instead.
386
+ *
387
+ * @param intervals - Flat (start, end) sample pairs (even length).
388
+ */
389
+ export function remix(request: RemixRequest): Float32Array;
390
+ export function remix(
391
+ samples: Float32Array,
392
+ intervals: Int32Array | ArrayLike<number>,
393
+ sampleRate?: number,
394
+ alignZeros?: boolean,
395
+ ): Float32Array;
396
+ export function remix(
397
+ samples: Float32Array | RemixRequest,
398
+ intervals?: Int32Array | ArrayLike<number>,
399
+ sampleRate = 22050,
400
+ alignZeros = false,
401
+ ): Float32Array {
402
+ if (!(samples instanceof Float32Array)) {
403
+ const r = samples;
404
+ return remix(r.samples, r.intervals, r.sampleRate, r.alignZeros);
405
+ }
406
+ // Sample indices must reach the native side as exact 32-bit integers, and a
407
+ // boundary the conversion changed would cut the slice somewhere the caller
408
+ // never named.
409
+ const intervalsI32 = toInt32Array('remix', intervals as ArrayLike<number>, 'intervals');
410
+ return requireModule().remix(samples, intervalsI32, sampleRate, alignZeros);
411
+ }
412
+
413
+ /**
414
+ * Resolve the cut points {@link remix} would use, without cutting.
415
+ *
416
+ * Returns a flat `Int32Array` of one clamped `(start, end)` pair per input
417
+ * interval. With `alignZeros` each boundary snaps to the nearest zero-crossing,
418
+ * with two guards that stop a slice from vanishing: a signal with no sign
419
+ * change at all (silence, a DC offset, any constant) is not snapped, and a
420
+ * slice that had content but collapses to empty after snapping keeps its
421
+ * unsnapped boundaries.
422
+ *
423
+ * Use this to cut a multichannel take on one common frame set: resolve once
424
+ * from one channel, then slice every channel with the returned pairs.
425
+ *
426
+ * @param intervals - Flat (start, end) sample pairs (even length).
427
+ */
428
+ export function remixAlignedIntervals(request: RemixRequest): Int32Array;
429
+ export function remixAlignedIntervals(
430
+ samples: Float32Array,
431
+ intervals: Int32Array | ArrayLike<number>,
432
+ sampleRate?: number,
433
+ alignZeros?: boolean,
434
+ ): Int32Array;
435
+ export function remixAlignedIntervals(
436
+ samples: Float32Array | RemixRequest,
437
+ intervals?: Int32Array | ArrayLike<number>,
438
+ sampleRate = 22050,
439
+ alignZeros = true,
440
+ ): Int32Array {
441
+ if (!(samples instanceof Float32Array)) {
442
+ const r = samples;
443
+ return remixAlignedIntervals(r.samples, r.intervals, r.sampleRate, r.alignZeros ?? true);
444
+ }
445
+ const intervalsI32 = toInt32Array(
446
+ 'remixAlignedIntervals',
447
+ intervals as ArrayLike<number>,
448
+ 'intervals',
449
+ );
450
+ return requireModule().remixAlignedIntervals(samples, intervalsI32, sampleRate, alignZeros);
451
+ }
452
+
453
+ /**
454
+ * HPSS into harmonic / percussive / residual signals.
455
+ *
456
+ * The three outputs always add back up to the input. `residual` is silent under
457
+ * the default soft mask, whose two masks sum to one, so `harmonic` and
458
+ * `percussive` already carry everything; it is returned anyway so the result
459
+ * shape does not change with the mask. Pass `hardMask: true` for a residual that
460
+ * holds signal — its thresholded masks leave the band where neither component
461
+ * dominates, measured at 3 % of the input energy on a voice-plus-kick signal.
462
+ *
463
+ * @example
464
+ * ```ts
465
+ * const soft = hpssWithResidual({ samples, sampleRate });
466
+ * // soft.residual is silence
467
+ * const hard = hpssWithResidual({ samples, sampleRate, hardMask: true });
468
+ * // hard.residual carries what neither component claimed
469
+ * ```
470
+ *
471
+ * @throws SonareError (`InvalidParameter`) on a kernel that is not an integer
472
+ * within the signed 32-bit range, or one the core rejects as even,
473
+ * non-positive or above its ceiling
474
+ */
475
+ export function hpssWithResidual(request: HpssWithResidualRequest): WasmHpssWithResidualResult;
476
+ export function hpssWithResidual(
477
+ samples: Float32Array,
478
+ sampleRate?: number,
479
+ kernelHarmonic?: number,
480
+ kernelPercussive?: number,
481
+ nFft?: number,
482
+ hopLength?: number,
483
+ hardMask?: boolean,
484
+ ): WasmHpssWithResidualResult;
485
+ export function hpssWithResidual(
486
+ samples: Float32Array | HpssWithResidualRequest,
487
+ sampleRate = 22050,
488
+ kernelHarmonic = 31,
489
+ kernelPercussive = 31,
490
+ nFft?: number,
491
+ hopLength?: number,
492
+ hardMask?: boolean,
493
+ ): WasmHpssWithResidualResult {
494
+ if (!(samples instanceof Float32Array)) {
495
+ const r = samples;
496
+ return hpssWithResidual(
497
+ r.samples,
498
+ r.sampleRate,
499
+ r.kernelHarmonic,
500
+ r.kernelPercussive,
501
+ r.nFft,
502
+ r.hopLength,
503
+ r.hardMask,
504
+ );
505
+ }
506
+ const fftOptions = resolveFftOptions('hpssWithResidual', nFft, hopLength);
507
+ const resolvedHardMask = resolveHardMask('hpssWithResidual', hardMask);
508
+ assertHpssKernels('hpssWithResidual', kernelHarmonic, kernelPercussive);
509
+ return requireModule().hpssWithResidualEx(
510
+ samples,
511
+ sampleRate,
512
+ kernelHarmonic,
513
+ kernelPercussive,
514
+ fftOptions.nFft,
515
+ fftOptions.hopLength,
516
+ resolvedHardMask,
517
+ );
518
+ }
519
+
520
+ /** Column-wise cross-similarity (librosa.segment.cross_similarity). */
521
+ export function segmentCrossSimilarity(request: SegmentCrossSimilarityRequest): SegmentMatrix {
522
+ validateSegmentMatrix('segmentCrossSimilarity', request.x, request.xRows, request.xCols, 'x');
523
+ validateSegmentMatrix('segmentCrossSimilarity', request.y, request.yRows, request.yCols, 'y');
524
+ if (request.xRows !== request.yRows) {
525
+ throw new RangeError('segmentCrossSimilarity: feature dimensions must match');
526
+ }
527
+ assertNonNegativeInteger('segmentCrossSimilarity', request.k ?? 0, 'k');
528
+ return requireModule().segmentCrossSimilarity(
529
+ request.x,
530
+ request.xRows,
531
+ request.xCols,
532
+ request.y,
533
+ request.yRows,
534
+ request.yCols,
535
+ request.k ?? 0,
536
+ request.metric ?? 'cosine',
537
+ request.mode ?? 'connectivity',
538
+ );
539
+ }
540
+
541
+ /** Self-similarity recurrence matrix (librosa.segment.recurrence_matrix). */
542
+ export function segmentRecurrenceMatrix(request: SegmentRecurrenceMatrixRequest): SegmentMatrix {
543
+ validateSegmentMatrix(
544
+ 'segmentRecurrenceMatrix',
545
+ request.data,
546
+ request.rows,
547
+ request.cols,
548
+ 'data',
549
+ );
550
+ assertNonNegativeInteger('segmentRecurrenceMatrix', request.k ?? 0, 'k');
551
+ assertNonNegativeInteger('segmentRecurrenceMatrix', request.width ?? 1, 'width');
552
+ return requireModule().segmentRecurrenceMatrix(
553
+ request.data,
554
+ request.rows,
555
+ request.cols,
556
+ request.k ?? 0,
557
+ request.width ?? 1,
558
+ request.sym ?? false,
559
+ request.metric ?? 'euclidean',
560
+ request.mode ?? 'connectivity',
561
+ );
562
+ }
563
+
564
+ /** Convert an `n × n` recurrence matrix to a lag matrix. */
565
+ export function segmentRecurrenceToLag(request: SegmentRecurrenceToLagRequest): SegmentMatrix {
566
+ validateSegmentMatrix(
567
+ 'segmentRecurrenceToLag',
568
+ request.recurrence,
569
+ request.n,
570
+ request.n,
571
+ 'recurrence',
572
+ );
573
+ return requireModule().segmentRecurrenceToLag(
574
+ request.recurrence,
575
+ request.n,
576
+ request.pad ?? false,
577
+ );
578
+ }
579
+
580
+ /** Convert a lag matrix back to an `n × n` recurrence matrix. */
581
+ export function segmentLagToRecurrence(request: SegmentLagToRecurrenceRequest): SegmentMatrix {
582
+ validateSegmentMatrix('segmentLagToRecurrence', request.lag, request.rows, request.lags, 'lag');
583
+ return requireModule().segmentLagToRecurrence(request.lag, request.rows, request.lags);
584
+ }
585
+
586
+ /** Refine frame boundaries by clustering within each parent segment. */
587
+ export function segmentSubsegment(request: SegmentSubsegmentRequest): Int32Array {
588
+ validateSegmentMatrix('segmentSubsegment', request.data, request.rows, request.cols, 'data');
589
+ assertPositiveInteger('segmentSubsegment', request.nSegments ?? 4, 'nSegments');
590
+ return requireModule().segmentSubsegment(
591
+ request.data,
592
+ request.rows,
593
+ request.cols,
594
+ request.boundaries,
595
+ request.nSegments ?? 4,
596
+ );
597
+ }
598
+
599
+ /** Cluster feature columns and return one label per column. */
600
+ export function segmentAgglomerative(request: SegmentAgglomerativeRequest): Int32Array {
601
+ validateSegmentMatrix('segmentAgglomerative', request.data, request.rows, request.cols, 'data');
602
+ assertPositiveInteger('segmentAgglomerative', request.k, 'k');
603
+ return requireModule().segmentAgglomerative(
604
+ request.data,
605
+ request.rows,
606
+ request.cols,
607
+ request.k,
608
+ request.linkage ?? 'average',
609
+ );
610
+ }
611
+
612
+ /** Enhance diagonal paths in an `n × n` recurrence matrix. */
613
+ export function segmentPathEnhance(request: SegmentPathEnhanceRequest): SegmentMatrix {
614
+ validateSegmentMatrix(
615
+ 'segmentPathEnhance',
616
+ request.recurrence,
617
+ request.n,
618
+ request.n,
619
+ 'recurrence',
620
+ );
621
+ assertPositiveInteger('segmentPathEnhance', request.win, 'win');
622
+ assertPositiveInteger('segmentPathEnhance', request.maxRatio ?? 2, 'maxRatio');
623
+ assertNonNegativeInteger('segmentPathEnhance', request.minRatio ?? 0, 'minRatio');
624
+ assertPositiveInteger('segmentPathEnhance', request.nFilters ?? 7, 'nFilters');
625
+ return requireModule().segmentPathEnhance(
626
+ request.recurrence,
627
+ request.n,
628
+ request.win,
629
+ request.maxRatio ?? 2,
630
+ request.minRatio ?? 0,
631
+ request.nFilters ?? 7,
632
+ );
633
+ }