@libraz/libsonare 1.7.2 → 1.8.1

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 +7 -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 +874 -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 +502 -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 +134 -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 +4173 -1621
  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 +483 -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 +654 -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 +528 -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 +165 -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 +893 -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 +3945 -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 +340 -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 +164 -0
  179. package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
  180. package/dist/worklet/engine-node.d.ts +83 -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 +72 -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 +75 -0
  193. package/dist/worklet/engine-strips.d.ts.map +1 -0
  194. package/dist/worklet/engine-sync.d.ts +39 -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 +418 -0
  199. package/dist/worklet/engine.d.ts.map +1 -0
  200. package/dist/worklet/guards.d.ts +53 -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 +331 -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 +3200 -541
  215. package/dist/worklet.js.map +1 -1
  216. package/package.json +23 -12
  217. package/src/_effects_common.ts +47 -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 +101 -22
  226. package/src/effects_note_ops.ts +683 -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 +388 -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 +288 -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 +441 -32
  246. package/src/mastering_dynamics.ts +22 -11
  247. package/src/metering.ts +67 -24
  248. package/src/mixer.ts +251 -22
  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 +271 -271
  259. package/src/public_types.ts +122 -3
  260. package/src/public_types_acoustic.ts +112 -3
  261. package/src/public_types_mastering.ts +275 -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 +196 -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 +491 -5
  268. package/src/quick_analysis.ts +203 -26
  269. package/src/realtime_engine.ts +773 -34
  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 +1158 -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 +202 -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 +800 -32
  287. package/src/worklet/engine-node.ts +99 -29
  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 +332 -93
  291. package/src/worklet/engine-register.ts +32 -18
  292. package/src/worklet/engine-strips.ts +275 -9
  293. package/src/worklet/engine-sync.ts +20 -7
  294. package/src/worklet/engine.ts +394 -48
  295. package/src/worklet/guards.ts +195 -44
  296. package/src/worklet/messages.ts +229 -2
  297. package/src/worklet/mixer-processor.ts +117 -48
  298. package/src/worklet/playback-processor.ts +300 -0
  299. package/src/worklet/protocol.ts +82 -11
  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
@@ -85,12 +85,28 @@ export const ChordQuality = {
85
85
  Major9: 14,
86
86
  Dominant9: 15,
87
87
  Sus2Add4: 16,
88
+ Major6: 17,
89
+ Minor6: 18,
90
+ MinorMajor7: 19,
91
+ Dominant7Sus4: 20,
92
+ Dominant11: 21,
93
+ Dominant13: 22,
94
+ Dominant7Flat9: 23,
95
+ Dominant7Sharp9: 24,
88
96
  } as const;
89
97
 
90
98
  export type ChordQuality = (typeof ChordQuality)[keyof typeof ChordQuality];
91
99
 
92
100
  /**
93
- * Section type
101
+ * Section type.
102
+ *
103
+ * `PreChorus` is never produced by `analyze()`: it has no detection branch, so
104
+ * filtering sections on it always yields an empty result. Every other value is
105
+ * reachable. `Unknown` means the analyzer did not name the segment: no
106
+ * boundary was detected, the segment matched none of the positive branches, or
107
+ * the evidence for a musical function was too weak to assert one. The first
108
+ * case comes with `confidence` 0; the last keeps the sub-threshold score, so a
109
+ * caller can see how close the segment came to a label.
94
110
  */
