@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
@@ -20,11 +20,13 @@ import type {
20
20
  Key,
21
21
  KeyCandidate,
22
22
  KeyDetectionOptions,
23
+ MeterEstimate,
23
24
  RirResult,
24
25
  RirSynthOptions,
25
26
  RoomEstimateOptions,
26
27
  RoomEstimateResult,
27
28
  RoomMorphOptions,
29
+ RoomMorphResult,
28
30
  } from './public_types';
29
31
  import { Mode, PitchClass } from './public_types';
30
32
  import type { ProgressCallback, WasmAcousticResult } from './sonare.js';
@@ -71,6 +73,8 @@ export interface DetectKeyRequest extends KeyDetectionOptions, SamplesRequest {}
71
73
  export interface AnalyzeWithProgressRequest extends SamplesRequest {
72
74
  onProgress?: ProgressCallback;
73
75
  cancel?: () => boolean;
76
+ /** Analysis options, with the same fields and defaults {@link analyze} takes. */
77
+ options?: MusicAnalyzeOptions;
74
78
  }
75
79
 
76
80
  /** Canonical request form for chord detection. */
@@ -147,6 +151,9 @@ export function detectBpm(
147
151
  /**
148
152
  * Detect musical key from audio samples.
149
153
  *
154
+ * The chroma is read at concert A440; a tuning offset is applied through
155
+ * {@link analyze}'s `tuning` option (and to chords through {@link detectChords}).
156
+ *
150
157
  * @param samples - Audio samples (mono, float32)
151
158
  * @param sampleRate - Sample rate in Hz (default: 22050)
152
159
  * @returns Detected key
@@ -330,6 +337,7 @@ export function detectChords(
330
337
  request.keyMode ?? Mode.Major,
331
338
  request.detectInversions ?? false,
332
339
  chordChromaMethodValue(request.chromaMethod ?? 'stft'),
340
+ request.tuning ?? 0,
333
341
  );
334
342
  return convertChordAnalysisResult(result);
335
343
  }
@@ -383,23 +391,13 @@ export function chordFunctionalAnalysis(
383
391
  request.useKeyContext ?? false,
384
392
  request.detectInversions ?? false,
385
393
  chordChromaMethodValue(request.chromaMethod ?? 'stft'),
394
+ request.tuning ?? 0,
386
395
  );
387
396
  }
388
397
 
389
398
  /**
390
- * Perform complete music analysis.
391
- *
392
- * @param samples - Audio samples (mono, float32)
393
- * @param sampleRate - Sample rate in Hz (default: 22050)
394
- * @returns Complete analysis result
395
- *
396
- * @remarks
397
- * This call is synchronous and blocks until analysis completes. Unlike the
398
- * Node binding (which offers `analyzeAsync` on a libuv worker thread), the
399
- * WASM build runs on a single thread, so there is no non-blocking variant —
400
- * the DSP pipeline always runs to completion on the calling thread. To keep
401
- * the UI responsive for long inputs, drive this from a Web Worker and use
402
- * {@link analyzeWithProgress} to report progress.
399
+ * Options for {@link analyze}. Every field is optional and falls back to the
400
+ * core default when omitted.
403
401
  */
404
402
  export interface MusicAnalyzeOptions {
405
403
  nFft?: number;
@@ -416,9 +414,68 @@ export interface MusicAnalyzeOptions {
416
414
  useChordKeyContext?: boolean;
417
415
  chordHmmBeamWidth?: number;
418
416
  detectChordInversions?: boolean;
417
+ /**
418
+ * Track a locally updated tempo prior during beat tracking (default: false).
419
+ */
420
+ adaptiveTempo?: boolean;
421
+ /**
422
+ * Length of the local tempo context in beats (default: 8). Must be positive.
423
+ */
424
+ tempoUpdateIntervalBeats?: number;
425
+ /**
426
+ * Decode a per-beat local tempo curve into
427
+ * {@link AnalysisResult.beatLocalBpm} (default: false).
428
+ *
429
+ * @remarks
430
+ * Off by default because it is an extra output rather than a better analysis:
431
+ * nothing else in the result changes, and a caller that does not read the
432
+ * curve would pay a decode over the beat grid for nothing.
433
+ *
434
+ * The curve describes the beat grid it was decoded from, and beat tracking
435
+ * holds a fixed tempo prior unless {@link MusicAnalyzeOptions.adaptiveTempo}
436
+ * is also set, so measuring a tempo that moves needs both.
437
+ */
438
+ computeTempoCurve?: boolean;
439
+ /**
440
+ * Meter numerators the estimator scores (default: `[3, 4, 6]`).
441
+ *
442
+ * @remarks
443
+ * Adding a numerator widens the search; it does not force the result. The
444
+ * list must hold between 1 and 16 entries, each in `[2, 32]`.
445
+ */
446
+ meterCandidateNumerators?: number[];
447
+ /**
448
+ * Beat unit reported for the detected meter (default: 4). Must be a power of
449
+ * two in `[1, 32]`. The estimator still reports 8 on its own when it resolves
450
+ * a compound meter, so this is the unit for everything else.
451
+ */
452
+ meterDenominator?: number;
453
+ /**
454
+ * Tuning offset of the recording in fractions of a semitone, the unit
455
+ * `estimateTuning` returns; must be in `[-0.5, 0.5)`. Every chroma the
456
+ * analysis builds (key, chords, sections) is shifted by it, so a recording
457
+ * that is not at A440 reads its key and chords on its own pitch grid.
458
+ * Default 0 (concert A440).
459
+ */
460
+ tuning?: number;
419
461
  }
420
462
  export interface MusicAnalyzeRequest extends SamplesRequest, MusicAnalyzeOptions {}
421
463
 
464
+ /**
465
+ * Perform complete music analysis.
466
+ *
467
+ * @param samples - Audio samples (mono, float32)
468
+ * @param sampleRate - Sample rate in Hz (default: 22050)
469
+ * @returns Complete analysis result
470
+ *
471
+ * @remarks
472
+ * This call is synchronous and blocks until analysis completes. Unlike the
473
+ * Node binding (which offers `analyzeAsync` on a libuv worker thread), the
474
+ * WASM build runs on a single thread, so there is no non-blocking variant —
475
+ * the DSP pipeline always runs to completion on the calling thread. To keep
476
+ * the UI responsive for long inputs, drive this from a Web Worker and use
477
+ * {@link analyzeWithProgress} to report progress.
478
+ */
422
479
  export function analyze(request: MusicAnalyzeRequest): AnalysisResult;
423
480
  export function analyze(
424
481
  samples: Float32Array,
@@ -436,6 +493,98 @@ export function analyze(
436
493
  return convertAnalysisResult(result);
437
494
  }
438
495
 
496
+ /**
497
+ * Canonical request form for {@link estimateMeter}.
498
+ *
499
+ * @remarks
500
+ * Every scoring field is optional and falls back to the core default when
501
+ * omitted; the core validates them and rejects a value it cannot answer rather
502
+ * than substituting one.
503
+ */
504
+ export interface EstimateMeterRequest {
505
+ /** Beat positions in seconds, non-decreasing. */
506
+ beatTimes: ArrayLike<number>;
507
+ /**
508
+ * Per-beat accent value, the same length as {@link beatTimes}.
509
+ *
510
+ * @remarks
511
+ * `AnalysisResult.beatObservations.onsetStrength` is the intended source —
512
+ * it is the windowed value the library's own downbeat pass scores.
513
+ * `beats[].strength` also works but is a single unwindowed envelope frame.
514
+ * Neither needs pre-scaling: the series is divided by its own maximum before
515
+ * scoring, so only the accent contrast within it is read.
516
+ *
517
+ * A series assembled by hand from {@link onsetEnvelope} — one frame read at
518
+ * each beat time — is neither of those, and it carries a sample-rate
519
+ * dependence neither of them has: a hop counted in samples frames a different
520
+ * amount of time at each rate, so one waveform sampled at 32000, 44100 and
521
+ * 48000 Hz has produced three different winning numerators off beat times
522
+ * identical to the sample. Widening the read to a window around the beat does
523
+ * not remove it. A browser decodes at the output device's rate, so that is a
524
+ * different answer per visitor for the same clip.
525
+ */
526
+ beatStrengths: ArrayLike<number>;
527
+ /**
528
+ * Meter numerators to score (default: `[3, 4, 6]`).
529
+ *
530
+ * @remarks
531
+ * Adding a numerator widens the search; it does not force the result. The
532
+ * list must hold between 1 and 16 entries, each in `[2, 32]`.
533
+ */
534
+ candidateNumerators?: number[];
535
+ /**
536
+ * Beat unit reported for the detected meter (default: 4). Must be a power of
537
+ * two in `[1, 32]`.
538
+ *
539
+ * @remarks
540
+ * Reported as requested: whether a beat divides into three is measured from
541
+ * energy *between* the beats, which per-beat accents do not carry, so a
542
+ * compound meter is not resolvable here. A six accented 3+3 comes back with
543
+ * this denominator and `grouping === [3, 3]`.
544
+ */
545
+ denominator?: number;
546
+ /** Weight of the downbeat accent term (default: 1). */
547
+ downbeatWeight?: number;
548
+ /** Weight of the measure-periodicity term (default: 0.5). */
549
+ measureWeight?: number;
550
+ /** Weight of the subdivision term (default: 0.15). */
551
+ subdivisionWeight?: number;
552
+ /**
553
+ * Score ratio above which a compound meter is preferred (default: 0.85).
554
+ *
555
+ * @remarks
556
+ * Only consulted when there is a subdivision to measure, so it has no effect
557
+ * here — this entry point scores per-beat accents alone.
558
+ */
559
+ compoundSubdivisionThreshold?: number;
560
+ }
561
+
562
+ /**
563
+ * Estimate meter over a caller-supplied beat series.
564
+ *
565
+ * @param request - Beat series plus optional scoring configuration
566
+ * @returns The selected signature, its downbeat phase and grouping, and the
567
+ * scored candidates
568
+ *
569
+ * @remarks
570
+ * Scores only the per-beat strengths, so no audio and no frame-level onset
571
+ * envelope is needed: an arbitrary span of an existing analysis can be scored
572
+ * without re-running it. Pass `beatObservations.onsetStrength` rather than
573
+ * `beats[].strength` — see {@link EstimateMeterRequest.beatStrengths}.
574
+ *
575
+ * The result carries `grouping` alongside the numerator: how the bar divides
576
+ * into accent groups of two and three beats, so a seven comes back as `[3, 2,
577
+ * 2]` or `[2, 2, 3]` rather than as a bare seven.
578
+ *
579
+ * Check `searched` before reading anything as a detection: a series too short
580
+ * to score any candidate reports a fixed fallback instead, and `candidateScores`
581
+ * grows with the square root of how many beats were scored, so scores from
582
+ * spans of different lengths are not directly comparable.
583
+ */
584
+ export function estimateMeter(request: EstimateMeterRequest): MeterEstimate {
585
+ return requireModule().estimateMeter(request.beatTimes, request.beatStrengths, request);
586
+ }
587
+
439
588
  export function analyzeImpulseResponse(request: AnalyzeImpulseResponseRequest): AcousticResult;
440
589
  export function analyzeImpulseResponse(
441
590
  samples: Float32Array,
@@ -451,9 +600,11 @@ export function analyzeImpulseResponse(
451
600
  ): AcousticResult {
452
601
  const request =
453
602
  samples instanceof Float32Array ? { samples, sampleRate, nOctaveBands, minDecayDb } : samples;
454
- if (request.minDecayDb === null) {
455
- throw new TypeError('analyzeImpulseResponse: minDecayDb must be a finite number');
456
- }
603
+ // Only `undefined` takes the default. `null` falls through to
604
+ // assertFiniteScalar, which refuses it with the same wording as any other
605
+ // non-finite value -- Number.isFinite(null) is false, so the case needs no
606
+ // branch of its own, and the one that was here answered it with a different
607
+ // error class than the check three lines down.
457
608
  const resolvedMinDecayDb = request.minDecayDb === undefined ? 30.0 : request.minDecayDb;
458
609
  assertFiniteScalar('analyzeImpulseResponse', resolvedMinDecayDb, 'minDecayDb');
459
610
  if (resolvedMinDecayDb <= 0) {
@@ -536,20 +687,23 @@ export function estimateRoom(
536
687
 
537
688
  /**
538
689
  * Morph a recording's reverberation toward a target room (creative FX, not
539
- * dereverberation). Returns the morphed samples (input length plus the target
540
- * room's reverb tail).
690
+ * dereverberation).
691
+ *
692
+ * Returns the morphed samples in `audio` (input length plus the target room's
693
+ * reverb tail) alongside the target-room synthesis's own `diagnostics`, which
694
+ * report a room other than the one requested — see {@link RoomMorphResult}.
541
695
  */
542
- export function roomMorph(request: RoomMorphRequest): Float32Array;
696
+ export function roomMorph(request: RoomMorphRequest): RoomMorphResult;
543
697
  export function roomMorph(
544
698
  samples: Float32Array,
545
699
  sampleRate: number,
546
700
  options?: RoomMorphOptions,
547
- ): Float32Array;
701
+ ): RoomMorphResult;
548
702
  export function roomMorph(
549
703
  samples: Float32Array | RoomMorphRequest,
550
704
  sampleRate?: number,
551
705
  options: RoomMorphOptions = {},
552
- ): Float32Array {
706
+ ): RoomMorphResult {
553
707
  const module = requireModule();
554
708
  if (typeof module.roomMorph !== 'function') {
555
709
  throw new Error('libsonare was built without acoustic-simulation support');
@@ -575,15 +729,17 @@ export function analyzeWithProgress(
575
729
  samples: Float32Array,
576
730
  sampleRate: number | undefined,
577
731
  onProgress: ProgressCallback,
732
+ options?: MusicAnalyzeOptions,
578
733
  ): AnalysisResult;
579
734
  export function analyzeWithProgress(
580
735
  samples: Float32Array | AnalyzeWithProgressRequest,
581
736
  sampleRate = 22050,
582
737
  onProgress?: ProgressCallback,
738
+ options?: MusicAnalyzeOptions,
583
739
  ): AnalysisResult {
584
740
  const request: AnalyzeWithProgressRequest =
585
741
  samples instanceof Float32Array
586
- ? { samples, sampleRate, onProgress: onProgress as ProgressCallback }
742
+ ? { samples, sampleRate, onProgress: onProgress as ProgressCallback, options }
587
743
  : samples;
588
744
  validateAnalysisInput(
589
745
  'analyzeWithProgress',
@@ -591,9 +747,11 @@ export function analyzeWithProgress(
591
747
  request.sampleRate ?? 22050,
592
748
  request,
593
749
  );
750
+ // The module reads options with the same reader analyze uses.
594
751
  const result = requireModule().analyzeWithProgress(
595
752
  request.samples,
596
753
  request.sampleRate ?? 22050,
754
+ request.options ?? {},
597
755
  request.onProgress ?? (() => {}),
598
756
  request.cancel ?? (() => false),
599
757
  );
@@ -619,11 +777,24 @@ export interface RhythmAnalysisResult {
619
777
  grooveType: string;
620
778
  patternRegularity: number;
621
779
  tempoStability: number;
780
+ /**
781
+ * The beat tracker's own tempo, refined from the local beat period. It is a
782
+ * third figure rather than either tempo entry point's: measured against
783
+ * synthesized click trains it differs from both at every sample rate, and
784
+ * lands closer to the known tempo than either. Analysed at the sample rate
785
+ * you pass, so `nFft` and `hopLength` are in samples of your buffer.
786
+ */
622
787
  bpm: number;
623
788
  beatIntervals: Float32Array;
624
789
  }
625
790
 
626
- export interface DynamicsAnalysisResult {
791
+ /**
792
+ * Dynamics metrics returned by {@link analyzeDynamics}.
793
+ *
794
+ * The Node package declares the same shape under the same name; the two are
795
+ * pinned to one field list by `tests/conformance/shared_type_shapes.json`.
796
+ */
797
+ export interface DynamicsResult {
627
798
  dynamicRangeDb: number;
628
799
  peakDb: number;
629
800
  rmsDb: number;
@@ -636,6 +807,12 @@ export interface DynamicsAnalysisResult {
636
807
  loudnessRmsDb: Float32Array;
637
808
  }
638
809
 
810
+ /**
811
+ * @deprecated Use {@link DynamicsResult}. Retained so code written against the
812
+ * WASM-only spelling keeps compiling; the Node package exports the same alias.
813
+ */
814
+ export type DynamicsAnalysisResult = DynamicsResult;
815
+
639
816
  /** Timbre metrics for one analysis window. Entries are ordered by time in `timbreOverTime`. */
640
817
  export interface TimbreFrame {
641
818
  brightness: number;
@@ -713,17 +890,17 @@ export function analyzeRhythm(
713
890
  /**
714
891
  * Dynamics analysis (RMS, peak, crest factor, LRA, loudness curve).
715
892
  */
716
- export function analyzeDynamics(request: AnalyzeDynamicsRequest): DynamicsAnalysisResult;
893
+ export function analyzeDynamics(request: AnalyzeDynamicsRequest): DynamicsResult;
717
894
  export function analyzeDynamics(
718
895
  samples: Float32Array,
719
896
  sampleRate?: number,
720
897
  options?: AnalyzeDynamicsOptions,
721
- ): DynamicsAnalysisResult;
898
+ ): DynamicsResult;
722
899
  export function analyzeDynamics(
723
900
  samples: Float32Array | AnalyzeDynamicsRequest,
724
901
  sampleRate = 22050,
725
902
  options: AnalyzeDynamicsOptions = {},
726
- ): DynamicsAnalysisResult {
903
+ ): DynamicsResult {
727
904
  const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
728
905
  validateAnalysisInput('analyzeDynamics', request.samples, request.sampleRate ?? 22050, request);
729
906
  return requireModule().analyzeDynamics(