@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,477 @@
1
+ /**
2
+ * Note-level editing: segmenting audio and a pitch track into editable notes,
3
+ * rendering an edited set back, and the split/merge operations over it.
4
+ */
5
+ import type { NoteExtractorOptions, NoteMoveOptions, NoteObject, NoteObjectInput, NoteSetEntry, NoteStretchOptions, NoteTarget, NoteTargetAssignResult, NoteTargetUnmatchedPolicy, PitchDecompositionResult, VoicedFlags } from './public_types';
6
+ import type { ValidateOptions } from './validation';
7
+ export interface NoteStretchRequest extends NoteStretchOptions, ValidateOptions {
8
+ samples: Float32Array;
9
+ sampleRate?: number;
10
+ }
11
+ export interface NoteMoveRequest extends NoteMoveOptions, ValidateOptions {
12
+ samples: Float32Array;
13
+ sampleRate?: number;
14
+ }
15
+ /** Canonical request form for {@link extractNotes}. */
16
+ export interface ExtractNotesRequest extends NoteExtractorOptions, ValidateOptions {
17
+ samples: Float32Array;
18
+ /**
19
+ * Sample rate in Hz. Required: `minNoteMs` and the per-frame RMS windows are
20
+ * converted to samples with this rate, so a wrong/omitted value silently
21
+ * segments differently.
22
+ */
23
+ sampleRate: number;
24
+ /**
25
+ * Per-frame F0 in Hz. A frame carrying no pitch is spelled as zero, a
26
+ * negative value or a non-finite one, and all three read the same: that
27
+ * frame contributes no measurement. A {@link pitchPyin} track can be passed
28
+ * straight through — its `fillNa` is a choice about the contour you want,
29
+ * not a requirement of this call.
30
+ */
31
+ f0Hz: Float32Array;
32
+ /** F0 frames per second. */
33
+ frameRate: number;
34
+ /** Per-frame voiced flags (truthy = voiced). Takes precedence over `voicedProb`. */
35
+ voiced?: VoicedFlags;
36
+ /** Per-frame voicing probability in `[0, 1]`; read only when `voiced` is omitted. */
37
+ voicedProb?: Float32Array;
38
+ }
39
+ /** Canonical request form for {@link renderNotes}. */
40
+ export interface RenderNotesRequest extends ValidateOptions {
41
+ samples: Float32Array;
42
+ /**
43
+ * Sample rate in Hz. Required: `fadeMs` is converted to samples with this
44
+ * rate, so a wrong/omitted value changes the cross-fade length.
45
+ */
46
+ sampleRate: number;
47
+ /** The notes to render, with their edits. Source spans must not overlap. */
48
+ notes: readonly NoteObjectInput[];
49
+ /**
50
+ * Equal-power cross-fade at each edited note's edges. Default 5 ms; a hard cut
51
+ * is deliberately not selectable, because the seam it leaves is a click.
52
+ */
53
+ fadeMs?: number;
54
+ /**
55
+ * The F0 track the notes were extracted from. Required only by
56
+ * `vibratoDepthChange` and `driftChange`, which act on the note's own pitch
57
+ * curve; every other edit ignores it. The curve is not carried on a
58
+ * {@link NoteObject} for the same reason it is not returned by
59
+ * {@link extractNotes} — it is this array sliced by
60
+ * `[frameStart, frameEnd)`, which the caller already holds.
61
+ */
62
+ f0Hz?: Float32Array;
63
+ /** F0 frames per second. Required when `f0Hz` is given. */
64
+ frameRate?: number;
65
+ /**
66
+ * Boundary between the drift and the vibrato that `vibratoDepthChange` and
67
+ * `driftChange` act on, in Hz. Default 3 Hz.
68
+ *
69
+ * Pass whatever {@link decomposeNotePitch} was called with. A host that draws
70
+ * the vibrato at one cutoff and edits it at another edits a curve it never
71
+ * showed anyone.
72
+ */
73
+ vibratoCutoffHz?: number;
74
+ }
75
+ /** Canonical request form for {@link decomposeNotePitch}. */
76
+ export interface DecomposeNotePitchRequest {
77
+ /**
78
+ * The note's slice of the F0 track — `f0Hz.subarray(frameStart, frameEnd)`.
79
+ * Every value must be finite and non-negative; zero denotes an unvoiced frame.
80
+ */
81
+ f0Hz: Float32Array;
82
+ /** F0 frames per second. */
83
+ frameRate: number;
84
+ /**
85
+ * The note's `medianHz`. A note with no pitch is spelled 0, so a negative
86
+ * value is rejected rather than read as a second way of saying that.
87
+ */
88
+ medianHz: number;
89
+ /** Where drift ends and vibrato begins, in Hz. Default 3 Hz. */
90
+ vibratoCutoffHz?: number;
91
+ }
92
+ /** The audio, track and note set the two note-set reshaping calls share. */
93
+ export interface NoteSetRequest extends NoteExtractorOptions, ValidateOptions {
94
+ /**
95
+ * The audio the set was extracted from. Every note is re-measured against it,
96
+ * so a different buffer re-derives the whole set against something else.
97
+ */
98
+ samples: Float32Array;
99
+ sampleRate: number;
100
+ /**
101
+ * Per-frame F0 in Hz. A frame carrying no pitch is spelled as zero, a
102
+ * negative value or a non-finite one, and all three read the same: that
103
+ * frame contributes no measurement. A {@link pitchPyin} track can be passed
104
+ * straight through — its `fillNa` is a choice about the contour you want,
105
+ * not a requirement of this call.
106
+ */
107
+ f0Hz: Float32Array;
108
+ /** F0 frames per second. */
109
+ frameRate: number;
110
+ /** Per-frame voiced flags (truthy = voiced). Takes precedence over `voicedProb`. */
111
+ voiced?: VoicedFlags;
112
+ /** Per-frame voicing probability in `[0, 1]`; read only when `voiced` is omitted. */
113
+ voicedProb?: Float32Array;
114
+ /** The current note set. Each note's `[frameStart, frameEnd)` must be non-empty and inside the track. */
115
+ notes: readonly NoteSetEntry[];
116
+ }
117
+ /** Canonical request form for {@link splitNote}. */
118
+ export interface SplitNoteRequest extends NoteSetRequest {
119
+ /** Index of the note to split. */
120
+ index: number;
121
+ /** Track frame to cut at, strictly inside that note's own span. */
122
+ frame: number;
123
+ }
124
+ /** Canonical request form for {@link mergeNotes}. */
125
+ export interface MergeNotesRequest extends NoteSetRequest {
126
+ /** Index of the first note to join; must be `< last`. */
127
+ first: number;
128
+ /** Index of the last note to join, inclusive. */
129
+ last: number;
130
+ }
131
+ /** Canonical request form for {@link noteTargetsFromSmf}. */
132
+ export interface NoteTargetsFromSmfRequest {
133
+ /** The Standard MIDI File, in memory. */
134
+ data: Uint8Array;
135
+ /**
136
+ * Which MIDI-bearing track to read, NOT an index into the file's own tracks: a
137
+ * track holding only meta events — a conductor track carrying the tempo map is
138
+ * the usual one — is not counted. A file whose first track is a conductor track
139
+ * therefore has its melody at 0, which is also the default.
140
+ */
141
+ trackIndex?: number;
142
+ }
143
+ /** Canonical request form for {@link assignNoteTargets}. */
144
+ export interface AssignNoteTargetsRequest {
145
+ /**
146
+ * The notes to assign targets to. Not modified; the result carries a new array.
147
+ * Only `onsetSample`, `offsetSample` and `medianHz` are read.
148
+ */
149
+ notes: readonly NoteObject[];
150
+ /** Converts each note's sample span to seconds, so the targets line up. Must be > 0. */
151
+ sampleRate: number;
152
+ /** The reference melody. An empty array assigns nothing and applies the policy. */
153
+ targets: readonly NoteTarget[];
154
+ /** What to do with a note that has a pitch and no target. Default `'leave'`. */
155
+ unmatchedPolicy?: NoteTargetUnmatchedPolicy;
156
+ /**
157
+ * Fraction of the note that must overlap a target for it to count, in `[0, 1]`.
158
+ * Default 0.5. `0` is its own meaning — any overlap at all counts — not a
159
+ * request for the default.
160
+ */
161
+ minOverlapRatio?: number;
162
+ /**
163
+ * Where the assigned shift saturates, in semitones. Default 12. `0` is its own
164
+ * meaning, as above: every correction saturates to nothing and the take is left
165
+ * as recorded. Must not be negative.
166
+ */
167
+ maxCorrectionSemitones?: number;
168
+ }
169
+ /**
170
+ * Time-stretch a note region between two sample offsets without changing pitch.
171
+ *
172
+ * @param samples - Audio samples (mono, float32)
173
+ * @param sampleRate - Sample rate in Hz
174
+ * @param onsetSample - Note onset position in samples
175
+ * @param offsetSample - Note offset position in samples
176
+ * @param stretchRatio - Stretch ratio (0.5 = half duration, 2.0 = double duration)
177
+ * @returns Audio with the note region stretched
178
+ */
179
+ export declare function noteStretch(request: NoteStretchRequest): Float32Array;
180
+ export declare function noteStretch(samples: Float32Array, sampleRate?: number, options?: NoteStretchOptions & ValidateOptions): Float32Array;
181
+ /** Move a note region to a new onset without changing its duration. */
182
+ export declare function noteMove(request: NoteMoveRequest): Float32Array;
183
+ export declare function noteMove(samples: Float32Array, sampleRate?: number, options?: NoteMoveOptions & ValidateOptions): Float32Array;
184
+ /**
185
+ * Extract editable note objects from audio and a caller-supplied F0 track.
186
+ *
187
+ * The track is segmented into monophonic notes; each note carries its span in
188
+ * source samples, its span in the track's own frames, its median pitch, two
189
+ * measured quality figures, its per-frame amplitude (RMS) curve, and an identity
190
+ * {@link NoteEdit}. Edit the notes and hand them to {@link renderNotes} to apply
191
+ * the result — the source audio is never mutated, and a set whose edits are all
192
+ * identity renders back to the input bit for bit.
193
+ *
194
+ * The per-note F0 curve is deliberately not returned: it is the caller's own
195
+ * `f0Hz` sliced by `[frameStart, frameEnd)`. The amplitude curve is measured
196
+ * here, so it is, one entry per F0 frame over that note's span.
197
+ *
198
+ * Voicing comes from `voiced` (truthy = voiced). `voicedProb` is read only when
199
+ * `voiced` is absent, and then a frame counts as voiced at or above
200
+ * `voicedThreshold` (default 0.5). At least one of the two is required. Because
201
+ * `voicedProb` from pYIN rises with F0 for a fixed frame length, prefer passing
202
+ * a {@link PitchResult}'s `voicedFlag` through `voiced`.
203
+ *
204
+ * @param request - Audio, F0 track, frame cadence and segmenter options
205
+ * @returns One {@link NoteObject} per segmented note, in time order; an empty
206
+ * array when the track segments to nothing
207
+ * @throws RangeError when `voiced` / `voicedProb` do not match `f0Hz` in length,
208
+ * or the samples/sample rate fail the shared input checks
209
+ * @throws SonareError (`InvalidParameter`) on an empty `f0Hz`, a non-positive
210
+ * `frameRate`, a negative or non-finite `f0Hz` value, a `voicedProb` outside
211
+ * `[0, 1]`, or a negative option value
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * // pitchPyin's default leaves unvoiced frames NaN, which reads here as a
216
+ * // frame carrying no pitch, so fillNa is a choice rather than a requirement.
217
+ * const pitch = pitchPyin({ samples, sampleRate });
218
+ * const notes = extractNotes({
219
+ * samples,
220
+ * sampleRate,
221
+ * f0Hz: pitch.f0,
222
+ * voiced: pitch.voicedFlag,
223
+ * frameRate: sampleRate / 512,
224
+ * minNoteMs: 40,
225
+ * });
226
+ * // Lift the second note by a semitone and mute the third.
227
+ * notes[1].edit.pitchShiftSemitones = 1;
228
+ * notes[2].edit.muted = true;
229
+ * const edited = renderNotes({ samples, sampleRate, notes });
230
+ * ```
231
+ */
232
+ export declare function extractNotes(request: ExtractNotesRequest): NoteObject[];
233
+ /**
234
+ * Render edited note objects back over their source audio.
235
+ *
236
+ * Only a note whose edit is non-identity is resynthesized; the source passes
237
+ * through everywhere else, so a set of untouched {@link extractNotes} output
238
+ * reproduces the input exactly. The output has the input's length: an edit that
239
+ * pushes a note past either end is truncated there.
240
+ *
241
+ * Per note the order is: pitch curve, time stretch, pitch shift, formant warp,
242
+ * amplitude envelope, then gain.
243
+ *
244
+ * Each note's `onsetSample`, `offsetSample` and `edit` are read, plus its
245
+ * `frameStart`, `frameEnd` and `medianHz` when the request carries an `f0Hz`
246
+ * track for a curve edit to act on; so an extracted note can be passed back
247
+ * as-is, or a note can be built by hand from those fields alone. Overlap is
248
+ * checked on the source spans only — where `timeOffsetSamples` lands a note is
249
+ * not, and a note lengthened past its own span writes into its neighbours'
250
+ * samples, so two moved or stretched notes may be written over each other.
251
+ *
252
+ * @param request - Source audio, the notes to render, the cross-fade length, and
253
+ * the F0 track a vibrato or drift edit reads
254
+ * @returns The rendered audio, the same length and sample rate as the input
255
+ * @throws RangeError when the samples or sample rate fail the shared input checks
256
+ * @throws SonareError (`InvalidParameter`) on a note whose span is empty,
257
+ * reversed or missing, overlapping source spans, a non-finite or non-positive
258
+ * edit field, a negative or non-finite envelope value, a negative `fadeMs` or
259
+ * `vibratoCutoffHz`, a frame span outside `f0Hz`, or a `vibratoDepthChange` /
260
+ * `driftChange` on a note with no usable pitch curve to apply it to
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * const notes = extractNotes({ samples, sampleRate, f0Hz, voiced, frameRate });
265
+ *
266
+ * // Silence the third note and leave the rest untouched.
267
+ * const muted = notes.map((note, index) =>
268
+ * index === 2 ? { ...note, edit: { ...note.edit, muted: true } } : note,
269
+ * );
270
+ * const rendered = renderNotes({ samples, sampleRate, notes: muted, fadeMs: 10 });
271
+ *
272
+ * // Flatten the first note's vibrato, which needs the track it was measured on.
273
+ * const flattened = notes.map((note, index) =>
274
+ * index === 0 ? { ...note, edit: { ...note.edit, vibratoDepthChange: -1 } } : note,
275
+ * );
276
+ * const steady = renderNotes({
277
+ * samples,
278
+ * sampleRate,
279
+ * notes: flattened,
280
+ * f0Hz,
281
+ * frameRate: sampleRate / 512,
282
+ * });
283
+ * ```
284
+ */
285
+ export declare function renderNotes(request: RenderNotesRequest): Float32Array;
286
+ /**
287
+ * Split one note's pitch curve into a centre, a slow drift and a vibrato.
288
+ *
289
+ * A performed note's pitch is one curve carrying three things at once: the note
290
+ * that was aimed at, a slow wander around it, and a periodic oscillation on top.
291
+ * Editing any of them on its own needs them separated first, and the only thing
292
+ * that decides where drift ends and vibrato begins is `vibratoCutoffHz`. Hand
293
+ * the same cutoff to {@link renderNotes}, or it edits a curve nobody was shown.
294
+ *
295
+ * Frames whose F0 is unusable carry no measurement, so the curve is held at the
296
+ * nearest usable neighbour across them. Both curves therefore have an entry
297
+ * everywhere; a host marking the held ones reads them off `f0Hz`, which is exact.
298
+ *
299
+ * A note with no usable pitch is reported as a zero `centreHz` and two empty
300
+ * curves rather than as an error — that is a measurement which came up empty,
301
+ * not a bad argument.
302
+ *
303
+ * @param request - The note's slice of the F0 track, its cadence, its centre, and
304
+ * the cutoff
305
+ * @returns The centre and the two curves, each one entry per frame of `f0Hz`
306
+ * @throws SonareError (`InvalidParameter`) on an empty `f0Hz`, a negative or
307
+ * non-finite `f0Hz` value, a non-positive `frameRate`, a negative `medianHz`,
308
+ * or a negative `vibratoCutoffHz`
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * const note = notes[0];
313
+ * const { centreHz, driftCents, vibratoCents } = decomposeNotePitch({
314
+ * f0Hz: f0Hz.subarray(note.frameStart, note.frameEnd),
315
+ * frameRate: sampleRate / 512,
316
+ * medianHz: note.medianHz,
317
+ * });
318
+ * ```
319
+ */
320
+ export declare function decomposeNotePitch(request: DecomposeNotePitchRequest): PitchDecompositionResult;
321
+ /**
322
+ * Split one note of a set in two at a track frame.
323
+ *
324
+ * Both halves are re-derived from the audio and the track the way
325
+ * {@link extractNotes} derives its own, rather than by patching the fields of
326
+ * the note they replace. Both inherit the source note's edit, and its amplitude
327
+ * envelope is cut at the same proportion so each half keeps its own part of it —
328
+ * a note whose edit is the identity therefore still renders bit for bit after
329
+ * being split.
330
+ *
331
+ * Every note in the set, not just the two halves, has its spans, curves, medians
332
+ * and stability re-derived from `samples` and the track, because a
333
+ * {@link NoteSetEntry} carries no curves for this call to copy through. The
334
+ * frame bounds are therefore what a note is identified by here, and the audio
335
+ * and track must be the ones the set was extracted from or the whole set is
336
+ * re-measured against something else.
337
+ *
338
+ * @param request - The source, the current note set, and where to cut
339
+ * @returns The whole new note set, one note longer than the one handed in
340
+ * @throws RangeError when `voiced` / `voicedProb` do not match `f0Hz` in length,
341
+ * or the samples/sample rate fail the shared input checks
342
+ * @throws SonareError (`InvalidParameter`) on an out-of-range `index`, a `frame`
343
+ * that is not strictly inside that note's own span, a note whose frame span is
344
+ * empty or runs past the track, or the track arguments {@link extractNotes}
345
+ * itself rejects
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * const notes = extractNotes({ samples, sampleRate, f0Hz, voiced, frameRate });
350
+ * const halves = splitNote({
351
+ * samples,
352
+ * sampleRate,
353
+ * f0Hz,
354
+ * voiced,
355
+ * frameRate,
356
+ * notes,
357
+ * index: 1,
358
+ * frame: Math.floor((notes[1].frameStart + notes[1].frameEnd) / 2),
359
+ * });
360
+ * ```
361
+ */
362
+ export declare function splitNote(request: SplitNoteRequest): NoteObject[];
363
+ /**
364
+ * Join a run of notes into one.
365
+ *
366
+ * The result spans from `notes[first]`'s onset to `notes[last]`'s offset,
367
+ * including whatever the segmenter cut out between them, and its measured fields
368
+ * are derived over that whole span — the pitch and amplitude of an unvoiced gap
369
+ * live in the track and the audio, not in either neighbour.
370
+ *
371
+ * It takes `notes[first]`'s edit, envelope included. Notes carrying different
372
+ * edits have no single correct answer here, so the rule is stated rather than
373
+ * guessed at; a host that cares sets the edit afterwards. Every note in the set
374
+ * is re-derived from `samples` and the track, exactly as {@link splitNote}
375
+ * describes.
376
+ *
377
+ * @param request - The source, the current note set, and the run to join
378
+ * @returns The whole new note set, `last - first` notes shorter than the one
379
+ * handed in
380
+ * @throws RangeError when `voiced` / `voicedProb` do not match `f0Hz` in length,
381
+ * or the samples/sample rate fail the shared input checks
382
+ * @throws SonareError (`InvalidParameter`) unless `first < last < notes.length`,
383
+ * on a note whose frame span is empty or runs past the track, or on the track
384
+ * arguments {@link extractNotes} itself rejects
385
+ *
386
+ * @example
387
+ * ```ts
388
+ * // Undo a split by rejoining the two halves it produced.
389
+ * const rejoined = mergeNotes({
390
+ * samples,
391
+ * sampleRate,
392
+ * f0Hz,
393
+ * voiced,
394
+ * frameRate,
395
+ * notes: halves,
396
+ * first: 1,
397
+ * last: 2,
398
+ * });
399
+ * ```
400
+ */
401
+ export declare function mergeNotes(request: MergeNotesRequest): NoteObject[];
402
+ /**
403
+ * Read one track of an in-memory Standard MIDI File as a reference melody.
404
+ *
405
+ * Each note-on is paired with the next note-off of the same note number on the
406
+ * same channel, and the pair becomes one {@link NoteTarget} at the note's own
407
+ * pitch. Times come from the file's tempo map, so a tempo change or a ramp inside
408
+ * it is followed rather than the initial tempo being scaled.
409
+ *
410
+ * A note-on the track never closes is dropped: it has no end, and the track's end
411
+ * is not a substitute for one — with events after it the note would span the whole
412
+ * remainder and, being the longest overlap everywhere, take the assignment away
413
+ * from every note that follows. Zero-length notes are skipped for the mirror
414
+ * reason: they overlap nothing, so they could never be assigned.
415
+ *
416
+ * @param request - The file's bytes and which MIDI-bearing track to read
417
+ * @returns One target per closed note, sorted by `startSec`; an empty array for a
418
+ * track with no closed note, which is a measurement that came up empty rather
419
+ * than an error
420
+ * @throws SonareError (`InvalidFormat`) when the bytes are not a readable SMF
421
+ * @throws SonareError (`InvalidParameter`) when `trackIndex` names no
422
+ * MIDI-bearing track
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * // A project's own export writes the tempo map as a conductor track, which
427
+ * // carries no MIDI, so the melody is at index 0 rather than 1.
428
+ * const targets = noteTargetsFromSmf({ data: project.exportSmf() });
429
+ * ```
430
+ */
431
+ export declare function noteTargetsFromSmf(request: NoteTargetsFromSmfRequest): NoteTarget[];
432
+ /**
433
+ * Write each note's `edit.pitchShiftSemitones` from the reference target it
434
+ * overlaps, which is what makes a take follow a written melody instead of a
435
+ * single stated interval.
436
+ *
437
+ * A note is matched to the target it overlaps longest, provided that overlap is
438
+ * at least `minOverlapRatio` of the note's own span; an exact tie goes to the
439
+ * target that starts first, so the answer does not depend on the order the
440
+ * targets arrived in. The shift is `targetMidi` minus the note's own `medianHz`
441
+ * as a MIDI number, saturated at `maxCorrectionSemitones` — a reference an octave
442
+ * out is a wrong reference, and a rejected call would tell the caller less than a
443
+ * bounded correction does.
444
+ *
445
+ * A note whose `medianHz` is not finite and positive is never assigned and never
446
+ * edited, whatever `unmatchedPolicy` says. Such a note has no measured pitch to
447
+ * correct from, so `'nearest'` would compute a shift from a pitch that does not
448
+ * exist; the policy governs notes that have a pitch and no target, which is a
449
+ * different thing from having no pitch.
450
+ *
451
+ * The notes handed in are not modified. Only `edit.pitchShiftSemitones` and
452
+ * `edit.muted` are written on the returned copies; every other field of a note —
453
+ * its spans, its metrics, its amplitude curve and its other edits — comes back
454
+ * exactly as it went in.
455
+ *
456
+ * @param request - The notes, their sample rate, the reference melody, and the
457
+ * three tunable knobs
458
+ * @returns The new note set and how many notes received a target
459
+ * @throws SonareError (`InvalidParameter`) on a non-positive `sampleRate`, an
460
+ * unknown `unmatchedPolicy`, a `minOverlapRatio` outside `[0, 1]`, a negative
461
+ * `maxCorrectionSemitones`, a note missing `onsetSample` / `offsetSample`, or a
462
+ * target whose `startSec`, `endSec` or `targetMidi` is not finite
463
+ *
464
+ * @example
465
+ * ```ts
466
+ * const notes = extractNotes({ samples, sampleRate, f0Hz, voiced, frameRate });
467
+ * const { notes: retuned, assignedCount } = assignNoteTargets({
468
+ * notes,
469
+ * sampleRate,
470
+ * targets: noteTargetsFromSmf({ data: smf }),
471
+ * unmatchedPolicy: 'mute',
472
+ * });
473
+ * const corrected = renderNotes({ samples, sampleRate, notes: retuned });
474
+ * ```
475
+ */
476
+ export declare function assignNoteTargets(request: AssignNoteTargetsRequest): NoteTargetAssignResult;
477
+ //# sourceMappingURL=effects_note_ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects_note_ops.d.ts","sourceRoot":"","sources":["../src/effects_note_ops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Percussive event editing: locating struck sounds in audio and rendering an
3
+ * edited set of them back.
4
+ */
5
+ import type { PercussiveEvent, PercussiveEventInput } from './public_types';
6
+ import type { ValidateOptions } from './validation';
7
+ /**
8
+ * The separation a percussive event's signal is lifted out with. Extraction
9
+ * measures events against it and rendering has to repeat it, so both calls take
10
+ * the same four fields and a render must be given what the extraction was.
11
+ */
12
+ export interface PercussiveSeparationOptions {
13
+ /**
14
+ * FFT size and hop the separation and the onset detector share. They cannot be
15
+ * set apart: an event measured on one framing and lifted out on another is not
16
+ * the same signal. Default 2048 and 512. The pair must overlap-add — `nFft`
17
+ * even and at least 2, `hopLength` no more than half of it — because the
18
+ * separation inverts an STFT. A negative value is rejected on its own, before
19
+ * the zero-is-default rule could swallow it.
20
+ */
21
+ nFft?: number;
22
+ /** Hop length in samples. Default 512. */
23
+ hopLength?: number;
24
+ /**
25
+ * Median filter lengths the separation runs, along time and along frequency. A
26
+ * longer harmonic kernel calls more of a sustained sound harmonic. Default 31;
27
+ * any other value must be odd and positive, so an even one is rejected rather
28
+ * than rounded. 1 is legal and degenerate rather than an error: a length-1
29
+ * median is the identity, so both components come back as the source.
30
+ */
31
+ hpssKernelHarmonic?: number;
32
+ /** Vertical median filter length, under the same rule. Default 31. */
33
+ hpssKernelPercussive?: number;
34
+ }
35
+ /** Canonical request form for {@link extractPercussiveEvents}. */
36
+ export interface ExtractPercussiveEventsRequest extends PercussiveSeparationOptions, ValidateOptions {
37
+ samples: Float32Array | readonly number[];
38
+ /**
39
+ * Sample rate in Hz. Required: `maxEventMs` is converted to samples with this
40
+ * rate, so a wrong/omitted value caps the spans differently.
41
+ */
42
+ sampleRate: number;
43
+ /**
44
+ * Minimum frames between consecutive onsets. Default 1, and a whole number:
45
+ * 0 is how the default is spelled, so a fractional wait is refused rather
46
+ * than truncated onto it. Negative is rejected.
47
+ */
48
+ onsetWait?: number;
49
+ /**
50
+ * Offset added to the detector's adaptive threshold; raising it finds fewer,
51
+ * stronger hits and lowering it finds more. Default 0.06, so exactly zero is
52
+ * the one value not selectable here — a negative one is accepted and puts the
53
+ * threshold below the default, which is the direction a caller reaching for
54
+ * zero wanted anyway.
55
+ */
56
+ onsetDelta?: number;
57
+ /**
58
+ * Caps a span that no onset follows. It binds at the end of a phrase and at the
59
+ * end of the track; anywhere else the next onset closes the span first. Default
60
+ * 500 ms.
61
+ */
62
+ maxEventMs?: number;
63
+ /**
64
+ * Drops an event whose `percussiveRatio` falls below this; must be in `[0, 1]`.
65
+ * 0 is both the default and the meaningful "keep everything". Raising it is
66
+ * useful on material that is mostly drums and wrong on a dense mix, where it
67
+ * also drops real hits sitting over a loud sustain.
68
+ */
69
+ minPercussiveRatio?: number;
70
+ }
71
+ /** Canonical request form for {@link renderPercussiveEvents}. */
72
+ export interface RenderPercussiveEventsRequest extends PercussiveSeparationOptions, ValidateOptions {
73
+ samples: Float32Array | readonly number[];
74
+ /**
75
+ * Sample rate in Hz. Required: `fadeMs` is converted to samples with this rate,
76
+ * so a wrong/omitted value changes the fade length.
77
+ */
78
+ sampleRate: number;
79
+ /** The events to render, with their edits. Source spans must not overlap. */
80
+ events: readonly PercussiveEventInput[];
81
+ /**
82
+ * Fade-out at the tail of each lifted span. Default 5 ms, so a zero-length
83
+ * fade is unreachable here rather than rejected — and a hard cut is not a thing
84
+ * to want anyway, because what the fade shapes is the signal being subtracted,
85
+ * so squaring it off leaves a step. There is deliberately
86
+ * no matching fade-in: a span opens in front of its transient, where the
87
+ * percussive component is near-silent, so cutting square there costs nothing
88
+ * and keeps a muted hit's attack from surviving inside a fade.
89
+ */
90
+ fadeMs?: number;
91
+ }
92
+ /**
93
+ * Extract editable percussive events from audio alone.
94
+ *
95
+ * Each event is a struck sound located in time: a span in source samples, its
96
+ * detector strength, the percussive peak over the span, the share of the span's
97
+ * energy the separation called percussive, and an identity
98
+ * {@link PercussiveEventEdit}. Edit the events and hand them to
99
+ * {@link renderPercussiveEvents} to apply the result — the source audio is never
100
+ * mutated, and a set whose edits are all identity renders back to the input bit
101
+ * for bit.
102
+ *
103
+ * Onsets are detected on the percussive component rather than on the source, so
104
+ * a harmonic attack is attenuated before the detector sees it instead of being
105
+ * filtered out afterwards. Each onset opens a span that the next one closes,
106
+ * capped by `maxEventMs` and never running past the end of the audio.
107
+ *
108
+ * Each onset is backtracked to the transient's start, which is not optional and
109
+ * is why there is no knob for it: peak-picking lands after the attack, and a span
110
+ * that opened there would report the next hit's peak and leave its own attack
111
+ * behind when muted.
112
+ *
113
+ * An event carries no pitch and is never associated with a {@link NoteObject} —
114
+ * a struck sound has no steady F0 to edit, so the two models are extracted by
115
+ * separate calls.
116
+ *
117
+ * @param request - Audio, its sample rate, and the separation, peak-picking and
118
+ * span options
119
+ * @returns One {@link PercussiveEvent} per detected hit, in time order; an empty
120
+ * array when nothing was detected
121
+ * @throws RangeError when the samples or sample rate fail the shared input checks
122
+ * @throws SonareError (`InvalidParameter`) on a kernel size that is not an
123
+ * integer within the 32-bit range, a framing size that is negative or outside
124
+ * that range, a framing that breaks constant overlap-add, an `onsetWait` that
125
+ * is fractional, negative or non-finite, a negative or non-finite `onsetDelta`
126
+ * / `maxEventMs`, or a `minPercussiveRatio` outside `[0, 1]`
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * const events = extractPercussiveEvents({ samples, sampleRate });
131
+ * // Drop the second hit and push the third 10 ms late.
132
+ * events[1].edit.muted = true;
133
+ * events[2].edit.timeOffsetSamples = Math.round(0.01 * sampleRate);
134
+ * const edited = renderPercussiveEvents({ samples, sampleRate, events });
135
+ * ```
136
+ */
137
+ export declare function extractPercussiveEvents(request: ExtractPercussiveEventsRequest): PercussiveEvent[];
138
+ /**
139
+ * Render edited percussive events back over their source audio.
140
+ *
141
+ * Per event the lifted signal is the percussive component over
142
+ * `[onsetSample, offsetSample)` under the tail fade. It is subtracted where it
143
+ * sits and, unless the event is muted, added back at the shifted position scaled
144
+ * by the gain. Only that signal moves, so muting a hit leaves the harmonic
145
+ * content under it sounding and moving one does not drag its neighbours' sustain
146
+ * along.
147
+ *
148
+ * Each event's span and `edit` are read; `strength`, `peakAmplitude` and
149
+ * `percussiveRatio` are ignored, so an extracted event can be passed back as-is,
150
+ * or an event can be built by hand from the span alone. A set whose edits are all
151
+ * identity reproduces the input bit for bit and runs no separation at all.
152
+ *
153
+ * Pass the separation the events were extracted with: a different one lifts a
154
+ * different signal out of the span than the one the events describe. It is
155
+ * validated even when every edit is the identity and no separation runs, so an
156
+ * unusable framing is an error on every set rather than on some of them.
157
+ *
158
+ * Overlap is checked on the source spans only. Where `timeOffsetSamples` lands an
159
+ * event is not, so two moved events may be written over each other, and a shift
160
+ * that pushes the signal past either end is truncated there rather than wrapped.
161
+ *
162
+ * @param request - Source audio, the events to render, the separation and the
163
+ * tail fade
164
+ * @returns The rendered audio, the same length and sample rate as the input
165
+ * @throws RangeError when the samples or sample rate fail the shared input checks
166
+ * @throws SonareError (`InvalidParameter`) on an event whose span is empty,
167
+ * reversed or outside the audio, overlapping source spans, a non-finite
168
+ * `gainDb`, a kernel size that is not an integer within the 32-bit range, a
169
+ * framing that breaks constant overlap-add, or a negative or non-finite
170
+ * `fadeMs`
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * const events = extractPercussiveEvents({ samples, sampleRate });
175
+ *
176
+ * // Lift the loudest hit by 3 dB and leave the rest untouched.
177
+ * const loudest = events.reduce((a, b) => (a.strength >= b.strength ? a : b));
178
+ * const edited = events.map((event) =>
179
+ * event === loudest ? { ...event, edit: { ...event.edit, gainDb: 3 } } : event,
180
+ * );
181
+ * const rendered = renderPercussiveEvents({ samples, sampleRate, events: edited });
182
+ * ```
183
+ */
184
+ export declare function renderPercussiveEvents(request: RenderPercussiveEventsRequest): Float32Array;
185
+ //# sourceMappingURL=effects_percussive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects_percussive.d.ts","sourceRoot":"","sources":["../src/effects_percussive.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,kEAAkE;AAClE,MAAM,WAAW,8BACf,SAAQ,2BAA2B,EACjC,eAAe;IACjB,OAAO,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,CAAC;IAC1C;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,iEAAiE;AACjE,MAAM,WAAW,6BACf,SAAQ,2BAA2B,EACjC,eAAe;IACjB,OAAO,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,CAAC;IAC1C;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACxC;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,eAAe,EAAE,CAKnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,YAAY,CAU3F"}