95
111
  export const SectionType = {
96
112
  Intro: 0,
@@ -111,6 +127,20 @@ export type SectionType = (typeof SectionType)[keyof typeof SectionType];
111
127
  export interface Key {
112
128
  root: PitchClass;
113
129
  mode: Mode;
130
+ /**
131
+ * Share of the model's belief that this key is the answer, in `[0, 1)`.
132
+ *
133
+ * A softmax over the profile correlations of every candidate that was scored,
134
+ * so it falls as the runner-up closes in and two keys that split the evidence
135
+ * -- a relative major and minor, typically -- each report about half.
136
+ *
137
+ * This is the model's own belief, **not** a measured accuracy. It says how
138
+ * decisively the chroma picked this key out of the candidate set; it does not
139
+ * say how often that pick is right, and nothing here has been fitted against
140
+ * annotated recordings. A confident wrong answer is entirely possible, so a
141
+ * pipeline that branches on it must choose its own threshold against its own
142
+ * material.
143
+ */
114
144
  confidence: number;
115
145
  name: string;
116
146
  shortName: string;
@@ -143,6 +173,7 @@ export interface ChordDetectionOptions extends ValidateOptions {
143
173
  /** Final-template correlation threshold in [0, 1]; below it emits Unknown / N.C. */
144
174
  threshold?: number;
145
175
  useTriadsOnly?: boolean;
176
+ /** STFT chroma window in samples at 22050 Hz, rescaled to the input rate so its duration is the same at every rate. */
146
177
  nFft?: number;
147
178
  hopLength?: number;
148
179
  useBeatSync?: boolean;
@@ -153,6 +184,11 @@ export interface ChordDetectionOptions extends ValidateOptions {
153
184
  keyMode?: Mode;
154
185
  detectInversions?: boolean;
155
186
  chromaMethod?: 'stft' | 'nnls';
187
+ /**
188
+ * Tuning offset of the recording in fractions of a semitone, the unit
189
+ * `estimateTuning` returns; must be in `[-0.5, 0.5)`. Default 0 (concert A440).
190
+ */
191
+ tuning?: number;
156
192
  }
157
193
 
158
194
  /** Options for `analyzeBpm`. All fields are optional. */
@@ -223,10 +259,52 @@ export interface AnalyzeSectionsOptions {
223
259
  * Detected beat
224
260
  */
225
261
  export interface Beat {
262
+ /** Beat position in seconds. */
226
263
  time: number;
264
+ /**
265
+ * Onset-envelope value sampled at the beat's frame.
266
+ *
267
+ * @remarks
268
+ * A single raw frame of the onset envelope, not a normalized or relative
269
+ * salience: it is unbounded, its scale depends on the material, and it moves
270
+ * with any jitter in the beat position. For accent scoring use
271
+ * {@link BeatObservations.onsetStrength}, which is the windowed aggregate the
272
+ * library's own downbeat pass scores.
273
+ */
227
274
  strength: number;
228
275
  }
229
276
 
277
+ /**
278
+ * Beat-level evidence behind the downbeat and meter decisions.
279
+ *
280
+ * @remarks
281
+ * These are inputs to the library's decision, not outputs of it, exposed so a
282
+ * caller running its own meter work scores the same evidence instead of
283
+ * reconstructing a weaker approximation from the frame-level onset envelope.
284
+ * Each non-empty stream holds one value per entry of
285
+ * {@link AnalysisResult.beats} and indexes in parallel with it. An empty stream
286
+ * means the analysis could not produce it, which is not the same as every beat
287
+ * having scored zero.
288
+ */
289
+ export interface BeatObservations {
290
+ /**
291
+ * Beat-local onset-strength window.
292
+ *
293
+ * @remarks
294
+ * Unlike {@link Beat.strength} this is aggregated over a window around the
295
+ * beat rather than sampled at a single frame, so it is the stream to score
296
+ * accents with.
297
+ */
298
+ onsetStrength: number[];
299
+ /**
300
+ * Beat-local low-frequency energy — the accent evidence a log-spectral
301
+ * difference discards. Empty when the analysis ran without audio.
302
+ */
303
+ lowFrequencyEnergy: number[];
304
+ /** Per-beat chord-change evidence. Empty until chords are analyzed. */
305
+ chordChange: number[];
306
+ }
307
+
230
308
  /**
231
309
  * Detected chord
232
310
  */
@@ -240,10 +318,22 @@ export interface Chord {
240
318
  quality: ChordQuality;
241
319
  start: number;
242
320
  end: number;
321
+ /** Derived from `end - start`; the core carries only the two endpoints. */
322
+ duration: number;
243
323
  confidence: number;
244
324
  name: string;
245
325
  }
246
326
 
327
+ /** A chord in {@link AnalysisResult.chords}, which carries its function in the key. */
328
+ export interface AnalysisChord extends Chord {
329
+ /**
330
+ * Roman numeral of the chord relative to {@link AnalysisResult.key}, e.g.
331
+ * `'V7'`, `'vi'`, `'bVII'`. The same spelling `chordFunctionalAnalysis`
332
+ * returns for that chord and key. Empty for a chord that is N.C.
333
+ */
334
+ romanNumeral: string;
335
+ }
336
+
247
337
  export interface ChordAnalysisResult {
248
338
  chords: Chord[];
249
339
  }
@@ -260,6 +350,94 @@ export interface Section {
260
350
  name: string;
261
351
  }
262
352
 
353
+ /** Options for `detectBoundaries`. All fields are optional. */
354
+ export interface BoundaryOptions {
355
+ /** FFT size used for the structural features. Default 2048. */
356
+ nFft?: number;
357
+ /** Hop length in samples. Default 512. */
358
+ hopLength?: number;
359
+ /** Checkerboard kernel size in frames. Default 64. */
360
+ kernelSize?: number;
361
+ /**
362
+ * Relative novelty threshold, applied to the curve after it has been scaled by
363
+ * its own maximum. Selects how prominent a peak must be *within this track*; it
364
+ * says nothing about how much the features actually changed. Default 0.3.
365
+ */
366
+ threshold?: number;
367
+ /**
368
+ * Novelty floor applied to the raw response before that scaling, asking whether
369
+ * anything changed at all. Default 0.005. Set to 0 to gate on {@link threshold}
370
+ * alone -- but self-scaling turns residual fluctuation into peaks of 1.0, so a
371
+ * stationary input then segments anyway. Lowering the floor does not recover
372
+ * level-only structure: a level change turns the feature vector about five times
373
+ * less than a comparable pitch change, landing below what steady noise produces,
374
+ * so the noise is admitted first.
375
+ */
376
+ absoluteThreshold?: number;
377
+ /** Number of MFCC coefficients. Default 13. */
378
+ nMfcc?: number;
379
+ /** Number of chroma bins. Default 12. */
380
+ nChroma?: number;
381
+ /** Minimum spacing between peaks, in seconds. Default 2. */
382
+ peakDistance?: number;
383
+ /** Use MFCC features. Default `true`. */
384
+ useMfcc?: boolean;
385
+ /** Use chroma features. Default `true`. */
386
+ useChroma?: boolean;
387
+ }
388
+
389
+ /**
390
+ * A single detected structural boundary (mirrors the C `SonareBoundary`).
391
+ */
392
+ export interface Boundary {
393
+ /** Boundary time in seconds (the authoritative output). */
394
+ time: number;
395
+ /**
396
+ * Index into the analysis grid, on {@link BoundaryResult.sampleRate}'s time
397
+ * base rather than the source's. For a long-form input the feature grid is
398
+ * additionally mean-pooled, so this indexes the pooled grid; use `time` for
399
+ * sample/second mapping either way.
400
+ */
401
+ frame: number;
402
+ /** Boundary strength (novelty score). */
403
+ strength: number;
404
+ }
405
+
406
+ /**
407
+ * Result of `detectBoundaries` (mirrors the C `SonareBoundaryResult`).
408
+ */
409
+ export interface BoundaryResult {
410
+ /** Detected transitions, in time order. */
411
+ boundaries: Boundary[];
412
+ /**
413
+ * Novelty curve scaled by its own maximum, one value per analysis frame. A
414
+ * peak of 1 means "the most novel frame here", not "a large change"; multiply
415
+ * by {@link noveltyPeak} to recover the raw response
416
+ * {@link BoundaryOptions.absoluteThreshold} is compared against.
417
+ */
418
+ noveltyCurve: Float32Array;
419
+ /**
420
+ * The largest raw checkerboard response, before normalization. Zero when the
421
+ * curve was left unnormalized because nothing rose above the numerical floor.
422
+ */
423
+ noveltyPeak: number;
424
+ /**
425
+ * The rate the analysis ran at, not the input's: a source above 22050 Hz is
426
+ * resampled to 22050 Hz before any feature is computed, which is what makes
427
+ * {@link Boundary.frame} interpretable.
428
+ */
429
+ sampleRate: number;
430
+ /** Hop length the analysis grid was built on. */
431
+ hopLength: number;
432
+ /** Analysis frame count, pooled for a long-form input. */
433
+ nFrames: number;
434
+ /**
435
+ * Feature pooling stride: 1 for every realistic input length, otherwise the
436
+ * number of raw STFT frames averaged into each analysis frame.
437
+ */
438
+ frameStride: number;
439
+ }
440
+
263
441
  /**
264
442
  * A single melody contour point (mirrors the C `SonareMelodyPoint`).
265
443
  */
@@ -312,9 +490,96 @@ export interface Dynamics {
312
490
  export interface TimeSignature {
313
491
  numerator: number;
314
492
  denominator: number;
493
+ /**
494
+ * Support for this signature in `[0, 1]`.
495
+ *
496
+ * @remarks
497
+ * What it measures depends on which field the signature arrived in. On
498
+ * {@link MeterEstimate.timeSignature} it is derived from the margin over the
499
+ * runner-up; on a {@link MeterEstimate.candidates} entry it is that
500
+ * candidate's share of the summed support. The two are not comparable, so
501
+ * read the value from the field you meant rather than from whichever one is
502
+ * to hand.
503
+ */
315
504
  confidence: number;
316
505
  }
317
506
 
507
+ /**
508
+ * Meter estimated over a caller-supplied beat series.
509
+ */
510
+ export interface MeterEstimate {
511
+ /**
512
+ * Selected time signature.
513
+ *
514
+ * @remarks
515
+ * Its `confidence` is the margin over the runner-up — how separated the
516
+ * winner is — not the share-of-support a {@link candidates} entry carries
517
+ * under the same field name.
518
+ */
519
+ timeSignature: TimeSignature;
520
+ /** Beat index the first measure starts on, in `[0, timeSignature.numerator)`. */
521
+ downbeatPhase: number;
522
+ /**
523
+ * Whether a search ran, as opposed to the fixed fallback being reported.
524
+ *
525
+ * @remarks
526
+ * `false` means the beat series was too short to score any candidate, and
527
+ * every other field then carries that fallback rather than a measurement —
528
+ * `timeSignature.confidence` included, which is 0, so an unchecked read
529
+ * degrades toward "no idea" rather than toward a middling detection. Read
530
+ * this before treating a short span's answer as a detection.
531
+ */
532
+ searched: boolean;
533
+ /**
534
+ * How the bar divides, in beats per accent group.
535
+ *
536
+ * @remarks
537
+ * `[3, 2, 2]` is the 7/8 an aksak meter notates as 3+2+2, and `[2, 2]` an
538
+ * ordinary four. Always sums to `timeSignature.numerator`.
539
+ *
540
+ * A single entry means no internal division was resolved — the numerator has
541
+ * none to find, it was too wide to search, or the span was too short to
542
+ * search at all.
543
+ *
544
+ * This is also what tells a compound bar from a simple one: per-beat accents
545
+ * cannot say how a beat subdivides, so a six accented 3+3 keeps the requested
546
+ * denominator and reports `[3, 3]` rather than being promoted to 6/8.
547
+ */
548
+ grouping: number[];
549
+ /**
550
+ * Multi-comb score per requested candidate numerator.
551
+ *
552
+ * @remarks
553
+ * Parallel to the `candidateNumerators` that were requested, in the order
554
+ * they were given. This does NOT index alike with {@link candidates}, which
555
+ * is ordered by descending support.
556
+ *
557
+ * Standardized and signed: zero is the level a numerator reaches on beats
558
+ * carrying no meter, so a negative entry means less support than noise would
559
+ * produce. Only the ordering and the gaps between entries carry meaning.
560
+ *
561
+ * Comparable only within one result. A score grows with the square root of
562
+ * how many beats were scored, so the same meter over twice the beats scores
563
+ * about 1.41 times as high; a segmentation search comparing spans of
564
+ * different lengths has to normalize for length first.
565
+ */
566
+ candidateScores: number[];
567
+ /**
568
+ * Candidate signatures ordered by descending support.
569
+ *
570
+ * @remarks
571
+ * A ranking, so entry `k` is the k-th best hypothesis — not the k-th
572
+ * requested numerator. Use {@link candidateScores} to read the score of a
573
+ * specific requested numerator.
574
+ *
575
+ * Each entry's `confidence` is that candidate's share of the summed support,
576
+ * so the entries sum to one. It is a different quantity from
577
+ * {@link timeSignature}'s margin-derived confidence, which shares the field
578
+ * name and nothing else.
579
+ */
580
+ candidates: TimeSignature[];
581
+ }
582
+
318
583
  /** Existing tempo-estimator hypothesis retained by unified analysis. */
319
584
  export interface BpmHypothesis {
320
585
  value: number;
@@ -356,7 +621,52 @@ export interface AnalysisResult {
356
621
  timeSignatureCandidates: TimeSignature[];
357
622
  beatTimes: Float32Array;
358
623
  beats: Beat[];
359
- chords: Chord[];
624
+ /**
625
+ * Indices into {@link AnalysisResult.beats} that fall on a measure start.
626
+ *
627
+ * @remarks
628
+ * Not the same length as `beats` — it holds one entry per detected downbeat,
629
+ * and each entry indexes `beats`, so `beats[downbeatIndices[k]]` is the k-th
630
+ * downbeat. Testing a beat for downbeat status is a membership check on this
631
+ * list rather than a time comparison against a separate downbeat series.
632
+ */
633
+ downbeatIndices: number[];
634
+ /**
635
+ * Beat index the first measure starts on, in `[0, timeSignature.numerator)`.
636
+ *
637
+ * @remarks
638
+ * The meter estimator's phase, so `downbeatIndices` normally begins at this
639
+ * value. It is not re-derived when downbeats are refined from chord and
640
+ * low-frequency-energy evidence, so the two can disagree when the refinement
641
+ * moves the first measure start.
642
+ */
643
+ downbeatPhase: number;
644
+ /**
645
+ * Beat-level evidence behind the downbeat and meter decisions, parallel to
646
+ * {@link AnalysisResult.beats}.
647
+ */
648
+ beatObservations: BeatObservations;
649
+ /**
650
+ * Smoothed local tempo at each beat, in BPM, parallel to
651
+ * {@link AnalysisResult.beats}.
652
+ *
653
+ * @remarks
654
+ * Empty unless `computeTempoCurve` was set, and empty regardless when fewer
655
+ * than two beats were detected, since a tempo is a property of the interval
656
+ * between two beats. The last entry repeats the tempo of the interval leading
657
+ * into the final beat, which opens no interval of its own.
658
+ *
659
+ * Values are continuous, not points on a tempo grid: each is a weighted
660
+ * average, in log tempo, of the beat intervals around it. A steady tempo
661
+ * reads within about 1% at every beat, and a tempo that moves is followed a
662
+ * few beats late.
663
+ *
664
+ * This is the local tempo rather than {@link AnalysisResult.bpm} resampled:
665
+ * on material whose tempo moves it departs from `bpm`, and reading a single
666
+ * number out of it is not how to get the global tempo.
667
+ */
668
+ beatLocalBpm: number[];
669
+ chords: AnalysisChord[];
360
670
  sections: Section[];
361
671
  timbre: Timbre;
362
672
  dynamics: Dynamics;
@@ -0,0 +1,196 @@
1
+ // Type-only: erased before runtime, so this does not create a module cycle with
2
+ // playback_renderer.ts, which imports the config types declared below.
3
+ import type { HrtfSet } from './playback_renderer';
4
+
5
+ /**
6
+ * The playback renderer configuration document, in the schema
7
+ * `schemas/playback-renderer-config.schema.json` (also shipped as the
8
+ * `./schemas/playback-renderer-config.schema.json` package export). Field
9
+ * spelling is the schema's own (snake_case, dotted nesting) rather than this
10
+ * binding's usual camelCase: the document is parsed by the shared C++ core, so
11
+ * every surface has to agree on one literal spelling.
12
+ *
13
+ * Every key is either a "prepare" key (fixed at {@link PlaybackRenderer}
14
+ * construction; changing one through `setConfig` throws) or a "realtime" key
15
+ * (adopted at the next processed block). Omitted keys take the schema defaults
16
+ * documented on each field below.
17
+ */
18
+ export interface PlaybackRendererConfig {
19
+ input?: PlaybackInputConfig;
20
+ target?: PlaybackTargetConfig;
21
+ /** LFE level folded into L/R when the output has no LFE plane or no subwoofer. Realtime, default 0. */
22
+ lfe_mix_db?: number;
23
+ upmix?: PlaybackUpmixConfig;
24
+ /** Static gain on the discrete centre of 5.1 / 7.1 input. Realtime, [-12, 12], default 0. */
25
+ dialogue_level_db?: number;
26
+ loudness?: PlaybackLoudnessConfig;
27
+ night_mode?: PlaybackNightModeConfig;
28
+ room?: PlaybackRoomConfig;
29
+ head_tracking?: PlaybackHeadTrackingConfig;
30
+ output_limiter?: PlaybackOutputLimiterConfig;
31
+ }
32
+
33
+ /** A speaker role name (`schemas/playback-renderer-config.schema.json` `$defs.role`). */
34
+ export type PlaybackChannelRole = 'L' | 'R' | 'C' | 'LFE' | 'Ls' | 'Rs' | 'Lss' | 'Rss';
35
+
36
+ export interface PlaybackInputConfig {
37
+ /** Prepare. `"auto"` follows the channel count of each processed block (1, 2, 6 or 8). Default `"auto"`. */
38
+ layout?: 'auto' | 'mono' | 'stereo' | '5.1' | '7.1';
39
+ /**
40
+ * Prepare. Role of each input channel, covering the fixed layout's roles
41
+ * exactly once; requires a fixed `layout`. `null` means canonical order.
42
+ */
43
+ channel_map?: PlaybackChannelRole[] | null;
44
+ }
45
+
46
+ export interface PlaybackSpeakerConfig {
47
+ /** Prepare. Listener distance in metres, [0.1, 30]; `null` disables distance compensation. Default `null`. */
48
+ distance_m?: number | null;
49
+ /** Realtime. Level trim in dB, [-20, 20]. Default 0. */
50
+ trim_db?: number;
51
+ /** Prepare. A `"small"` speaker is high-passed at the crossover when bass management is enabled. Default `"large"`. */
52
+ size?: 'large' | 'small';
53
+ }
54
+
55
+ export interface PlaybackBassManagementConfig {
56
+ /** Prepare. Default false. */
57
+ enabled?: boolean;
58
+ /** Prepare. LR4 crossover frequency, [40, 200]. Default 80. */
59
+ crossover_hz?: number;
60
+ /** Prepare. false folds the low band and LFE into the large L/R pair; L and R must then be large. Default true. */
61
+ subwoofer?: boolean;
62
+ /** Realtime. LFE gain when feeding the subwoofer, [-10, 15]. Default 10. */
63
+ lfe_gain_db?: number;
64
+ }
65
+
66
+ export interface PlaybackTargetConfig {
67
+ /** Prepare. Default `"headphones"`. */
68
+ kind?: 'headphones' | 'speakers';
69
+ /** Prepare. Required for `kind: "speakers"`, forbidden for `"headphones"`. */
70
+ layout?: 'stereo' | '5.1' | '7.1';
71
+ /** Per-speaker calibration keyed by role; only the non-LFE roles of the output layout. */
72
+ speakers?: Partial<Record<Exclude<PlaybackChannelRole, 'LFE'>, PlaybackSpeakerConfig>>;
73
+ bass_management?: PlaybackBassManagementConfig;
74
+ }
75
+
76
+ export interface PlaybackUpmixConfig {
77
+ /** Realtime. Stereo input only; the latency does not change. Default true. */
78
+ enabled?: boolean;
79
+ /** Realtime. Width of the centre window on the panning index, [0.05, 1]. Default 0.2. */
80
+ center_width?: number;
81
+ /** Realtime. Power share of the ambience kept in the front pair, [0, 1]. Default 0.5. */
82
+ front_ambience?: number;
83
+ /** Realtime. Derive LFE from the low-passed L/R sum. Default false. */
84
+ lfe_from_upmix?: boolean;
85
+ }
86
+
87
+ export interface PlaybackLoudnessConfig {
88
+ /** Realtime. Measured program loudness, [-70, 0]; `null` means no alignment gain. Default `null`. */
89
+ program_lufs?: number | null;
90
+ /** Realtime. [-40, -5]. Default -24. */
91
+ target_lufs?: number;
92
+ }
93
+
94
+ export interface PlaybackNightModeConfig {
95
+ /** Realtime. 0 disables the dynamic range control. [0, 1]. Default 0. */
96
+ amount?: number;
97
+ }
98
+
99
+ export interface PlaybackRoomConfig {
100
+ /** Prepare. Headphones only. Default `"living_room"`. */
101
+ preset?: 'none' | 'living_room' | 'home_theater' | 'screening_room';
102
+ /** Realtime. Level of the early reflections and the late reverberation, [-30, 6]. Default -6. */
103
+ mix_db?: number;
104
+ /** Realtime. Default true. */
105
+ enabled?: boolean;
106
+ }
107
+
108
+ export interface PlaybackHeadTrackingConfig {
109
+ /** Realtime. false treats the head pose as zero. Default true. */
110
+ enabled?: boolean;
111
+ }
112
+
113
+ export interface PlaybackOutputLimiterConfig {
114
+ /** Realtime. The latency does not change. Default true. */
115
+ enabled?: boolean;
116
+ /** Realtime. [-12, 0]. Default -1. */
117
+ ceiling_db?: number;
118
+ }
119
+
120
+ /** A stage name used in {@link PlaybackDiagnostics.inactive_stages} and `.latency.stages`. */
121
+ export type PlaybackStageName =
122
+ | 'reorder'
123
+ | 'dialogue_level'
124
+ | 'upmix'
125
+ | 'loudness'
126
+ | 'night_mode'
127
+ | 'layout_convert'
128
+ | 'speaker_calibration'
129
+ | 'bass_management'
130
+ | 'binaural'
131
+ | 'room_early'
132
+ | 'room_late'
133
+ | 'output_limiter';
134
+
135
+ /** Per-stage reported latency, in samples and in Q8 fixed-point. */
136
+ export interface PlaybackStageLatency {
137
+ samples: number;
138
+ q8: number;
139
+ }
140
+
141
+ /**
142
+ * The renderer's diagnostics document, a plain object that can be sent through
143
+ * `postMessage` as is. Field spelling is the core's own (snake_case), the same
144
+ * pass-through convention as {@link PlaybackRendererConfig}.
145
+ */
146
+ export interface PlaybackDiagnostics {
147
+ active_input_layout: 'mono' | 'stereo' | '5.1' | '7.1';
148
+ layout_switches: number;
149
+ truncated_drains: number;
150
+ /** Stages this configuration does not exercise (e.g. `room_early` for a speakers target). */
151
+ inactive_stages: PlaybackStageName[];
152
+ latency: {
153
+ samples: number;
154
+ /** Every stage name reports an entry, whether or not it is currently active. */
155
+ stages: Record<PlaybackStageName, PlaybackStageLatency>;
156
+ };
157
+ loudness_gain_db: number;
158
+ loudness_gain_clamped: boolean;
159
+ /** True when an `hrtf` was supplied to a speakers target, which ignores it. */
160
+ hrtf_ignored: boolean;
161
+ /** Deepest last-block gain reduction across the main and LFE limiters, in dB (<= 0). */
162
+ limiter_gain_reduction_db: number;
163
+ non_finite_discards: number;
164
+ }
165
+
166
+ /** Request shape for the {@link PlaybackRenderer} constructor. */
167
+ export interface PlaybackRendererOptions {
168
+ config: PlaybackRendererConfig | string;
169
+ /**
170
+ * Required for a headphones target: this build embeds no HRTF data. Load the
171
+ * package asset `./hrtf/default.shrf` (or any SHRF v1 file) and pass it
172
+ * through `HrtfSet.fromBytes`. Ignored by a speakers target.
173
+ */
174
+ hrtf?: HrtfSet;
175
+ /** Default 48000. */
176
+ sampleRate?: number;
177
+ /** Upper bound on the frames of every process call. Default 1024. */
178
+ maxBlockSize?: number;
179
+ }
180
+
181
+ /** Request shape for the one-shot `renderPlayback`. */
182
+ export interface RenderPlaybackRequest {
183
+ /** Interleaved input, `channels` samples per frame. */
184
+ samples: Float32Array;
185
+ channels: number;
186
+ sampleRate: number;
187
+ config: PlaybackRendererConfig | string;
188
+ /** Required for a headphones target; see {@link PlaybackRendererOptions.hrtf}. */
189
+ hrtf?: HrtfSet;
190
+ }
191
+
192
+ /** `renderPlayback`'s result: interleaved output with the target's own channel count. */
193
+ export interface RenderPlaybackResult {
194
+ samples: Float32Array;
195
+ channels: number;
196
+ }
@@ -1,12 +1,17 @@
1
1
  /**
2
- * Realtime equalizer spectrum snapshot.
2
+ * Realtime equalizer snapshot.
3
3
  *
4
4
  * Mirrors the C++ `EqualizerSpectrumSnapshot`: `preLeft`/`preRight` and
5
- * `postLeft`/`postRight` are the pre- and post-EQ spectrum streams (trimmed to
6
- * their valid count). `bandGainDb` holds per-band applied gain (24 entries),
7
- * `profileDb` the smoothed magnitude profile (16 entries), `lastAutoGainDb`
8
- * the latest auto-gain compensation, and `seq` increments each time a new
9
- * snapshot is published.
5
+ * `postLeft`/`postRight` are the pre- and post-EQ waveform streams (uniformly
6
+ * decimated time-domain samples, trimmed to their valid count), so they are a
7
+ * scope feed rather than a spectral estimate. `bandGainDb` holds per-band
8
+ * applied gain (24 entries). `profileDb` is the frequency-domain view: the
9
+ * post-EQ signal is Hann-windowed, transformed and its bin powers summed into
10
+ * 16 geometrically spaced bands covering 20 Hz to 20 kHz, in amplitude decibels
11
+ * relative to full scale (a full-scale sine reads about 0 dB in its own band),
12
+ * rising immediately and falling smoothly. `lastAutoGainDb` is the latest
13
+ * auto-gain compensation, and `seq` increments each time a new snapshot is
14
+ * published.
10
15
  */
11
16
  export interface EqSpectrumSnapshot {
12
17
  preLeft: Float32Array;
@@ -31,7 +36,8 @@ export type EqBandType =
31
36
  | 'BandPass'
32
37
  | 'Notch'
33
38
  | 'TiltShelf'
34
- | 'FlatTilt';
39
+ | 'FlatTilt'
40
+ | 'AllPass';
35
41
 
36
42
  /** Biquad coefficient design mode. */
37
43
  export type EqCoeffMode = 'Rbj' | 'Vicanek';
@@ -52,11 +58,27 @@ export interface EqBand {
52
58
  type?: EqBandType;
53
59
  frequencyHz?: number;
54
60
  gainDb?: number;
61
+ /**
62
+ * Resonance/slope. Ignored for a LowShelf/HighShelf band once `phase:
63
+ * 'NaturalPhase'` forces Vicanek coefficients (the Vicanek matched-Z shelf
64
+ * design has no Q/S parameter) -- the value is still stored and read back
65
+ * verbatim, so a reflected `q` on such a band does not describe the applied
66
+ * response. Set `coeffMode: 'Rbj'` for a Q-controllable shelf.
67
+ */
55
68
  q?: number;
56
69
  enabled?: boolean;
57
70
  coeffMode?: EqCoeffMode;
71
+ /**
72
+ * Slope in dB/octave. 6 selects a first-order section on a pass or shelf
73
+ * band; a first-order shelf's frequency is its half-gain point and its `q`
74
+ * is unused.
75
+ */
58
76
  slopeDbOct?: number;
59
77
  placement?: EqStereoPlacement;
78
+ /**
79
+ * `'NaturalPhase'` forces `coeffMode: 'Vicanek'` for this band, which
80
+ * ignores `q` for LowShelf/HighShelf (see `q`'s doc).
81
+ */
60
82
  phase?: EqBandPhase;
61
83
  soloed?: boolean;
62
84
  bypassed?: boolean;
@@ -69,6 +91,13 @@ export interface EqBand {
69
91
  rangeDb?: number;
70
92
  attackMs?: number;
71
93
  releaseMs?: number;
94
+ /**
95
+ * Delays the detector's view of the signal by this many ms; a larger value
96
+ * makes the band react LATER, not earlier -- this is a detector delay, not
97
+ * true look-ahead, and adds no latency to the audio path.
98
+ */
99
+ detectorDelayMs?: number;
100
+ /** Former (misleading) spelling of `detectorDelayMs`, still accepted; `detectorDelayMs` wins if both are set. */
72
101
  lookaheadMs?: number;
73
102
  externalSidechain?: boolean;
74
103
  sidechainFreqHz?: number;
@@ -179,3 +208,6 @@ export interface RealtimeVoiceChangerPodConfig {
179
208
  /** True-peak ceiling in dBTP applied by the ISP limiter (default -1.0). */
180
209
  limiterIspCeilingDbtp: number;
181
210
  }
211
+
212
+ /** One raw UMP message: 1 to 4 words, most significant word first. */
213
+ export type UmpWords = Uint32Array | readonly number[];