@drop-ai/core 0.2.0 → 0.3.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 (301) hide show
  1. package/README.md +655 -237
  2. package/dist/actions/ActionRegistry.d.ts.map +1 -1
  3. package/dist/actions/ActionRegistry.js +7 -2
  4. package/dist/actions/ActionRegistry.js.map +1 -1
  5. package/dist/actions/types.d.ts +7 -1
  6. package/dist/actions/types.d.ts.map +1 -1
  7. package/dist/analysis/AudioAnalyzer.d.ts +71 -0
  8. package/dist/analysis/AudioAnalyzer.d.ts.map +1 -0
  9. package/dist/analysis/AudioAnalyzer.js +569 -0
  10. package/dist/analysis/AudioAnalyzer.js.map +1 -0
  11. package/dist/audio/AudioEngine.d.ts +14 -1
  12. package/dist/audio/AudioEngine.d.ts.map +1 -1
  13. package/dist/audio/AudioEngine.js +115 -35
  14. package/dist/audio/AudioEngine.js.map +1 -1
  15. package/dist/audio/Auditioner.d.ts +104 -0
  16. package/dist/audio/Auditioner.d.ts.map +1 -0
  17. package/dist/audio/Auditioner.js +239 -0
  18. package/dist/audio/Auditioner.js.map +1 -0
  19. package/dist/audio/BWFMetadata.d.ts +116 -0
  20. package/dist/audio/BWFMetadata.d.ts.map +1 -0
  21. package/dist/audio/BWFMetadata.js +394 -0
  22. package/dist/audio/BWFMetadata.js.map +1 -0
  23. package/dist/audio/ChannelSplitter.d.ts +37 -0
  24. package/dist/audio/ChannelSplitter.d.ts.map +1 -0
  25. package/dist/audio/ChannelSplitter.js +82 -0
  26. package/dist/audio/ChannelSplitter.js.map +1 -0
  27. package/dist/audio/ExportAnalyzer.d.ts +39 -0
  28. package/dist/audio/ExportAnalyzer.d.ts.map +1 -0
  29. package/dist/audio/ExportAnalyzer.js +76 -0
  30. package/dist/audio/ExportAnalyzer.js.map +1 -0
  31. package/dist/audio/LufsNormalizer.d.ts +37 -0
  32. package/dist/audio/LufsNormalizer.d.ts.map +1 -0
  33. package/dist/audio/LufsNormalizer.js +217 -0
  34. package/dist/audio/LufsNormalizer.js.map +1 -0
  35. package/dist/audio/OfflineExporter.d.ts +1 -6
  36. package/dist/audio/OfflineExporter.d.ts.map +1 -1
  37. package/dist/audio/OfflineExporter.js +31 -10
  38. package/dist/audio/OfflineExporter.js.map +1 -1
  39. package/dist/audio/RoutingGraph.d.ts +134 -0
  40. package/dist/audio/RoutingGraph.d.ts.map +1 -0
  41. package/dist/audio/RoutingGraph.js +547 -0
  42. package/dist/audio/RoutingGraph.js.map +1 -0
  43. package/dist/audio/SampleRateConverter.d.ts +21 -0
  44. package/dist/audio/SampleRateConverter.d.ts.map +1 -0
  45. package/dist/audio/SampleRateConverter.js +84 -0
  46. package/dist/audio/SampleRateConverter.js.map +1 -0
  47. package/dist/audio/SilencePadding.d.ts +29 -0
  48. package/dist/audio/SilencePadding.d.ts.map +1 -0
  49. package/dist/audio/SilencePadding.js +86 -0
  50. package/dist/audio/SilencePadding.js.map +1 -0
  51. package/dist/audio/SourceCache.d.ts +13 -16
  52. package/dist/audio/SourceCache.d.ts.map +1 -1
  53. package/dist/audio/SourceCache.js +21 -33
  54. package/dist/audio/SourceCache.js.map +1 -1
  55. package/dist/audio/engine/Declick.d.ts +98 -0
  56. package/dist/audio/engine/Declick.d.ts.map +1 -0
  57. package/dist/audio/engine/Declick.js +204 -0
  58. package/dist/audio/engine/Declick.js.map +1 -0
  59. package/dist/audio/engine/DiskIO.d.ts +172 -0
  60. package/dist/audio/engine/DiskIO.d.ts.map +1 -0
  61. package/dist/audio/engine/DiskIO.js +384 -0
  62. package/dist/audio/engine/DiskIO.js.map +1 -0
  63. package/dist/audio/engine/LatencyCompensator.d.ts +46 -0
  64. package/dist/audio/engine/LatencyCompensator.d.ts.map +1 -0
  65. package/dist/audio/engine/LatencyCompensator.js +84 -0
  66. package/dist/audio/engine/LatencyCompensator.js.map +1 -0
  67. package/dist/audio/engine/MultiTrackRecorder.d.ts +146 -0
  68. package/dist/audio/engine/MultiTrackRecorder.d.ts.map +1 -0
  69. package/dist/audio/engine/MultiTrackRecorder.js +359 -0
  70. package/dist/audio/engine/MultiTrackRecorder.js.map +1 -0
  71. package/dist/audio/engine/PlaylistEngine.d.ts.map +1 -1
  72. package/dist/audio/engine/PlaylistEngine.js +9 -2
  73. package/dist/audio/engine/PlaylistEngine.js.map +1 -1
  74. package/dist/audio/engine/PunchRecordManager.d.ts +113 -0
  75. package/dist/audio/engine/PunchRecordManager.d.ts.map +1 -0
  76. package/dist/audio/engine/PunchRecordManager.js +191 -0
  77. package/dist/audio/engine/PunchRecordManager.js.map +1 -0
  78. package/dist/audio/engine/RoutingGraph.d.ts +135 -0
  79. package/dist/audio/engine/RoutingGraph.d.ts.map +1 -0
  80. package/dist/audio/engine/RoutingGraph.js +436 -0
  81. package/dist/audio/engine/RoutingGraph.js.map +1 -0
  82. package/dist/audio/engine/SidechainRouter.d.ts +139 -0
  83. package/dist/audio/engine/SidechainRouter.d.ts.map +1 -0
  84. package/dist/audio/engine/SidechainRouter.js +292 -0
  85. package/dist/audio/engine/SidechainRouter.js.map +1 -0
  86. package/dist/audio/engine/XrunTracker.d.ts +71 -0
  87. package/dist/audio/engine/XrunTracker.d.ts.map +1 -0
  88. package/dist/audio/engine/XrunTracker.js +118 -0
  89. package/dist/audio/engine/XrunTracker.js.map +1 -0
  90. package/dist/audio/export/CDMarkerExporter.d.ts +62 -0
  91. package/dist/audio/export/CDMarkerExporter.d.ts.map +1 -0
  92. package/dist/audio/export/CDMarkerExporter.js +164 -0
  93. package/dist/audio/export/CDMarkerExporter.js.map +1 -0
  94. package/dist/audio/export/ExportGraphBuilder.d.ts +121 -0
  95. package/dist/audio/export/ExportGraphBuilder.d.ts.map +1 -0
  96. package/dist/audio/export/ExportGraphBuilder.js +522 -0
  97. package/dist/audio/export/ExportGraphBuilder.js.map +1 -0
  98. package/dist/audio/export/ExportPresetManager.d.ts +87 -0
  99. package/dist/audio/export/ExportPresetManager.d.ts.map +1 -0
  100. package/dist/audio/export/ExportPresetManager.js +306 -0
  101. package/dist/audio/export/ExportPresetManager.js.map +1 -0
  102. package/dist/commands/handlers/RegionHandler.d.ts.map +1 -1
  103. package/dist/commands/handlers/RegionHandler.js +25 -1
  104. package/dist/commands/handlers/RegionHandler.js.map +1 -1
  105. package/dist/commands/handlers/TrackHandler.js +1 -1
  106. package/dist/commands/handlers/TrackHandler.js.map +1 -1
  107. package/dist/commands/impl/FreezeTrackCommand.d.ts.map +1 -1
  108. package/dist/commands/impl/FreezeTrackCommand.js +37 -36
  109. package/dist/commands/impl/FreezeTrackCommand.js.map +1 -1
  110. package/dist/commands/impl/SetRegionTimeDomainCommand.d.ts.map +1 -1
  111. package/dist/commands/impl/SetRegionTimeDomainCommand.js +3 -3
  112. package/dist/commands/impl/SetRegionTimeDomainCommand.js.map +1 -1
  113. package/dist/commands/impl/ToggleLoopCommand.d.ts +1 -0
  114. package/dist/commands/impl/ToggleLoopCommand.d.ts.map +1 -1
  115. package/dist/commands/impl/ToggleLoopCommand.js +10 -0
  116. package/dist/commands/impl/ToggleLoopCommand.js.map +1 -1
  117. package/dist/commands/impl/TrimRegionCommand.d.ts +14 -1
  118. package/dist/commands/impl/TrimRegionCommand.d.ts.map +1 -1
  119. package/dist/commands/impl/TrimRegionCommand.js +138 -33
  120. package/dist/commands/impl/TrimRegionCommand.js.map +1 -1
  121. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts +27 -0
  122. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts.map +1 -0
  123. package/dist/commands/impl/TrimRegionToPlayheadCommand.js +69 -0
  124. package/dist/commands/impl/TrimRegionToPlayheadCommand.js.map +1 -0
  125. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts +28 -0
  126. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts.map +1 -0
  127. package/dist/commands/impl/TrimRegionToRangeCommand.js +69 -0
  128. package/dist/commands/impl/TrimRegionToRangeCommand.js.map +1 -0
  129. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts +27 -0
  130. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts.map +1 -0
  131. package/dist/commands/impl/TrimToAdjacentRegionCommand.js +77 -0
  132. package/dist/commands/impl/TrimToAdjacentRegionCommand.js.map +1 -0
  133. package/dist/commands/types.d.ts +19 -0
  134. package/dist/commands/types.d.ts.map +1 -1
  135. package/dist/commands/types.js +21 -0
  136. package/dist/commands/types.js.map +1 -1
  137. package/dist/domain/Crossfade.d.ts +78 -0
  138. package/dist/domain/Crossfade.d.ts.map +1 -0
  139. package/dist/domain/Crossfade.js +216 -0
  140. package/dist/domain/Crossfade.js.map +1 -0
  141. package/dist/domain/ExportConfig.d.ts +98 -1
  142. package/dist/domain/ExportConfig.d.ts.map +1 -1
  143. package/dist/domain/ExportConfig.js +154 -1
  144. package/dist/domain/ExportConfig.js.map +1 -1
  145. package/dist/domain/ExportPreset.d.ts +62 -0
  146. package/dist/domain/ExportPreset.d.ts.map +1 -0
  147. package/dist/domain/ExportPreset.js +79 -0
  148. package/dist/domain/ExportPreset.js.map +1 -0
  149. package/dist/domain/ImportStatus.d.ts +40 -0
  150. package/dist/domain/ImportStatus.d.ts.map +1 -0
  151. package/dist/domain/ImportStatus.js +86 -0
  152. package/dist/domain/ImportStatus.js.map +1 -0
  153. package/dist/domain/Playlist.d.ts +72 -0
  154. package/dist/domain/Playlist.d.ts.map +1 -1
  155. package/dist/domain/Playlist.js +231 -6
  156. package/dist/domain/Playlist.js.map +1 -1
  157. package/dist/domain/Region.d.ts +76 -0
  158. package/dist/domain/Region.d.ts.map +1 -1
  159. package/dist/domain/Region.js +234 -1
  160. package/dist/domain/Region.js.map +1 -1
  161. package/dist/domain/Route.d.ts +43 -3
  162. package/dist/domain/Route.d.ts.map +1 -1
  163. package/dist/domain/Route.js +92 -6
  164. package/dist/domain/Route.js.map +1 -1
  165. package/dist/domain/Session.d.ts +31 -0
  166. package/dist/domain/Session.d.ts.map +1 -1
  167. package/dist/domain/Session.js +70 -0
  168. package/dist/domain/Session.js.map +1 -1
  169. package/dist/domain/Source.d.ts +145 -1
  170. package/dist/domain/Source.d.ts.map +1 -1
  171. package/dist/domain/Source.js +144 -1
  172. package/dist/domain/Source.js.map +1 -1
  173. package/dist/domain/ThawList.d.ts +37 -0
  174. package/dist/domain/ThawList.d.ts.map +1 -0
  175. package/dist/domain/ThawList.js +73 -0
  176. package/dist/domain/ThawList.js.map +1 -0
  177. package/dist/domain/Track.d.ts +93 -1
  178. package/dist/domain/Track.d.ts.map +1 -1
  179. package/dist/domain/Track.js +136 -0
  180. package/dist/domain/Track.js.map +1 -1
  181. package/dist/domain/TriggerBox.d.ts +123 -0
  182. package/dist/domain/TriggerBox.d.ts.map +1 -0
  183. package/dist/domain/TriggerBox.js +430 -0
  184. package/dist/domain/TriggerBox.js.map +1 -0
  185. package/dist/domain/VCATrack.d.ts +64 -1
  186. package/dist/domain/VCATrack.d.ts.map +1 -1
  187. package/dist/domain/VCATrack.js +128 -1
  188. package/dist/domain/VCATrack.js.map +1 -1
  189. package/dist/domain/VideoExportConfig.d.ts +117 -0
  190. package/dist/domain/VideoExportConfig.d.ts.map +1 -0
  191. package/dist/domain/VideoExportConfig.js +244 -0
  192. package/dist/domain/VideoExportConfig.js.map +1 -0
  193. package/dist/domain/VideoExportStatus.d.ts +89 -0
  194. package/dist/domain/VideoExportStatus.d.ts.map +1 -0
  195. package/dist/domain/VideoExportStatus.js +192 -0
  196. package/dist/domain/VideoExportStatus.js.map +1 -0
  197. package/dist/domain/VideoMetadata.d.ts +46 -0
  198. package/dist/domain/VideoMetadata.d.ts.map +1 -0
  199. package/dist/domain/VideoMetadata.js +2 -0
  200. package/dist/domain/VideoMetadata.js.map +1 -0
  201. package/dist/domain/index.d.ts +5 -0
  202. package/dist/domain/index.d.ts.map +1 -1
  203. package/dist/domain/index.js +5 -0
  204. package/dist/domain/index.js.map +1 -1
  205. package/dist/domain/temporal/TempoMap.d.ts +199 -2
  206. package/dist/domain/temporal/TempoMap.d.ts.map +1 -1
  207. package/dist/domain/temporal/TempoMap.js +464 -30
  208. package/dist/domain/temporal/TempoMap.js.map +1 -1
  209. package/dist/index.d.ts +43 -1
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +32 -1
  212. package/dist/index.js.map +1 -1
  213. package/dist/lib/ThawList.d.ts +100 -0
  214. package/dist/lib/ThawList.d.ts.map +1 -0
  215. package/dist/lib/ThawList.js +153 -0
  216. package/dist/lib/ThawList.js.map +1 -0
  217. package/dist/midi/MidiFileParser.d.ts +33 -0
  218. package/dist/midi/MidiFileParser.d.ts.map +1 -0
  219. package/dist/midi/MidiFileParser.js +246 -0
  220. package/dist/midi/MidiFileParser.js.map +1 -0
  221. package/dist/midi/MidiFileWriter.d.ts +31 -0
  222. package/dist/midi/MidiFileWriter.d.ts.map +1 -0
  223. package/dist/midi/MidiFileWriter.js +160 -0
  224. package/dist/midi/MidiFileWriter.js.map +1 -0
  225. package/dist/midi/MidiImporter.d.ts +37 -0
  226. package/dist/midi/MidiImporter.d.ts.map +1 -0
  227. package/dist/midi/MidiImporter.js +62 -0
  228. package/dist/midi/MidiImporter.js.map +1 -0
  229. package/dist/plugins/PluginPresetManager.d.ts +86 -0
  230. package/dist/plugins/PluginPresetManager.d.ts.map +1 -0
  231. package/dist/plugins/PluginPresetManager.js +140 -0
  232. package/dist/plugins/PluginPresetManager.js.map +1 -0
  233. package/dist/processing/IO.d.ts +15 -1
  234. package/dist/processing/IO.d.ts.map +1 -1
  235. package/dist/processing/IO.js +29 -1
  236. package/dist/processing/IO.js.map +1 -1
  237. package/dist/processing/InternalSend.d.ts +104 -0
  238. package/dist/processing/InternalSend.d.ts.map +1 -0
  239. package/dist/processing/InternalSend.js +175 -0
  240. package/dist/processing/InternalSend.js.map +1 -0
  241. package/dist/processing/MeterDSP.d.ts +166 -0
  242. package/dist/processing/MeterDSP.d.ts.map +1 -0
  243. package/dist/processing/MeterDSP.js +754 -0
  244. package/dist/processing/MeterDSP.js.map +1 -0
  245. package/dist/processing/Panner.d.ts +145 -0
  246. package/dist/processing/Panner.d.ts.map +1 -0
  247. package/dist/processing/Panner.js +281 -0
  248. package/dist/processing/Panner.js.map +1 -0
  249. package/dist/processing/PluginInsert.d.ts +56 -1
  250. package/dist/processing/PluginInsert.d.ts.map +1 -1
  251. package/dist/processing/PluginInsert.js +180 -2
  252. package/dist/processing/PluginInsert.js.map +1 -1
  253. package/dist/processing/Processor.d.ts +38 -0
  254. package/dist/processing/Processor.d.ts.map +1 -1
  255. package/dist/processing/Processor.js +60 -1
  256. package/dist/processing/Processor.js.map +1 -1
  257. package/dist/processing/SurroundPanner.d.ts +122 -0
  258. package/dist/processing/SurroundPanner.d.ts.map +1 -0
  259. package/dist/processing/SurroundPanner.js +376 -0
  260. package/dist/processing/SurroundPanner.js.map +1 -0
  261. package/dist/processing/TruePeakLimiter.d.ts +34 -0
  262. package/dist/processing/TruePeakLimiter.d.ts.map +1 -0
  263. package/dist/processing/TruePeakLimiter.js +144 -0
  264. package/dist/processing/TruePeakLimiter.js.map +1 -0
  265. package/dist/storage/ExportPresetStorage.d.ts +33 -0
  266. package/dist/storage/ExportPresetStorage.d.ts.map +1 -0
  267. package/dist/storage/ExportPresetStorage.js +121 -0
  268. package/dist/storage/ExportPresetStorage.js.map +1 -0
  269. package/dist/storage/SessionArchive.d.ts +73 -0
  270. package/dist/storage/SessionArchive.d.ts.map +1 -0
  271. package/dist/storage/SessionArchive.js +211 -0
  272. package/dist/storage/SessionArchive.js.map +1 -0
  273. package/dist/storage/SessionTemplate.d.ts +74 -5
  274. package/dist/storage/SessionTemplate.d.ts.map +1 -1
  275. package/dist/storage/SessionTemplate.js +247 -53
  276. package/dist/storage/SessionTemplate.js.map +1 -1
  277. package/dist/utils/BwfMetadataWriter.d.ts +42 -0
  278. package/dist/utils/BwfMetadataWriter.d.ts.map +1 -0
  279. package/dist/utils/BwfMetadataWriter.js +131 -0
  280. package/dist/utils/BwfMetadataWriter.js.map +1 -0
  281. package/dist/utils/FilenameTemplate.d.ts +40 -0
  282. package/dist/utils/FilenameTemplate.d.ts.map +1 -0
  283. package/dist/utils/FilenameTemplate.js +78 -0
  284. package/dist/utils/FilenameTemplate.js.map +1 -0
  285. package/dist/utils/Logger.d.ts +28 -0
  286. package/dist/utils/Logger.d.ts.map +1 -0
  287. package/dist/utils/Logger.js +46 -0
  288. package/dist/utils/Logger.js.map +1 -0
  289. package/dist/utils/Mp4ChapterGenerator.d.ts +17 -0
  290. package/dist/utils/Mp4ChapterGenerator.d.ts.map +1 -0
  291. package/dist/utils/Mp4ChapterGenerator.js +33 -0
  292. package/dist/utils/Mp4ChapterGenerator.js.map +1 -0
  293. package/dist/utils/OggEncoder.d.ts +20 -20
  294. package/dist/utils/OggEncoder.d.ts.map +1 -1
  295. package/dist/utils/OggEncoder.js +114 -50
  296. package/dist/utils/OggEncoder.js.map +1 -1
  297. package/dist/utils/TocGenerator.d.ts +17 -0
  298. package/dist/utils/TocGenerator.d.ts.map +1 -0
  299. package/dist/utils/TocGenerator.js +47 -0
  300. package/dist/utils/TocGenerator.js.map +1 -0
  301. package/package.json +7 -8
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Standard MIDI File (SMF) Parser
3
+ * Ardour reference: libs/evoral/SMF.cc
4
+ *
5
+ * Parses SMF Type 0 (single track) and Type 1 (multi-track) files.
6
+ * Converts MIDI ticks to frames based on tempo.
7
+ */
8
+ /**
9
+ * Parse a Standard MIDI File from an ArrayBuffer.
10
+ */
11
+ export function parseMidiFile(data, sampleRate = 44100) {
12
+ const view = new DataView(data);
13
+ let offset = 0;
14
+ // Read header chunk "MThd"
15
+ const headerTag = readString(view, offset, 4);
16
+ if (headerTag !== 'MThd') {
17
+ throw new Error('Not a valid MIDI file: missing MThd header');
18
+ }
19
+ offset += 4;
20
+ const headerLength = view.getUint32(offset, false);
21
+ offset += 4;
22
+ const format = view.getUint16(offset, false);
23
+ offset += 2;
24
+ const numTracks = view.getUint16(offset, false);
25
+ offset += 2;
26
+ const division = view.getUint16(offset, false);
27
+ offset += 2;
28
+ // Skip any remaining header bytes
29
+ offset += headerLength - 6;
30
+ let ticksPerBeat;
31
+ if (division & 0x8000) {
32
+ // SMPTE-based: frames per second + ticks per frame
33
+ const fps = -(((division >> 8) & 0xFF) << 24 >> 24); // sign-extend
34
+ const tpf = division & 0xFF;
35
+ ticksPerBeat = fps * tpf; // approximate
36
+ }
37
+ else {
38
+ ticksPerBeat = division;
39
+ }
40
+ // Parse track chunks
41
+ let globalTempo = 120; // Default BPM
42
+ const tracks = [];
43
+ for (let t = 0; t < numTracks && offset < data.byteLength; t++) {
44
+ const trackTag = readString(view, offset, 4);
45
+ if (trackTag !== 'MTrk') {
46
+ throw new Error(`Expected MTrk at offset ${offset}, got ${trackTag}`);
47
+ }
48
+ offset += 4;
49
+ const trackLength = view.getUint32(offset, false);
50
+ offset += 4;
51
+ const trackEnd = offset + trackLength;
52
+ const track = parseTrack(view, offset, trackEnd, ticksPerBeat, sampleRate);
53
+ // Extract tempo if present (first track in Type 1)
54
+ if (track.tempo > 0) {
55
+ globalTempo = track.tempo;
56
+ }
57
+ tracks.push({
58
+ name: track.name || `Track ${t + 1}`,
59
+ notes: track.notes,
60
+ channel: track.channel,
61
+ });
62
+ offset = trackEnd;
63
+ }
64
+ // Apply tempo to convert ticks to frames
65
+ const secondsPerTick = 60 / (globalTempo * ticksPerBeat);
66
+ for (const track of tracks) {
67
+ for (const note of track.notes) {
68
+ note.startFrame = Math.round(note.startTick * secondsPerTick * sampleRate);
69
+ note.durationFrames = Math.round(note.durationTicks * secondsPerTick * sampleRate);
70
+ }
71
+ }
72
+ return {
73
+ format,
74
+ numTracks,
75
+ ticksPerBeat,
76
+ tempo: globalTempo,
77
+ tracks,
78
+ };
79
+ }
80
+ function parseTrack(view, start, end, ticksPerBeat, sampleRate) {
81
+ let offset = start;
82
+ let tick = 0;
83
+ let name = '';
84
+ let tempo = 0;
85
+ let primaryChannel = 0;
86
+ // Track active notes for Note-On/Note-Off pairing
87
+ const activeNotes = new Map();
88
+ const notes = [];
89
+ let prevStatus = 0;
90
+ while (offset < end) {
91
+ // Read delta time (variable-length quantity)
92
+ const [deltaTime, bytesRead] = readVLQ(view, offset);
93
+ offset += bytesRead;
94
+ tick += deltaTime;
95
+ if (offset >= end)
96
+ break;
97
+ let statusByte = view.getUint8(offset);
98
+ // Running status
99
+ if (statusByte < 0x80) {
100
+ statusByte = prevStatus;
101
+ }
102
+ else {
103
+ offset++;
104
+ prevStatus = statusByte;
105
+ }
106
+ const type = statusByte & 0xF0;
107
+ const channel = statusByte & 0x0F;
108
+ switch (type) {
109
+ case 0x90: { // Note On
110
+ const pitch = view.getUint8(offset++);
111
+ const velocity = view.getUint8(offset++);
112
+ if (velocity === 0) {
113
+ // Note On with velocity 0 = Note Off
114
+ finishNote(activeNotes, notes, channel, pitch, tick);
115
+ }
116
+ else {
117
+ const key = `${channel}-${pitch}`;
118
+ // End any existing note on same key
119
+ finishNote(activeNotes, notes, channel, pitch, tick);
120
+ activeNotes.set(key, { pitch, velocity, channel, startTick: tick });
121
+ primaryChannel = channel;
122
+ }
123
+ break;
124
+ }
125
+ case 0x80: { // Note Off
126
+ const pitch = view.getUint8(offset++);
127
+ offset++; // velocity (ignored)
128
+ finishNote(activeNotes, notes, channel, pitch, tick);
129
+ break;
130
+ }
131
+ case 0xA0: // Aftertouch
132
+ case 0xB0: // Control Change
133
+ case 0xE0: // Pitch Bend
134
+ offset += 2;
135
+ break;
136
+ case 0xC0: // Program Change
137
+ case 0xD0: // Channel Pressure
138
+ offset += 1;
139
+ break;
140
+ case 0xF0: {
141
+ if (statusByte === 0xFF) {
142
+ // Meta event
143
+ const metaType = view.getUint8(offset++);
144
+ const [metaLength, metaLenBytes] = readVLQ(view, offset);
145
+ offset += metaLenBytes;
146
+ if (metaType === 0x03) {
147
+ // Track Name
148
+ name = readString(view, offset, metaLength);
149
+ }
150
+ else if (metaType === 0x51) {
151
+ // Tempo (microseconds per quarter note)
152
+ if (metaLength >= 3) {
153
+ const uspqn = (view.getUint8(offset) << 16) |
154
+ (view.getUint8(offset + 1) << 8) |
155
+ view.getUint8(offset + 2);
156
+ tempo = 60000000 / uspqn;
157
+ }
158
+ }
159
+ else if (metaType === 0x2F) {
160
+ // End of Track
161
+ offset += metaLength;
162
+ // Close any remaining active notes
163
+ for (const [key, note] of activeNotes) {
164
+ notes.push({
165
+ pitch: note.pitch,
166
+ velocity: note.velocity,
167
+ channel: note.channel,
168
+ startTick: note.startTick,
169
+ durationTicks: tick - note.startTick,
170
+ startFrame: 0,
171
+ durationFrames: 0,
172
+ });
173
+ }
174
+ activeNotes.clear();
175
+ return { name, notes, channel: primaryChannel, tempo };
176
+ }
177
+ offset += metaLength;
178
+ }
179
+ else if (statusByte === 0xF0 || statusByte === 0xF7) {
180
+ // SysEx
181
+ const [sysexLen, sysexLenBytes] = readVLQ(view, offset);
182
+ offset += sysexLenBytes + sysexLen;
183
+ }
184
+ else {
185
+ // Other system messages
186
+ break;
187
+ }
188
+ break;
189
+ }
190
+ default:
191
+ // Unknown — skip
192
+ break;
193
+ }
194
+ }
195
+ // Close remaining notes
196
+ for (const [key, note] of activeNotes) {
197
+ notes.push({
198
+ pitch: note.pitch,
199
+ velocity: note.velocity,
200
+ channel: note.channel,
201
+ startTick: note.startTick,
202
+ durationTicks: tick - note.startTick,
203
+ startFrame: 0,
204
+ durationFrames: 0,
205
+ });
206
+ }
207
+ return { name, notes, channel: primaryChannel, tempo };
208
+ }
209
+ function finishNote(activeNotes, notes, channel, pitch, tick) {
210
+ const key = `${channel}-${pitch}`;
211
+ const active = activeNotes.get(key);
212
+ if (active) {
213
+ notes.push({
214
+ pitch: active.pitch,
215
+ velocity: active.velocity,
216
+ channel: active.channel,
217
+ startTick: active.startTick,
218
+ durationTicks: tick - active.startTick,
219
+ startFrame: 0,
220
+ durationFrames: 0,
221
+ });
222
+ activeNotes.delete(key);
223
+ }
224
+ }
225
+ function readVLQ(view, offset) {
226
+ let value = 0;
227
+ let bytesRead = 0;
228
+ while (offset + bytesRead < view.byteLength) {
229
+ const byte = view.getUint8(offset + bytesRead);
230
+ value = (value << 7) | (byte & 0x7F);
231
+ bytesRead++;
232
+ if ((byte & 0x80) === 0)
233
+ break;
234
+ if (bytesRead > 4)
235
+ break; // VLQ can't be more than 4 bytes
236
+ }
237
+ return [value, bytesRead];
238
+ }
239
+ function readString(view, offset, length) {
240
+ let str = '';
241
+ for (let i = 0; i < length && offset + i < view.byteLength; i++) {
242
+ str += String.fromCharCode(view.getUint8(offset + i));
243
+ }
244
+ return str;
245
+ }
246
+ //# sourceMappingURL=MidiFileParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiFileParser.js","sourceRoot":"","sources":["../../src/midi/MidiFileParser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Standard MIDI File (SMF) Writer
3
+ * Ardour reference: libs/ardour/smf_source.cc / export_smf_writer.cc
4
+ *
5
+ * Generates SMF Type 1 files from MidiRegion/MidiNote data.
6
+ */
7
+ export interface MidiWriteNote {
8
+ pitch: number;
9
+ velocity: number;
10
+ channel: number;
11
+ startFrame: number;
12
+ durationFrames: number;
13
+ }
14
+ export interface MidiWriteTrack {
15
+ name: string;
16
+ notes: MidiWriteNote[];
17
+ }
18
+ export interface MidiWriteOptions {
19
+ ticksPerBeat?: number;
20
+ tempo?: number;
21
+ sampleRate?: number;
22
+ }
23
+ /**
24
+ * Write a Standard MIDI File (Type 1) to an ArrayBuffer.
25
+ */
26
+ export declare function writeMidiFile(tracks: MidiWriteTrack[], options?: MidiWriteOptions): ArrayBuffer;
27
+ /**
28
+ * Convenience: create a MIDI file Blob from tracks.
29
+ */
30
+ export declare function createMidiBlob(tracks: MidiWriteTrack[], options?: MidiWriteOptions): Blob;
31
+ //# sourceMappingURL=MidiFileWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiFileWriter.d.ts","sourceRoot":"","sources":["../../src/midi/MidiFileWriter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,aAAa,CACzB,MAAM,EAAE,cAAc,EAAE,EACxB,OAAO,GAAE,gBAAqB,GAC/B,WAAW,CA0Cb;AAqJD;;GAEG;AACH,wBAAgB,cAAc,CAC1B,MAAM,EAAE,cAAc,EAAE,EACxB,OAAO,CAAC,EAAE,gBAAgB,GAC3B,IAAI,CAGN"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Standard MIDI File (SMF) Writer
3
+ * Ardour reference: libs/ardour/smf_source.cc / export_smf_writer.cc
4
+ *
5
+ * Generates SMF Type 1 files from MidiRegion/MidiNote data.
6
+ */
7
+ /**
8
+ * Write a Standard MIDI File (Type 1) to an ArrayBuffer.
9
+ */
10
+ export function writeMidiFile(tracks, options = {}) {
11
+ var _a, _b, _c;
12
+ const ticksPerBeat = (_a = options.ticksPerBeat) !== null && _a !== void 0 ? _a : 480;
13
+ const tempo = (_b = options.tempo) !== null && _b !== void 0 ? _b : 120;
14
+ const sampleRate = (_c = options.sampleRate) !== null && _c !== void 0 ? _c : 44100;
15
+ // Convert frames to ticks
16
+ const secondsPerTick = 60 / (tempo * ticksPerBeat);
17
+ const framesToTicks = (frames) => Math.round(frames / (secondsPerTick * sampleRate));
18
+ const trackChunks = [];
19
+ // Track 0: tempo track
20
+ trackChunks.push(buildTempoTrack(tempo, ticksPerBeat));
21
+ // Subsequent tracks: note data
22
+ for (const track of tracks) {
23
+ trackChunks.push(buildNoteTrack(track, framesToTicks));
24
+ }
25
+ // Build file header
26
+ const numTracks = trackChunks.length;
27
+ const headerChunk = buildHeaderChunk(1, numTracks, ticksPerBeat);
28
+ // Calculate total size
29
+ let totalSize = headerChunk.byteLength;
30
+ for (const chunk of trackChunks) {
31
+ totalSize += chunk.byteLength;
32
+ }
33
+ // Combine all chunks
34
+ const result = new Uint8Array(totalSize);
35
+ let offset = 0;
36
+ result.set(new Uint8Array(headerChunk), offset);
37
+ offset += headerChunk.byteLength;
38
+ for (const chunk of trackChunks) {
39
+ result.set(chunk, offset);
40
+ offset += chunk.byteLength;
41
+ }
42
+ return result.buffer;
43
+ }
44
+ function buildHeaderChunk(format, numTracks, ticksPerBeat) {
45
+ const buffer = new ArrayBuffer(14);
46
+ const view = new DataView(buffer);
47
+ // "MThd"
48
+ view.setUint8(0, 0x4D);
49
+ view.setUint8(1, 0x54);
50
+ view.setUint8(2, 0x68);
51
+ view.setUint8(3, 0x64);
52
+ // Header length (always 6)
53
+ view.setUint32(4, 6, false);
54
+ // Format
55
+ view.setUint16(8, format, false);
56
+ // Number of tracks
57
+ view.setUint16(10, numTracks, false);
58
+ // Division (ticks per beat)
59
+ view.setUint16(12, ticksPerBeat, false);
60
+ return buffer;
61
+ }
62
+ function buildTempoTrack(tempo, ticksPerBeat) {
63
+ const events = [];
64
+ // Delta time 0
65
+ events.push(0x00);
66
+ // Set Tempo meta event (FF 51 03 tt tt tt)
67
+ const uspqn = Math.round(60000000 / tempo);
68
+ events.push(0xFF, 0x51, 0x03);
69
+ events.push((uspqn >> 16) & 0xFF);
70
+ events.push((uspqn >> 8) & 0xFF);
71
+ events.push(uspqn & 0xFF);
72
+ // End of Track (delta=0)
73
+ events.push(0x00, 0xFF, 0x2F, 0x00);
74
+ return wrapTrackChunk(new Uint8Array(events));
75
+ }
76
+ function buildNoteTrack(track, framesToTicks) {
77
+ const events = [];
78
+ // Track Name meta event
79
+ if (track.name) {
80
+ const nameBytes = new TextEncoder().encode(track.name);
81
+ events.push({
82
+ tick: 0,
83
+ data: [0xFF, 0x03, ...writeVLQ(nameBytes.length), ...nameBytes],
84
+ });
85
+ }
86
+ // Note events
87
+ for (const note of track.notes) {
88
+ const startTick = framesToTicks(note.startFrame);
89
+ const endTick = framesToTicks(note.startFrame + note.durationFrames);
90
+ const channel = Math.max(0, Math.min(15, note.channel));
91
+ // Note On
92
+ events.push({
93
+ tick: startTick,
94
+ data: [0x90 | channel, note.pitch & 0x7F, note.velocity & 0x7F],
95
+ });
96
+ // Note Off
97
+ events.push({
98
+ tick: endTick,
99
+ data: [0x80 | channel, note.pitch & 0x7F, 0x40], // release velocity 64
100
+ });
101
+ }
102
+ // Sort by tick, Note Off before Note On at same tick
103
+ events.sort((a, b) => {
104
+ if (a.tick !== b.tick)
105
+ return a.tick - b.tick;
106
+ // Note Off (0x80) should come before Note On (0x90)
107
+ const aIsOff = (a.data[0] & 0xF0) === 0x80 ? 0 : 1;
108
+ const bIsOff = (b.data[0] & 0xF0) === 0x80 ? 0 : 1;
109
+ return aIsOff - bIsOff;
110
+ });
111
+ // Convert to byte stream with delta times
112
+ const bytes = [];
113
+ let prevTick = 0;
114
+ for (const event of events) {
115
+ const delta = Math.max(0, event.tick - prevTick);
116
+ bytes.push(...writeVLQ(delta));
117
+ bytes.push(...event.data);
118
+ prevTick = event.tick;
119
+ }
120
+ // End of Track
121
+ bytes.push(0x00, 0xFF, 0x2F, 0x00);
122
+ return wrapTrackChunk(new Uint8Array(bytes));
123
+ }
124
+ function wrapTrackChunk(trackData) {
125
+ const chunk = new Uint8Array(8 + trackData.length);
126
+ const view = new DataView(chunk.buffer);
127
+ // "MTrk"
128
+ chunk[0] = 0x4D;
129
+ chunk[1] = 0x54;
130
+ chunk[2] = 0x72;
131
+ chunk[3] = 0x6B;
132
+ // Track length
133
+ view.setUint32(4, trackData.length, false);
134
+ // Track data
135
+ chunk.set(trackData, 8);
136
+ return chunk;
137
+ }
138
+ function writeVLQ(value) {
139
+ if (value < 0)
140
+ value = 0;
141
+ if (value < 0x80)
142
+ return [value];
143
+ const bytes = [];
144
+ let v = value;
145
+ bytes.unshift(v & 0x7F);
146
+ v >>= 7;
147
+ while (v > 0) {
148
+ bytes.unshift((v & 0x7F) | 0x80);
149
+ v >>= 7;
150
+ }
151
+ return bytes;
152
+ }
153
+ /**
154
+ * Convenience: create a MIDI file Blob from tracks.
155
+ */
156
+ export function createMidiBlob(tracks, options) {
157
+ const buffer = writeMidiFile(tracks, options);
158
+ return new Blob([buffer], { type: 'audio/midi' });
159
+ }
160
+ //# sourceMappingURL=MidiFileWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiFileWriter.js","sourceRoot":"","sources":["../../src/midi/MidiFileWriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MIDI Importer — bridges MidiFileParser output to domain models.
3
+ * Creates MidiClip/MidiRegion/Track from parsed MIDI file data.
4
+ */
5
+ import { MidiFileData } from './MidiFileParser';
6
+ import { MidiClip } from '../domain/MidiClip';
7
+ import { MidiRegion } from '../domain/MidiRegion';
8
+ export interface MidiImportResult {
9
+ /** Parsed file metadata */
10
+ fileData: MidiFileData;
11
+ /** One MidiClip per track in the file */
12
+ clips: MidiClip[];
13
+ /** One MidiRegion per track, positioned at startFrame */
14
+ regions: MidiRegion[];
15
+ }
16
+ /**
17
+ * Import a MIDI file from an ArrayBuffer.
18
+ *
19
+ * @param data Raw .mid file bytes
20
+ * @param sampleRate Session sample rate (for tick-to-frame conversion)
21
+ * @param startFrame Where to place the imported regions on the timeline
22
+ */
23
+ export declare function importMidiFile(data: ArrayBuffer, sampleRate?: number, startFrame?: number): MidiImportResult;
24
+ /**
25
+ * Export MidiRegions to MIDI file data for the writer.
26
+ */
27
+ export declare function exportMidiRegions(regions: MidiRegion[], sampleRate?: number): {
28
+ name: string;
29
+ notes: Array<{
30
+ pitch: number;
31
+ velocity: number;
32
+ channel: number;
33
+ startFrame: number;
34
+ durationFrames: number;
35
+ }>;
36
+ }[];
37
+ //# sourceMappingURL=MidiImporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiImporter.d.ts","sourceRoot":"","sources":["../../src/midi/MidiImporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAgC,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC7B,2BAA2B;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,yCAAyC;IACzC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yDAAyD;IACzD,OAAO,EAAE,UAAU,EAAE,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC1B,IAAI,EAAE,WAAW,EACjB,UAAU,GAAE,MAAc,EAC1B,UAAU,GAAE,MAAU,GACvB,gBAAgB,CA0DlB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,OAAO,EAAE,UAAU,EAAE,EACrB,UAAU,GAAE,MAAc,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,EAAE,CAWpI"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * MIDI Importer — bridges MidiFileParser output to domain models.
3
+ * Creates MidiClip/MidiRegion/Track from parsed MIDI file data.
4
+ */
5
+ import { parseMidiFile } from './MidiFileParser';
6
+ import { MidiClip } from '../domain/MidiClip';
7
+ import { MidiNote } from '../domain/MidiNote';
8
+ import { MidiRegion } from '../domain/MidiRegion';
9
+ /**
10
+ * Import a MIDI file from an ArrayBuffer.
11
+ *
12
+ * @param data Raw .mid file bytes
13
+ * @param sampleRate Session sample rate (for tick-to-frame conversion)
14
+ * @param startFrame Where to place the imported regions on the timeline
15
+ */
16
+ export function importMidiFile(data, sampleRate = 44100, startFrame = 0) {
17
+ const fileData = parseMidiFile(data, sampleRate);
18
+ const clips = [];
19
+ const regions = [];
20
+ for (let i = 0; i < fileData.tracks.length; i++) {
21
+ const track = fileData.tracks[i];
22
+ // Skip empty tracks (common in Type 1 — track 0 is often tempo-only)
23
+ if (track.notes.length === 0)
24
+ continue;
25
+ const clipId = crypto.randomUUID();
26
+ const regionId = crypto.randomUUID();
27
+ // Create MidiNotes from parsed data
28
+ const midiNotes = track.notes.map(n => {
29
+ return new MidiNote(crypto.randomUUID(), n.pitch, n.velocity, n.startFrame, n.durationFrames, n.channel);
30
+ });
31
+ // Create MidiClip
32
+ const clip = new MidiClip(clipId, track.name, midiNotes);
33
+ clips.push(clip);
34
+ // Create MidiRegion
35
+ const clipDuration = clip.getDuration();
36
+ const region = new MidiRegion(regionId, track.name, startFrame, clipDuration);
37
+ // Add notes to region
38
+ for (const note of midiNotes) {
39
+ // Clone notes for the region (they're separate from clip notes)
40
+ const regionNote = new MidiNote(crypto.randomUUID(), note.pitch, note.velocity, note.startFrame, note.durationFrames, note.channel);
41
+ region.addNote(regionNote);
42
+ }
43
+ regions.push(region);
44
+ }
45
+ return { fileData, clips, regions };
46
+ }
47
+ /**
48
+ * Export MidiRegions to MIDI file data for the writer.
49
+ */
50
+ export function exportMidiRegions(regions, sampleRate = 44100) {
51
+ return regions.map(region => ({
52
+ name: region.name,
53
+ notes: region.getNotes().map(n => ({
54
+ pitch: n.pitch,
55
+ velocity: n.velocity,
56
+ channel: n.channel,
57
+ startFrame: n.startFrame,
58
+ durationFrames: n.durationFrames,
59
+ })),
60
+ }));
61
+ }
62
+ //# sourceMappingURL=MidiImporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiImporter.js","sourceRoot":"","sources":["../../src/midi/MidiImporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { Signal } from '../lib/Signal';
2
+ import { Plugin } from './Plugin';
3
+ /**
4
+ * A named snapshot of plugin parameter values that can be saved, recalled,
5
+ * and applied to a compatible plugin instance.
6
+ */
7
+ export interface PluginPreset {
8
+ /** Unique preset identifier. */
9
+ id: string;
10
+ /** Human-readable preset name. */
11
+ name: string;
12
+ /** Descriptor ID of the plugin this preset targets (e.g. 'internal-reverb'). */
13
+ pluginId: string;
14
+ /** Optional version string the preset was created against. */
15
+ pluginVersion?: string;
16
+ /** Parameter name -> value map. */
17
+ parameters: Record<string, number>;
18
+ /** Arbitrary key/value metadata (author, notes, tags, etc.). */
19
+ metadata?: Record<string, string>;
20
+ /** Whether this preset ships with the application (factory) or was
21
+ * created by the user. */
22
+ isFactory: boolean;
23
+ /** ISO-8601 creation timestamp. */
24
+ createdAt: string;
25
+ }
26
+ /**
27
+ * Manages plugin presets across all plugin types.
28
+ *
29
+ * Presets are organized by `pluginId` so they can be quickly looked up when
30
+ * a user opens a plugin UI. The manager distinguishes between factory
31
+ * presets (read-only, shipped with the application) and user presets.
32
+ *
33
+ * Signal-based notification is provided via `presetsChanged`, which emits
34
+ * the affected `pluginId` whenever presets are added, removed, or updated.
35
+ */
36
+ export declare class PluginPresetManager {
37
+ /** pluginId -> ordered array of presets */
38
+ private _presets;
39
+ /**
40
+ * Emitted whenever presets change for a given plugin. The payload is the
41
+ * affected `pluginId`.
42
+ */
43
+ readonly presetsChanged: Signal<string>;
44
+ /**
45
+ * Save a new user preset for the specified plugin.
46
+ *
47
+ * @returns The newly created preset (with generated `id` and timestamp).
48
+ */
49
+ savePreset(pluginId: string, name: string, parameters: Record<string, number>, metadata?: Record<string, string>, pluginVersion?: string): PluginPreset;
50
+ /**
51
+ * Delete a preset by its unique ID. Factory presets cannot be deleted.
52
+ *
53
+ * @returns `true` if the preset was found and deleted.
54
+ */
55
+ deletePreset(presetId: string): boolean;
56
+ /**
57
+ * Get all presets (factory + user) for a given plugin type.
58
+ */
59
+ getPresetsForPlugin(pluginId: string): PluginPreset[];
60
+ /**
61
+ * Get a single preset by its unique ID, searching across all plugins.
62
+ */
63
+ getPreset(presetId: string): PluginPreset | undefined;
64
+ /**
65
+ * Apply a preset to a live Plugin instance by calling `setParameter()`
66
+ * for each stored parameter value.
67
+ */
68
+ applyPreset(presetId: string, plugin: Plugin): void;
69
+ /**
70
+ * Register one or more factory presets for a plugin type.
71
+ *
72
+ * Factory presets are read-only and are prepended to the preset list so
73
+ * they appear before user presets in UIs.
74
+ */
75
+ registerFactoryPresets(pluginId: string, presets: Omit<PluginPreset, 'id' | 'createdAt' | 'isFactory'>[]): void;
76
+ /**
77
+ * Serialize all presets (factory + user) to a JSON string.
78
+ */
79
+ serialize(): string;
80
+ /**
81
+ * Restore a PluginPresetManager from a JSON string produced by
82
+ * `serialize()`.
83
+ */
84
+ static deserialize(json: string): PluginPresetManager;
85
+ }
86
+ //# sourceMappingURL=PluginPresetManager.d.ts.map