@drop-ai/core 0.3.0 → 0.3.2

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 (390) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +734 -734
  3. package/dist/analysis/AudioAnalyzer.d.ts +0 -2
  4. package/dist/analysis/AudioAnalyzer.d.ts.map +1 -1
  5. package/dist/analysis/AudioAnalyzer.js +0 -2
  6. package/dist/analysis/AudioAnalyzer.js.map +1 -1
  7. package/dist/audio/Auditioner.d.ts +0 -2
  8. package/dist/audio/Auditioner.d.ts.map +1 -1
  9. package/dist/audio/Auditioner.js +0 -2
  10. package/dist/audio/Auditioner.js.map +1 -1
  11. package/dist/audio/BWFMetadata.d.ts +0 -2
  12. package/dist/audio/BWFMetadata.d.ts.map +1 -1
  13. package/dist/audio/BWFMetadata.js +0 -2
  14. package/dist/audio/BWFMetadata.js.map +1 -1
  15. package/dist/audio/BufferPool.d.ts +0 -3
  16. package/dist/audio/BufferPool.d.ts.map +1 -1
  17. package/dist/audio/BufferPool.js +0 -3
  18. package/dist/audio/BufferPool.js.map +1 -1
  19. package/dist/audio/ChannelSplitter.d.ts +0 -1
  20. package/dist/audio/ChannelSplitter.d.ts.map +1 -1
  21. package/dist/audio/ChannelSplitter.js +0 -1
  22. package/dist/audio/ChannelSplitter.js.map +1 -1
  23. package/dist/audio/ExportAnalyzer.d.ts +0 -1
  24. package/dist/audio/ExportAnalyzer.d.ts.map +1 -1
  25. package/dist/audio/ExportAnalyzer.js +0 -1
  26. package/dist/audio/ExportAnalyzer.js.map +1 -1
  27. package/dist/audio/LufsNormalizer.d.ts +0 -1
  28. package/dist/audio/LufsNormalizer.d.ts.map +1 -1
  29. package/dist/audio/LufsNormalizer.js +0 -1
  30. package/dist/audio/LufsNormalizer.js.map +1 -1
  31. package/dist/audio/MeterUtils.d.ts +0 -2
  32. package/dist/audio/MeterUtils.d.ts.map +1 -1
  33. package/dist/audio/MeterUtils.js +0 -2
  34. package/dist/audio/MeterUtils.js.map +1 -1
  35. package/dist/audio/OfflineExporter.d.ts +0 -1
  36. package/dist/audio/OfflineExporter.d.ts.map +1 -1
  37. package/dist/audio/OfflineExporter.js +0 -1
  38. package/dist/audio/OfflineExporter.js.map +1 -1
  39. package/dist/audio/ProcessingGraph.d.ts +0 -1
  40. package/dist/audio/ProcessingGraph.d.ts.map +1 -1
  41. package/dist/audio/ProcessingGraph.js +0 -1
  42. package/dist/audio/ProcessingGraph.js.map +1 -1
  43. package/dist/audio/RoutingGraph.d.ts +1 -1
  44. package/dist/audio/RoutingGraph.js +2 -2
  45. package/dist/audio/SampleRateConverter.d.ts +0 -1
  46. package/dist/audio/SampleRateConverter.d.ts.map +1 -1
  47. package/dist/audio/SampleRateConverter.js +0 -1
  48. package/dist/audio/SampleRateConverter.js.map +1 -1
  49. package/dist/audio/SilencePadding.d.ts +0 -2
  50. package/dist/audio/SilencePadding.d.ts.map +1 -1
  51. package/dist/audio/SilencePadding.js +0 -2
  52. package/dist/audio/SilencePadding.js.map +1 -1
  53. package/dist/audio/SourceCache.d.ts +0 -3
  54. package/dist/audio/SourceCache.d.ts.map +1 -1
  55. package/dist/audio/SourceCache.js +0 -3
  56. package/dist/audio/SourceCache.js.map +1 -1
  57. package/dist/audio/engine/Declick.d.ts +0 -1
  58. package/dist/audio/engine/Declick.d.ts.map +1 -1
  59. package/dist/audio/engine/Declick.js +0 -1
  60. package/dist/audio/engine/Declick.js.map +1 -1
  61. package/dist/audio/engine/DiskIO.d.ts +0 -2
  62. package/dist/audio/engine/DiskIO.d.ts.map +1 -1
  63. package/dist/audio/engine/DiskIO.js +0 -2
  64. package/dist/audio/engine/DiskIO.js.map +1 -1
  65. package/dist/audio/engine/MultiTrackRecorder.d.ts +0 -2
  66. package/dist/audio/engine/MultiTrackRecorder.d.ts.map +1 -1
  67. package/dist/audio/engine/MultiTrackRecorder.js.map +1 -1
  68. package/dist/audio/engine/PlaylistEngine.d.ts +1 -1
  69. package/dist/audio/engine/PlaylistEngine.d.ts.map +1 -1
  70. package/dist/audio/engine/PlaylistEngine.js +1 -1
  71. package/dist/audio/engine/PlaylistEngine.js.map +1 -1
  72. package/dist/audio/engine/PunchRecordManager.d.ts +0 -2
  73. package/dist/audio/engine/PunchRecordManager.d.ts.map +1 -1
  74. package/dist/audio/engine/PunchRecordManager.js.map +1 -1
  75. package/dist/audio/engine/RoutingGraph.d.ts +0 -2
  76. package/dist/audio/engine/RoutingGraph.d.ts.map +1 -1
  77. package/dist/audio/engine/RoutingGraph.js.map +1 -1
  78. package/dist/audio/engine/SidechainRouter.d.ts +0 -2
  79. package/dist/audio/engine/SidechainRouter.d.ts.map +1 -1
  80. package/dist/audio/engine/SidechainRouter.js +0 -2
  81. package/dist/audio/engine/SidechainRouter.js.map +1 -1
  82. package/dist/audio/export/CDMarkerExporter.d.ts +0 -2
  83. package/dist/audio/export/CDMarkerExporter.d.ts.map +1 -1
  84. package/dist/audio/export/CDMarkerExporter.js +0 -2
  85. package/dist/audio/export/CDMarkerExporter.js.map +1 -1
  86. package/dist/audio/export/ExportGraphBuilder.d.ts +0 -2
  87. package/dist/audio/export/ExportGraphBuilder.d.ts.map +1 -1
  88. package/dist/audio/export/ExportGraphBuilder.js +0 -2
  89. package/dist/audio/export/ExportGraphBuilder.js.map +1 -1
  90. package/dist/audio/export/ExportPresetManager.d.ts +0 -2
  91. package/dist/audio/export/ExportPresetManager.d.ts.map +1 -1
  92. package/dist/audio/export/ExportPresetManager.js +0 -2
  93. package/dist/audio/export/ExportPresetManager.js.map +1 -1
  94. package/dist/automation/AutomationList.d.ts +0 -1
  95. package/dist/automation/AutomationList.d.ts.map +1 -1
  96. package/dist/automation/AutomationList.js +0 -1
  97. package/dist/automation/AutomationList.js.map +1 -1
  98. package/dist/automation/AutomationMode.d.ts +0 -1
  99. package/dist/automation/AutomationMode.d.ts.map +1 -1
  100. package/dist/automation/AutomationMode.js +0 -1
  101. package/dist/automation/AutomationMode.js.map +1 -1
  102. package/dist/commands/CommandHistory.d.ts +1 -4
  103. package/dist/commands/CommandHistory.d.ts.map +1 -1
  104. package/dist/commands/CommandHistory.js +6 -9
  105. package/dist/commands/CommandHistory.js.map +1 -1
  106. package/dist/commands/CommandRegistry.d.ts +1 -2
  107. package/dist/commands/CommandRegistry.d.ts.map +1 -1
  108. package/dist/commands/CommandRegistry.js +1 -2
  109. package/dist/commands/CommandRegistry.js.map +1 -1
  110. package/dist/commands/UndoTransaction.d.ts +0 -2
  111. package/dist/commands/UndoTransaction.d.ts.map +1 -1
  112. package/dist/commands/UndoTransaction.js +1 -3
  113. package/dist/commands/UndoTransaction.js.map +1 -1
  114. package/dist/commands/handlers/HistoryHandler.d.ts +5 -5
  115. package/dist/commands/handlers/HistoryHandler.js +10 -10
  116. package/dist/commands/handlers/HistoryHandler.js.map +1 -1
  117. package/dist/commands/handlers/MarkerHandler.d.ts +0 -1
  118. package/dist/commands/handlers/MarkerHandler.d.ts.map +1 -1
  119. package/dist/commands/handlers/MarkerHandler.js +0 -1
  120. package/dist/commands/handlers/MarkerHandler.js.map +1 -1
  121. package/dist/commands/impl/CopyRegionCommand.d.ts +0 -1
  122. package/dist/commands/impl/CopyRegionCommand.d.ts.map +1 -1
  123. package/dist/commands/impl/CopyRegionCommand.js +0 -1
  124. package/dist/commands/impl/CopyRegionCommand.js.map +1 -1
  125. package/dist/commands/impl/DuplicateRegionCommand.d.ts +0 -1
  126. package/dist/commands/impl/DuplicateRegionCommand.d.ts.map +1 -1
  127. package/dist/commands/impl/DuplicateRegionCommand.js +0 -1
  128. package/dist/commands/impl/DuplicateRegionCommand.js.map +1 -1
  129. package/dist/commands/impl/ExportCommand.d.ts +0 -1
  130. package/dist/commands/impl/ExportCommand.d.ts.map +1 -1
  131. package/dist/commands/impl/ExportCommand.js +0 -1
  132. package/dist/commands/impl/ExportCommand.js.map +1 -1
  133. package/dist/commands/impl/FreezeTrackCommand.d.ts +1 -1
  134. package/dist/commands/impl/FreezeTrackCommand.js +1 -1
  135. package/dist/commands/impl/PasteRegionCommand.d.ts +0 -1
  136. package/dist/commands/impl/PasteRegionCommand.d.ts.map +1 -1
  137. package/dist/commands/impl/PasteRegionCommand.js +0 -1
  138. package/dist/commands/impl/PasteRegionCommand.js.map +1 -1
  139. package/dist/commands/impl/SaveSnapshotCommand.d.ts +1 -1
  140. package/dist/commands/impl/SaveSnapshotCommand.js +1 -1
  141. package/dist/commands/impl/SetLoopRangeCommand.d.ts +0 -1
  142. package/dist/commands/impl/SetLoopRangeCommand.d.ts.map +1 -1
  143. package/dist/commands/impl/SetLoopRangeCommand.js +0 -1
  144. package/dist/commands/impl/SetLoopRangeCommand.js.map +1 -1
  145. package/dist/commands/impl/SetPunchRangeCommand.d.ts +0 -1
  146. package/dist/commands/impl/SetPunchRangeCommand.d.ts.map +1 -1
  147. package/dist/commands/impl/SetPunchRangeCommand.js +0 -1
  148. package/dist/commands/impl/SetPunchRangeCommand.js.map +1 -1
  149. package/dist/commands/impl/SplitAtPlayheadCommand.d.ts +0 -2
  150. package/dist/commands/impl/SplitAtPlayheadCommand.d.ts.map +1 -1
  151. package/dist/commands/impl/SplitAtPlayheadCommand.js +0 -2
  152. package/dist/commands/impl/SplitAtPlayheadCommand.js.map +1 -1
  153. package/dist/commands/impl/SplitRegionCommand.d.ts +0 -1
  154. package/dist/commands/impl/SplitRegionCommand.d.ts.map +1 -1
  155. package/dist/commands/impl/SplitRegionCommand.js +0 -1
  156. package/dist/commands/impl/SplitRegionCommand.js.map +1 -1
  157. package/dist/commands/impl/StripSilenceCommand.d.ts +0 -1
  158. package/dist/commands/impl/StripSilenceCommand.d.ts.map +1 -1
  159. package/dist/commands/impl/StripSilenceCommand.js +0 -1
  160. package/dist/commands/impl/StripSilenceCommand.js.map +1 -1
  161. package/dist/commands/impl/TimeStretchRegionCommand.d.ts +1 -2
  162. package/dist/commands/impl/TimeStretchRegionCommand.d.ts.map +1 -1
  163. package/dist/commands/impl/TimeStretchRegionCommand.js +1 -2
  164. package/dist/commands/impl/TimeStretchRegionCommand.js.map +1 -1
  165. package/dist/commands/impl/TrimRegionCommand.d.ts +1 -1
  166. package/dist/commands/impl/TrimRegionCommand.js +2 -2
  167. package/dist/commands/impl/TrimRegionCommand.js.map +1 -1
  168. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts +0 -1
  169. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts.map +1 -1
  170. package/dist/commands/impl/TrimRegionToPlayheadCommand.js +0 -1
  171. package/dist/commands/impl/TrimRegionToPlayheadCommand.js.map +1 -1
  172. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts +0 -1
  173. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts.map +1 -1
  174. package/dist/commands/impl/TrimRegionToRangeCommand.js +0 -1
  175. package/dist/commands/impl/TrimRegionToRangeCommand.js.map +1 -1
  176. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts +0 -1
  177. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts.map +1 -1
  178. package/dist/commands/impl/TrimToAdjacentRegionCommand.js +0 -1
  179. package/dist/commands/impl/TrimToAdjacentRegionCommand.js.map +1 -1
  180. package/dist/domain/ABComparison.d.ts +0 -1
  181. package/dist/domain/ABComparison.d.ts.map +1 -1
  182. package/dist/domain/ABComparison.js +0 -1
  183. package/dist/domain/ABComparison.js.map +1 -1
  184. package/dist/domain/CDMarker.d.ts +0 -1
  185. package/dist/domain/CDMarker.d.ts.map +1 -1
  186. package/dist/domain/CDMarker.js +0 -1
  187. package/dist/domain/CDMarker.js.map +1 -1
  188. package/dist/domain/ClockMode.d.ts +0 -1
  189. package/dist/domain/ClockMode.d.ts.map +1 -1
  190. package/dist/domain/ClockMode.js +0 -1
  191. package/dist/domain/ClockMode.js.map +1 -1
  192. package/dist/domain/DragManager.d.ts +0 -2
  193. package/dist/domain/DragManager.d.ts.map +1 -1
  194. package/dist/domain/DragManager.js +0 -2
  195. package/dist/domain/DragManager.js.map +1 -1
  196. package/dist/domain/EditMode.d.ts +0 -1
  197. package/dist/domain/EditMode.d.ts.map +1 -1
  198. package/dist/domain/EditMode.js +0 -1
  199. package/dist/domain/EditMode.js.map +1 -1
  200. package/dist/domain/ExportConfig.d.ts +0 -1
  201. package/dist/domain/ExportConfig.d.ts.map +1 -1
  202. package/dist/domain/ExportConfig.js +0 -1
  203. package/dist/domain/ExportConfig.js.map +1 -1
  204. package/dist/domain/ExportPreset.d.ts +0 -2
  205. package/dist/domain/ExportPreset.d.ts.map +1 -1
  206. package/dist/domain/ExportPreset.js +0 -2
  207. package/dist/domain/ExportPreset.js.map +1 -1
  208. package/dist/domain/ExportStatus.d.ts +0 -1
  209. package/dist/domain/ExportStatus.d.ts.map +1 -1
  210. package/dist/domain/ExportStatus.js +0 -1
  211. package/dist/domain/ExportStatus.js.map +1 -1
  212. package/dist/domain/GridSettings.d.ts +0 -3
  213. package/dist/domain/GridSettings.d.ts.map +1 -1
  214. package/dist/domain/GridSettings.js +0 -3
  215. package/dist/domain/GridSettings.js.map +1 -1
  216. package/dist/domain/Marker.d.ts +0 -1
  217. package/dist/domain/Marker.d.ts.map +1 -1
  218. package/dist/domain/Marker.js +0 -1
  219. package/dist/domain/Marker.js.map +1 -1
  220. package/dist/domain/MeterData.d.ts +0 -2
  221. package/dist/domain/MeterData.d.ts.map +1 -1
  222. package/dist/domain/MeterType.d.ts +0 -2
  223. package/dist/domain/MeterType.d.ts.map +1 -1
  224. package/dist/domain/MeterType.js +0 -2
  225. package/dist/domain/MeterType.js.map +1 -1
  226. package/dist/domain/MonitorMode.d.ts +0 -1
  227. package/dist/domain/MonitorMode.d.ts.map +1 -1
  228. package/dist/domain/MonitorMode.js +0 -1
  229. package/dist/domain/MonitorMode.js.map +1 -1
  230. package/dist/domain/MouseMode.d.ts +0 -1
  231. package/dist/domain/MouseMode.d.ts.map +1 -1
  232. package/dist/domain/MouseMode.js +0 -1
  233. package/dist/domain/MouseMode.js.map +1 -1
  234. package/dist/domain/OverlapType.d.ts +0 -2
  235. package/dist/domain/OverlapType.d.ts.map +1 -1
  236. package/dist/domain/OverlapType.js +0 -2
  237. package/dist/domain/OverlapType.js.map +1 -1
  238. package/dist/domain/Range.d.ts +0 -1
  239. package/dist/domain/Range.d.ts.map +1 -1
  240. package/dist/domain/Range.js +0 -1
  241. package/dist/domain/Range.js.map +1 -1
  242. package/dist/domain/RecordMode.d.ts +0 -1
  243. package/dist/domain/RecordMode.d.ts.map +1 -1
  244. package/dist/domain/RecordMode.js +0 -1
  245. package/dist/domain/RecordMode.js.map +1 -1
  246. package/dist/domain/Region.d.ts +3 -3
  247. package/dist/domain/Region.js +4 -4
  248. package/dist/domain/Region.js.map +1 -1
  249. package/dist/domain/RegionClipboard.d.ts +1 -3
  250. package/dist/domain/RegionClipboard.d.ts.map +1 -1
  251. package/dist/domain/RegionClipboard.js +1 -2
  252. package/dist/domain/RegionClipboard.js.map +1 -1
  253. package/dist/domain/RulerType.d.ts +0 -1
  254. package/dist/domain/RulerType.d.ts.map +1 -1
  255. package/dist/domain/RulerType.js +0 -1
  256. package/dist/domain/RulerType.js.map +1 -1
  257. package/dist/domain/SelectionHistory.d.ts +0 -3
  258. package/dist/domain/SelectionHistory.d.ts.map +1 -1
  259. package/dist/domain/SelectionHistory.js +0 -3
  260. package/dist/domain/SelectionHistory.js.map +1 -1
  261. package/dist/domain/SendBus.d.ts +0 -1
  262. package/dist/domain/SendBus.d.ts.map +1 -1
  263. package/dist/domain/SendBus.js +0 -1
  264. package/dist/domain/SendBus.js.map +1 -1
  265. package/dist/domain/SidechainConfig.d.ts +0 -1
  266. package/dist/domain/SidechainConfig.d.ts.map +1 -1
  267. package/dist/domain/SidechainConfig.js +0 -1
  268. package/dist/domain/SidechainConfig.js.map +1 -1
  269. package/dist/domain/Take.d.ts +0 -1
  270. package/dist/domain/Take.d.ts.map +1 -1
  271. package/dist/domain/Take.js +0 -1
  272. package/dist/domain/Take.js.map +1 -1
  273. package/dist/domain/ThawList.d.ts +0 -1
  274. package/dist/domain/ThawList.d.ts.map +1 -1
  275. package/dist/domain/ThawList.js +0 -1
  276. package/dist/domain/ThawList.js.map +1 -1
  277. package/dist/domain/TrackGroup.d.ts +0 -1
  278. package/dist/domain/TrackGroup.d.ts.map +1 -1
  279. package/dist/domain/TrackGroup.js +0 -1
  280. package/dist/domain/TrackGroup.js.map +1 -1
  281. package/dist/domain/TransportFSM.d.ts +0 -1
  282. package/dist/domain/TransportFSM.d.ts.map +1 -1
  283. package/dist/domain/TransportFSM.js +0 -1
  284. package/dist/domain/TransportFSM.js.map +1 -1
  285. package/dist/domain/TransportMode.d.ts +0 -1
  286. package/dist/domain/TransportMode.d.ts.map +1 -1
  287. package/dist/domain/TransportMode.js +0 -1
  288. package/dist/domain/TransportMode.js.map +1 -1
  289. package/dist/domain/TriggerBox.d.ts +0 -2
  290. package/dist/domain/TriggerBox.d.ts.map +1 -1
  291. package/dist/domain/TriggerBox.js +0 -2
  292. package/dist/domain/TriggerBox.js.map +1 -1
  293. package/dist/domain/VCATrack.d.ts +0 -2
  294. package/dist/domain/VCATrack.d.ts.map +1 -1
  295. package/dist/domain/VCATrack.js +0 -2
  296. package/dist/domain/VCATrack.js.map +1 -1
  297. package/dist/domain/VideoExportConfig.d.ts +0 -1
  298. package/dist/domain/VideoExportConfig.d.ts.map +1 -1
  299. package/dist/domain/VideoExportConfig.js +0 -1
  300. package/dist/domain/VideoExportConfig.js.map +1 -1
  301. package/dist/domain/ZoomFocus.d.ts +0 -1
  302. package/dist/domain/ZoomFocus.d.ts.map +1 -1
  303. package/dist/domain/ZoomFocus.js +0 -1
  304. package/dist/domain/ZoomFocus.js.map +1 -1
  305. package/dist/domain/temporal/TempoMap.d.ts +3 -4
  306. package/dist/domain/temporal/TempoMap.d.ts.map +1 -1
  307. package/dist/domain/temporal/TempoMap.js +2 -2
  308. package/dist/domain/temporal/TempoMap.js.map +1 -1
  309. package/dist/domain/temporal/types.d.ts +1 -1
  310. package/dist/domain/temporal/types.d.ts.map +1 -1
  311. package/dist/domain/temporal/types.js +1 -1
  312. package/dist/domain/temporal/types.js.map +1 -1
  313. package/dist/lib/Signal.d.ts +1 -1
  314. package/dist/lib/ThawList.d.ts +1 -3
  315. package/dist/lib/ThawList.d.ts.map +1 -1
  316. package/dist/lib/ThawList.js +1 -3
  317. package/dist/lib/ThawList.js.map +1 -1
  318. package/dist/midi/MidiFileParser.d.ts +0 -1
  319. package/dist/midi/MidiFileParser.d.ts.map +1 -1
  320. package/dist/midi/MidiFileParser.js +0 -1
  321. package/dist/midi/MidiFileParser.js.map +1 -1
  322. package/dist/midi/MidiFileWriter.d.ts +0 -1
  323. package/dist/midi/MidiFileWriter.d.ts.map +1 -1
  324. package/dist/midi/MidiFileWriter.js +0 -1
  325. package/dist/midi/MidiFileWriter.js.map +1 -1
  326. package/dist/plugins/PluginManager.js +2 -2
  327. package/dist/plugins/PluginManager.js.map +1 -1
  328. package/dist/plugins/impl/ExpanderPlugin.d.ts +1 -1
  329. package/dist/plugins/impl/ExpanderPlugin.js +1 -1
  330. package/dist/plugins/impl/ParametricEQPlugin.d.ts +1 -1
  331. package/dist/plugins/impl/ParametricEQPlugin.js +1 -1
  332. package/dist/processing/InternalSend.d.ts +0 -2
  333. package/dist/processing/InternalSend.d.ts.map +1 -1
  334. package/dist/processing/InternalSend.js.map +1 -1
  335. package/dist/processing/MeterDSP.d.ts +0 -1
  336. package/dist/processing/MeterDSP.d.ts.map +1 -1
  337. package/dist/processing/MeterDSP.js +0 -1
  338. package/dist/processing/MeterDSP.js.map +1 -1
  339. package/dist/processing/MeterProcessor.d.ts +0 -1
  340. package/dist/processing/MeterProcessor.d.ts.map +1 -1
  341. package/dist/processing/MeterProcessor.js +0 -1
  342. package/dist/processing/MeterProcessor.js.map +1 -1
  343. package/dist/processing/Panner.d.ts +1 -2
  344. package/dist/processing/Panner.d.ts.map +1 -1
  345. package/dist/processing/Panner.js +1 -2
  346. package/dist/processing/Panner.js.map +1 -1
  347. package/dist/processing/PolarityProcessor.d.ts +1 -1
  348. package/dist/processing/PolarityProcessor.js +1 -1
  349. package/dist/processing/SendProcessor.d.ts +0 -1
  350. package/dist/processing/SendProcessor.d.ts.map +1 -1
  351. package/dist/processing/SendProcessor.js +0 -1
  352. package/dist/processing/SendProcessor.js.map +1 -1
  353. package/dist/processing/SurroundPanner.d.ts +0 -2
  354. package/dist/processing/SurroundPanner.d.ts.map +1 -1
  355. package/dist/processing/SurroundPanner.js +0 -2
  356. package/dist/processing/SurroundPanner.js.map +1 -1
  357. package/dist/processing/TruePeakLimiter.d.ts +0 -2
  358. package/dist/processing/TruePeakLimiter.d.ts.map +1 -1
  359. package/dist/processing/TruePeakLimiter.js +0 -2
  360. package/dist/processing/TruePeakLimiter.js.map +1 -1
  361. package/dist/storage/SessionStorage.d.ts +1 -1
  362. package/dist/utils/BwfMetadataWriter.d.ts +0 -1
  363. package/dist/utils/BwfMetadataWriter.d.ts.map +1 -1
  364. package/dist/utils/BwfMetadataWriter.js +0 -1
  365. package/dist/utils/BwfMetadataWriter.js.map +1 -1
  366. package/dist/utils/DitherProcessor.d.ts +0 -1
  367. package/dist/utils/DitherProcessor.d.ts.map +1 -1
  368. package/dist/utils/DitherProcessor.js +0 -1
  369. package/dist/utils/DitherProcessor.js.map +1 -1
  370. package/dist/utils/FilenameTemplate.d.ts +0 -1
  371. package/dist/utils/FilenameTemplate.d.ts.map +1 -1
  372. package/dist/utils/FilenameTemplate.js +0 -1
  373. package/dist/utils/FilenameTemplate.js.map +1 -1
  374. package/dist/utils/FlacEncoder.d.ts +0 -1
  375. package/dist/utils/FlacEncoder.d.ts.map +1 -1
  376. package/dist/utils/FlacEncoder.js +0 -1
  377. package/dist/utils/FlacEncoder.js.map +1 -1
  378. package/dist/utils/Mp4ChapterGenerator.d.ts +0 -1
  379. package/dist/utils/Mp4ChapterGenerator.d.ts.map +1 -1
  380. package/dist/utils/Mp4ChapterGenerator.js +0 -1
  381. package/dist/utils/Mp4ChapterGenerator.js.map +1 -1
  382. package/dist/utils/OggEncoder.d.ts +0 -2
  383. package/dist/utils/OggEncoder.d.ts.map +1 -1
  384. package/dist/utils/OggEncoder.js +0 -2
  385. package/dist/utils/OggEncoder.js.map +1 -1
  386. package/dist/utils/TocGenerator.d.ts +0 -1
  387. package/dist/utils/TocGenerator.d.ts.map +1 -1
  388. package/dist/utils/TocGenerator.js +0 -1
  389. package/dist/utils/TocGenerator.js.map +1 -1
  390. package/package.json +7 -7
package/README.md CHANGED
@@ -1,734 +1,734 @@
1
- # drop-daw
2
-
3
- Headless DAW (Digital Audio Workstation) engine for TypeScript/JavaScript. Provides domain models, command system, audio engine, automation, plugins, and MIDI — all with zero browser or framework dependencies.
4
-
5
- ```bash
6
- npm install drop-daw
7
- ```
8
-
9
- ## Features
10
-
11
- - **Headless** — No browser, no React, no framework required. Runs in Node.js, Electron, or any JS runtime.
12
- - **Command Pattern** — All mutations go through `CommandExecutor` with built-in Undo/Redo.
13
- - **Dependency Injection** — Bring your own audio backend via the `AudioProvider` interface.
14
- - **60+ Commands** — Transport, tracks, regions, automation, plugins, MIDI, markers, ranges, export.
15
- - **20+ Built-in Plugins** — EQ, compressor, reverb, delay, saturation, de-esser, and more.
16
- - **Signal-based Events** — Type-safe reactive event system (Qt Signal/Slot pattern).
17
- - **Serialization** — Full session save/load with JSON snapshots.
18
- - **TypeScript-first** — Complete type definitions included.
19
-
20
- ---
21
-
22
- ## Quick Start
23
-
24
- ```typescript
25
- import {
26
- AudioEngine,
27
- Session,
28
- Track,
29
- TrackType,
30
- CommandExecutor,
31
- CommandType,
32
- } from 'drop-daw';
33
-
34
- // 1. Implement AudioProvider interface for your platform
35
- class MyAudioBackend implements AudioProvider {
36
- // ... implement the interface methods
37
- }
38
-
39
- // 2. Initialize the engine with your backend
40
- const engine = AudioEngine.getInstance(new MyAudioBackend());
41
-
42
- // 3. Work with the session directly
43
- const track = engine.session.addTrack('Vocals', TrackType.AUDIO);
44
-
45
- // 4. Or use the command system (with undo/redo support)
46
- await CommandExecutor.getInstance().execute({
47
- type: CommandType.ADD_TRACK,
48
- payload: { name: 'Guitar', trackType: 'audio' },
49
- });
50
- ```
51
-
52
- ---
53
-
54
- ## Architecture
55
-
56
- ```
57
- ┌──────────────────────────────────────────────────┐
58
- │ Your App │
59
- │ (React, Electron, Node.js CLI, etc.) │
60
- │ │
61
- │ ┌─────────────┐ ┌────────────────────────────┐ │
62
- │ │ UI Layer │ │ AudioProvider (impl) │ │
63
- │ │ (optional) │ │ e.g. Web Audio, PortAudio │ │
64
- │ └──────┬──────┘ └─────────────┬──────────────┘ │
65
- ├─────────┼───────────────────────┼────────────────┤
66
- │ ▼ ▼ │
67
- │ ┌─────────────┐ ┌────────────────────────────┐ │
68
- │ │ Command │ │ AudioEngine │ │
69
- │ │ Executor │ │ (session + backend) │ │
70
- │ └──────┬──────┘ └────────────────────────────┘ │
71
- │ ▼ │
72
- │ ┌───────────────────────────────────────┐ │
73
- │ │ Domain Layer │ │
74
- │ │ Session → Track → Playlist → Region │ │
75
- │ │ Automation, Plugins, MIDI, Markers │ │
76
- │ └───────────────────────────────────────┘ │
77
- │ │
78
- │ drop-daw
79
- └──────────────────────────────────────────────────┘
80
- ```
81
-
82
- ---
83
-
84
- ## Core Concepts
85
-
86
- ### Session
87
-
88
- The root container for a DAW project. Manages tracks, sources, markers, ranges, tempo, and transport state.
89
-
90
- ```typescript
91
- import { Session, TrackType } from 'drop-daw';
92
-
93
- const session = new Session('My Song', undefined, 44100);
94
-
95
- // Tracks
96
- const vocal = session.addTrack('Vocals', TrackType.AUDIO);
97
- const bass = session.addTrack('Bass', TrackType.AUDIO);
98
- const synth = session.addTrack('Synth', TrackType.MIDI);
99
- const reverb = session.addAuxTrack('Reverb Bus');
100
-
101
- // Transport
102
- session.setTempo(120);
103
- session.setTimeSignature(4, 4);
104
-
105
- // Markers
106
- session.addMarker('Chorus', 44100 * 30); // at 30 seconds
107
-
108
- // Ranges
109
- const loopRange = session.addRange('Loop A', 44100 * 10, 44100 * 20);
110
- session.setLoopRange(loopRange.id);
111
- session.setLoopEnabled(true);
112
-
113
- // Serialization
114
- const snapshot = session.toJSON();
115
- const restored = Session.fromJSON(snapshot);
116
- ```
117
-
118
- ### Track
119
-
120
- Represents an audio, MIDI, aux, bus, folder, or VCA track. Each track has a `Route` (signal chain) and a `Playlist` (region container).
121
-
122
- ```typescript
123
- const track = session.addTrack('Lead Guitar', TrackType.AUDIO);
124
-
125
- track.setMute(false);
126
- track.setSolo(true);
127
- track.setArmed(true);
128
- track.setColor('#ff6b6b');
129
- track.setMonitorMode(MonitorMode.AUTO);
130
-
131
- // React to changes
132
- track.muteChanged.connect((muted) => console.log('Mute:', muted));
133
- track.soloChanged.connect((soloed) => console.log('Solo:', soloed));
134
- ```
135
-
136
- **Track Types:**
137
-
138
- | Type | Description |
139
- |------|-------------|
140
- | `AUDIO` | Standard audio track with region playback |
141
- | `MIDI` | MIDI track with note data and virtual instruments |
142
- | `AUX` | Auxiliary bus for send effects (reverb, delay) |
143
- | `BUS` | Mix bus for subgroup routing |
144
- | `FOLDER` | Folder track for organizing child tracks |
145
- | `VCA` | VCA fader for linked level control |
146
-
147
- ### Region
148
-
149
- A segment of audio on the timeline, referencing a `Source`.
150
-
151
- ```typescript
152
- import { Region } from 'drop-daw';
153
-
154
- const region = new Region(
155
- 'region-1', // id
156
- 'source-1', // sourceId
157
- 0, // start (frames)
158
- 44100 * 10, // length (10 seconds at 44.1kHz)
159
- 0, // sourceStart
160
- 'Vocal Take 1' // name
161
- );
162
-
163
- region.setFadeIn(4410); // 100ms fade in
164
- region.setFadeOut(4410); // 100ms fade out
165
- region.move(44100 * 5); // move to 5 seconds
166
- region.resize(44100 * 8); // resize to 8 seconds
167
- ```
168
-
169
- ### AudioEngine
170
-
171
- Central controller connecting the session to an audio backend. Uses the singleton pattern with dependency injection.
172
-
173
- ```typescript
174
- import { AudioEngine, AudioProvider } from 'drop-daw';
175
-
176
- // Initialize with your backend implementation
177
- const engine = AudioEngine.getInstance(myBackend);
178
- await engine.initialize();
179
-
180
- // Transport
181
- await engine.start();
182
- engine.pause();
183
- engine.seek(10.5); // seek to 10.5 seconds
184
- engine.stop();
185
-
186
- // Metering
187
- const meter = engine.getMeterData('track-1');
188
- console.log('Peak:', meter.peak, 'RMS:', meter.rms);
189
-
190
- // Export
191
- await engine.exportAudio(engine.getExportConfig(), engine.getExportStatus());
192
-
193
- // Swap backend at runtime
194
- engine.setBackend(new DifferentBackend());
195
- ```
196
-
197
- ### AudioProvider Interface
198
-
199
- Implement this interface to connect drop-daw to any audio system.
200
-
201
- ```typescript
202
- import { AudioProvider } from 'drop-daw';
203
-
204
- class WebAudioBackend implements AudioProvider {
205
- async initialize(): Promise<void> { /* ... */ }
206
-
207
- // Transport
208
- start(): void { /* ... */ }
209
- stop(): void { /* ... */ }
210
- pause(): void { /* ... */ }
211
- seek(time: number): void { /* ... */ }
212
-
213
- // Track management
214
- createTrack(trackId, name, inputId, outputId): void { /* ... */ }
215
- deleteTrack(trackId): void { /* ... */ }
216
-
217
- // Region scheduling
218
- scheduleRegion(trackId, region): void { /* ... */ }
219
- updateRegions(trackId, regions): void { /* ... */ }
220
- removeRegion(trackId, regionId): void { /* ... */ }
221
-
222
- // Metering
223
- getMeterData(trackId): MeterData { /* ... */ }
224
- getMasterMeterData(): MeterData { /* ... */ }
225
-
226
- // ... and more (see full interface in source)
227
- }
228
- ```
229
-
230
- **Included backend examples (in the drop.ai app, not in this package):**
231
-
232
- | Backend | Environment | Description |
233
- |---------|-------------|-------------|
234
- | `ToneAudioProvider` | Browser | Tone.js + Web Audio API |
235
- | `HeadlessAudioProvider` | Node.js | No-op backend for CLI/testing |
236
- | `MockAudioProvider` | Test | Mock backend for unit tests |
237
-
238
- ---
239
-
240
- ## Command System
241
-
242
- All state mutations can go through the command system, providing validation (via Zod), handler routing, and undo/redo support.
243
-
244
- ### Executing Commands
245
-
246
- ```typescript
247
- import { CommandExecutor, CommandType } from 'drop-daw';
248
-
249
- const executor = CommandExecutor.getInstance();
250
-
251
- // Add a track
252
- await executor.execute({
253
- type: CommandType.ADD_TRACK,
254
- payload: { name: 'Vocals', trackType: 'audio' },
255
- });
256
-
257
- // Set volume
258
- await executor.execute({
259
- type: CommandType.SET_VOLUME,
260
- payload: { trackId: 'track-1', volume: 0.75 },
261
- });
262
-
263
- // Split region at playhead
264
- await executor.execute({
265
- type: CommandType.SPLIT_AT_PLAYHEAD,
266
- payload: { trackId: 'track-1', frame: 44100 * 15 },
267
- });
268
-
269
- // Add a plugin
270
- await executor.execute({
271
- type: CommandType.ADD_PLUGIN,
272
- payload: { trackId: 'track-1', pluginId: 'internal-eq6' },
273
- });
274
- ```
275
-
276
- ### Undo / Redo
277
-
278
- ```typescript
279
- const history = executor.history;
280
-
281
- await history.undo();
282
- await history.redo();
283
- await history.undoMultiple(3); // undo 3 steps
284
-
285
- console.log(history.canUndo); // true
286
- console.log(history.nextUndoLabel); // "Add Track"
287
-
288
- // Transaction: group multiple commands into one undo step
289
- history.beginTransaction('Move and resize');
290
- // ... execute multiple commands ...
291
- await history.commitTransaction();
292
- ```
293
-
294
- ### Registering Custom Handlers
295
-
296
- ```typescript
297
- import { CommandHandler, CommandResult } from 'drop-daw';
298
-
299
- class MyCustomHandler implements CommandHandler {
300
- readonly handledTypes = ['MY_CUSTOM_COMMAND'];
301
-
302
- async execute(type: string, payload: any): Promise<CommandResult> {
303
- // your logic here
304
- return { success: true };
305
- }
306
- }
307
-
308
- CommandExecutor.getInstance().registerHandler(new MyCustomHandler());
309
- ```
310
-
311
- ### Command Types
312
-
313
- **Transport:** `PLAY`, `PAUSE`, `STOP`, `SEEK`, `SET_TEMPO`, `SET_TIME_SIGNATURE`, `TOGGLE_METRONOME`, `START_RECORDING`, `STOP_RECORDING`
314
-
315
- **Tracks:** `ADD_TRACK`, `REMOVE_TRACK`, `SET_VOLUME`, `SET_PAN`, `MUTE_TRACK`, `SOLO_TRACK`, `ARM_TRACK`, `SET_TRACK_MONITOR`
316
-
317
- **Regions:** `ADD_REGION`, `REMOVE_REGION`, `MOVE_REGION`, `RESIZE_REGION`, `SPLIT_AT_PLAYHEAD`, `DUPLICATE_REGION`, `COPY_REGION`, `PASTE_REGION`, `MERGE_REGIONS`, `TRIM_REGION`, `SET_REGION_FADES`, `REVERSE_REGION`, `NORMALIZE_REGION`, `STRIP_SILENCE`, `TIME_STRETCH_REGION`, `LOCK_REGION`, `GROUP_REGIONS`, `UNGROUP_REGIONS`
318
-
319
- **Automation:** `ADD_AUTOMATION`, `MOVE_AUTOMATION_POINT`, `REMOVE_AUTOMATION_POINT`
320
-
321
- **Plugins:** `ADD_PLUGIN`, `REMOVE_PLUGIN`, `SET_PLUGIN_PARAMETER`
322
-
323
- **Ranges:** `ADD_RANGE`, `REMOVE_RANGE`, `SET_RANGE`, `SET_LOOP_RANGE`, `SET_PUNCH_RANGE`, `TOGGLE_LOOP`
324
-
325
- **Markers:** `ADD_MARKER`, `REMOVE_MARKER`, `MOVE_MARKER`
326
-
327
- **IO/Routing:** `CONNECT_IO`, `DISCONNECT_IO`, `ADD_SEND_BUS`, `REMOVE_SEND_BUS`, `SET_SEND_LEVEL`
328
-
329
- **Session:** `EXPORT`, `NEW_SESSION`, `LOAD_SESSION`, `SAVE_SESSION`, `SAVE_SNAPSHOT`
330
-
331
- **History:** `UNDO`, `REDO`, `SELECTION_UNDO`, `SELECTION_REDO`
332
-
333
- ---
334
-
335
- ## Plugins
336
-
337
- 20+ built-in audio effect plugins, managed by `PluginManager`.
338
-
339
- ```typescript
340
- import { PluginManager } from 'drop-daw';
341
-
342
- const manager = PluginManager.getInstance();
343
-
344
- // List all available plugins
345
- const plugins = manager.getAvailablePlugins();
346
- plugins.forEach(p => console.log(p.id, p.name));
347
-
348
- // Create a plugin instance
349
- const eq = manager.createPlugin('internal-eq6');
350
- eq.setParameter('band1-freq', 100);
351
- eq.setParameter('band1-gain', 3.0);
352
-
353
- // Get/set full state (presets)
354
- const state = eq.getState();
355
- eq.setState(state);
356
-
357
- // React to parameter changes
358
- eq.parameterChanged.connect(({ id, value }) => {
359
- console.log(`${id} changed to ${value}`);
360
- });
361
- ```
362
-
363
- ### Available Plugins
364
-
365
- | ID | Name | Description |
366
- |----|------|-------------|
367
- | `internal-eq6` | Parametric EQ | 6-band parametric equalizer |
368
- | `internal-compressor` | Compressor | Dynamics compressor |
369
- | `internal-multiband-comp` | Multiband Compressor | Multi-band dynamics |
370
- | `internal-expander` | Expander | Expander/gate |
371
- | `internal-gate` | Gate | Noise gate |
372
- | `internal-deesser` | De-Esser | Sibilance reduction |
373
- | `internal-reverb` | Reverb | Algorithmic reverb |
374
- | `internal-convolver` | Convolution Reverb | IR-based reverb |
375
- | `internal-delay` | Delay | Simple delay |
376
- | `internal-sync-delay` | Sync Delay | BPM-synced delay |
377
- | `internal-chorus` | Chorus | Chorus effect |
378
- | `internal-phaser` | Phaser | Phaser effect |
379
- | `internal-tremolo` | Tremolo | Tremolo effect |
380
- | `internal-vibrato` | Vibrato | Vibrato effect |
381
- | `internal-autopan` | Auto Pan | Automatic panning |
382
- | `internal-distortion` | Distortion | Distortion/overdrive |
383
- | `internal-tape-sat` | Tape Saturation | Analog tape emulation |
384
- | `internal-filter` | Filter | Multi-mode filter |
385
- | `internal-eq3` | 3-Band EQ | Simple 3-band EQ |
386
- | `internal-gain` | Gain | Utility gain |
387
-
388
- ---
389
-
390
- ## Automation
391
-
392
- Per-parameter automation with multiple recording modes.
393
-
394
- ```typescript
395
- import { AutomationList, AutomationMode } from 'drop-daw';
396
-
397
- const automation = new AutomationList();
398
-
399
- // Add points
400
- automation.addPoint(0, 0.5); // value 0.5 at time 0
401
- automation.addPoint(2.0, 1.0); // value 1.0 at time 2s
402
- automation.addPoint(4.0, 0.0); // value 0.0 at time 4s
403
-
404
- // Read interpolated value
405
- const value = automation.getValueAt(1.0); // ~0.75 (linear interpolation)
406
-
407
- // Modes
408
- automation.mode = AutomationMode.READ; // playback only
409
- automation.mode = AutomationMode.WRITE; // overwrite
410
- automation.mode = AutomationMode.TOUCH; // write while touching, snap back on release
411
- automation.mode = AutomationMode.LATCH; // write while touching, hold last value
412
-
413
- // Range operations
414
- const copied = automation.copy(1.0, 3.0);
415
- automation.paste(copied, 5.0);
416
- automation.eraseRange(1.0, 3.0);
417
- ```
418
-
419
- ---
420
-
421
- ## Signal (Event System)
422
-
423
- Type-safe event emitter inspired by Qt's Signal/Slot pattern. Used throughout the domain layer.
424
-
425
- ```typescript
426
- import { Signal } from 'drop-daw';
427
-
428
- const signal = new Signal<number>();
429
-
430
- // Subscribe
431
- const sub = signal.connect((value) => {
432
- console.log('Received:', value);
433
- });
434
-
435
- // Emit
436
- signal.emit(42); // logs "Received: 42"
437
-
438
- // Unsubscribe
439
- sub.dispose();
440
-
441
- // Or disconnect by reference
442
- const handler = (v: number) => console.log(v);
443
- signal.connect(handler);
444
- signal.disconnect(handler);
445
-
446
- // Clear all listeners
447
- signal.clear();
448
- ```
449
-
450
- ### Common Signals
451
-
452
- ```typescript
453
- // Session
454
- session.trackAdded.connect((track) => { /* ... */ });
455
- session.trackRemoved.connect((trackId) => { /* ... */ });
456
- session.tempoChanged.connect((bpm) => { /* ... */ });
457
- session.playingChanged.connect((isPlaying) => { /* ... */ });
458
- session.selectionChanged.connect((selectedIds) => { /* ... */ });
459
- session.markerAdded.connect((marker) => { /* ... */ });
460
-
461
- // Track
462
- track.muteChanged.connect((muted) => { /* ... */ });
463
- track.soloChanged.connect((soloed) => { /* ... */ });
464
- track.armChanged.connect((armed) => { /* ... */ });
465
-
466
- // CommandExecutor
467
- executor.commandExecuted.connect(({ type, payload }) => { /* ... */ });
468
-
469
- // CommandHistory
470
- history.historyChanged.connect(() => { /* ... */ });
471
- ```
472
-
473
- ---
474
-
475
- ## Actions & Key Bindings
476
-
477
- Map keyboard shortcuts to commands.
478
-
479
- ```typescript
480
- import { ActionRegistry, ActionCategory } from 'drop-daw';
481
-
482
- const registry = ActionRegistry.getInstance();
483
-
484
- // Register default actions (typically done at app bootstrap)
485
- registry.registerDefaults([
486
- {
487
- id: 'transport.play',
488
- label: 'Play/Pause',
489
- category: ActionCategory.TRANSPORT,
490
- defaultKey: 'Space',
491
- commandFactory: () => ({ type: CommandType.PLAY, payload: {} }),
492
- },
493
- {
494
- id: 'edit.undo',
495
- label: 'Undo',
496
- category: ActionCategory.EDIT,
497
- defaultKey: 'Ctrl+Z',
498
- commandFactory: () => ({ type: CommandType.UNDO, payload: {} }),
499
- },
500
- ]);
501
-
502
- // Execute by action ID
503
- await registry.execute('transport.play');
504
-
505
- // Query
506
- const actions = registry.getActionsByCategory();
507
- const key = registry.getEffectiveKey('transport.play'); // 'Space'
508
- ```
509
-
510
- ### Custom Key Bindings
511
-
512
- ```typescript
513
- import { KeyBindings } from 'drop-daw';
514
-
515
- const bindings = KeyBindings.getInstance();
516
-
517
- bindings.setBinding('transport.play', 'Enter');
518
- bindings.getBinding('transport.play'); // 'Enter'
519
- bindings.removeBinding('transport.play'); // back to default
520
- bindings.resetToDefaults();
521
- ```
522
-
523
- ---
524
-
525
- ## Preferences
526
-
527
- Persistent settings with defaults.
528
-
529
- ```typescript
530
- import { Preferences } from 'drop-daw';
531
-
532
- const prefs = Preferences.getInstance();
533
-
534
- prefs.set('sampleRate', 48000);
535
- prefs.set('audioBufferSize', 256);
536
- prefs.set('theme', 'dark');
537
- prefs.set('snapToGrid', true);
538
- prefs.set('historyDepth', 100);
539
-
540
- const sr = prefs.get('sampleRate'); // 48000
541
-
542
- // React to changes
543
- prefs.preferenceChanged.connect(() => {
544
- console.log('Settings updated');
545
- });
546
-
547
- // Reset
548
- prefs.resetToDefaults();
549
- ```
550
-
551
- **Available Keys:** `audioBufferSize`, `sampleRate`, `theme`, `autoSaveInterval`, `snapToGrid`, `gridSubdivision`, `meterType`, `showMinimap`, `followPlayhead`, `countInBars`, `historyDepth`, `saveHistory`, `saveHistoryDepth`
552
-
553
- ---
554
-
555
- ## Storage
556
-
557
- Session persistence via IndexedDB (browser) or localStorage fallback.
558
-
559
- ```typescript
560
- import { SessionStorage } from 'drop-daw';
561
-
562
- const storage = SessionStorage.getInstance();
563
-
564
- // Save
565
- await storage.saveSession(session);
566
-
567
- // List
568
- const sessions = await storage.listSessions();
569
- // [{ id: '...', name: 'My Song', modified: Date }]
570
-
571
- // Load
572
- const snapshot = await storage.loadSession(sessions[0].id);
573
- const restored = Session.fromJSON(snapshot);
574
-
575
- // Snapshots (named save points)
576
- const snapId = await storage.saveSnapshot(session.id, 'Before mixing', session.toJSON());
577
- const snap = await storage.loadSnapshot(snapId);
578
-
579
- // Delete
580
- await storage.deleteSession(session.id);
581
- ```
582
-
583
- ---
584
-
585
- ## Processing Chain
586
-
587
- Each track has a `Route` containing an ordered chain of processors.
588
-
589
- ```typescript
590
- import {
591
- GainProcessor,
592
- PanProcessor,
593
- PluginInsert,
594
- SendProcessor,
595
- MeterProcessor,
596
- } from 'drop-daw';
597
-
598
- // Processor types available in the chain:
599
- // GainProcessor — Fader / Trim level control
600
- // PanProcessor — Stereo panning and width
601
- // PluginInsert — Plugin effect slot
602
- // SendProcessor — Pre/Post fader send to aux bus
603
- // MeterProcessor — Peak/RMS metering
604
- ```
605
-
606
- ---
607
-
608
- ## Usage Examples
609
-
610
- ### Node.js CLI
611
-
612
- ```typescript
613
- import { AudioEngine, Session, CommandExecutor, CommandType } from 'drop-daw';
614
-
615
- // Headless backend (no audio output)
616
- class HeadlessBackend implements AudioProvider {
617
- async initialize() {}
618
- start() {}
619
- stop() {}
620
- // ... no-op implementations
621
- }
622
-
623
- const engine = AudioEngine.getInstance(new HeadlessBackend());
624
- const session = engine.session;
625
-
626
- session.addTrack('Track 1', TrackType.AUDIO);
627
- console.log('Tracks:', session.tracks.map(t => t.name));
628
-
629
- const snapshot = session.toJSON();
630
- // Save to file, process offline, etc.
631
- ```
632
-
633
- ### Electron App
634
-
635
- ```typescript
636
- import { AudioEngine, AudioProvider } from 'drop-daw';
637
-
638
- class ElectronAudioBackend implements AudioProvider {
639
- // Use PortAudio or native audio APIs
640
- // ...
641
- }
642
-
643
- const engine = AudioEngine.getInstance(new ElectronAudioBackend());
644
- await engine.initialize();
645
- ```
646
-
647
- ### React Integration
648
-
649
- ```typescript
650
- import { useEffect, useState } from 'react';
651
- import { AudioEngine, Session } from 'drop-daw';
652
-
653
- function useDAWEngine(backend: AudioProvider) {
654
- const [engine] = useState(() => AudioEngine.getInstance(backend));
655
-
656
- useEffect(() => {
657
- const sub = engine.session.tempoChanged.connect((bpm) => {
658
- // update React state
659
- });
660
- return () => sub.dispose();
661
- }, [engine]);
662
-
663
- return engine;
664
- }
665
- ```
666
-
667
- ---
668
-
669
- ## API Reference
670
-
671
- ### Singletons
672
-
673
- | Class | Access | Description |
674
- |-------|--------|-------------|
675
- | `AudioEngine` | `getInstance(backend?)` | Audio engine with session and transport |
676
- | `CommandExecutor` | `getInstance()` | Command dispatch with validation |
677
- | `PluginManager` | `getInstance()` | Plugin factory |
678
- | `ActionRegistry` | `getInstance()` | Keyboard shortcut ↔ command mapping |
679
- | `Preferences` | `getInstance()` | User settings |
680
- | `KeyBindings` | `getInstance()` | Custom key binding overrides |
681
- | `SessionStorage` | `getInstance()` | Session persistence |
682
-
683
- ### Domain Models
684
-
685
- | Class | Description |
686
- |-------|-------------|
687
- | `Session` | Project root — tracks, sources, markers, ranges, tempo |
688
- | `Track` | Audio/MIDI/AUX/BUS/FOLDER/VCA track |
689
- | `Region` | Audio segment on the timeline |
690
- | `Playlist` | Region collection within a track |
691
- | `Source` | Audio file reference (URL, duration, sampleRate) |
692
- | `Range` | Loop/punch/selection range |
693
- | `Marker` | Timeline marker (position + name) |
694
- | `MidiNote` | Single MIDI note event |
695
- | `MidiRegion` | MIDI note collection on the timeline |
696
- | `SendBus` | Pre/post fader send bus |
697
- | `Route` | Signal chain (input → processors → output) |
698
- | `TempoMap` | BPM change events over time |
699
- | `GridSettings` | Grid type and snap mode |
700
- | `CrossfadeEngine` | Automatic crossfade calculation |
701
- | `MixerScene` | Mixer snapshot save/restore |
702
- | `TrackGroup` | Track grouping for linked control |
703
-
704
- ### Type Definitions
705
-
706
- ```typescript
707
- type FrameCount = number // sample frame position
708
- type SampleRate = number // e.g. 44100, 48000, 96000
709
- type Gain = number // 0.0 to 1.0+
710
- type DB = number // decibels
711
-
712
- type TrackId = string
713
- type RegionId = string
714
- type SourceId = string
715
- type RangeId = string
716
- type ProcessorId = string
717
- type RouteId = string
718
- ```
719
-
720
- ---
721
-
722
- ## Dependencies
723
-
724
- | Package | Type | Description |
725
- |---------|------|-------------|
726
- | `zod` | runtime | Command payload validation |
727
- | `lamejs` | peer (optional) | MP3 export support |
728
- | `soundtouchjs` | peer (optional) | Time-stretch / pitch-shift |
729
-
730
- ---
731
-
732
- ## License
733
-
734
- MIT
1
+ # @drop-ai/core
2
+
3
+ Headless DAW (Digital Audio Workstation) engine for TypeScript/JavaScript. Provides domain models, command system, audio engine, automation, plugins, and MIDI — all with zero browser or framework dependencies.
4
+
5
+ ```bash
6
+ npm install @drop-ai/core
7
+ ```
8
+
9
+ ## Features
10
+
11
+ - **Headless** — No browser, no React, no framework required. Runs in Node.js, Electron, or any JS runtime.
12
+ - **Command Pattern** — All mutations go through `CommandExecutor` with built-in Undo/Redo.
13
+ - **Dependency Injection** — Bring your own audio backend via the `AudioProvider` interface.
14
+ - **60+ Commands** — Transport, tracks, regions, automation, plugins, MIDI, markers, ranges, export.
15
+ - **20+ Built-in Plugins** — EQ, compressor, reverb, delay, saturation, de-esser, and more.
16
+ - **Signal-based Events** — Type-safe reactive event system (Qt Signal/Slot pattern).
17
+ - **Serialization** — Full session save/load with JSON snapshots.
18
+ - **TypeScript-first** — Complete type definitions included.
19
+
20
+ ---
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import {
26
+ AudioEngine,
27
+ Session,
28
+ Track,
29
+ TrackType,
30
+ CommandExecutor,
31
+ CommandType,
32
+ } from '@drop-ai/core';
33
+
34
+ // 1. Implement AudioProvider interface for your platform
35
+ class MyAudioBackend implements AudioProvider {
36
+ // ... implement the interface methods
37
+ }
38
+
39
+ // 2. Initialize the engine with your backend
40
+ const engine = AudioEngine.getInstance(new MyAudioBackend());
41
+
42
+ // 3. Work with the session directly
43
+ const track = engine.session.addTrack('Vocals', TrackType.AUDIO);
44
+
45
+ // 4. Or use the command system (with undo/redo support)
46
+ await CommandExecutor.getInstance().execute({
47
+ type: CommandType.ADD_TRACK,
48
+ payload: { name: 'Guitar', trackType: 'audio' },
49
+ });
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Architecture
55
+
56
+ ```
57
+ ┌──────────────────────────────────────────────────┐
58
+ │ Your App │
59
+ │ (React, Electron, Node.js CLI, etc.) │
60
+ │ │
61
+ │ ┌─────────────┐ ┌────────────────────────────┐ │
62
+ │ │ UI Layer │ │ AudioProvider (impl) │ │
63
+ │ │ (optional) │ │ e.g. Web Audio, PortAudio │ │
64
+ │ └──────┬──────┘ └─────────────┬──────────────┘ │
65
+ ├─────────┼───────────────────────┼────────────────┤
66
+ │ ▼ ▼ │
67
+ │ ┌─────────────┐ ┌────────────────────────────┐ │
68
+ │ │ Command │ │ AudioEngine │ │
69
+ │ │ Executor │ │ (session + backend) │ │
70
+ │ └──────┬──────┘ └────────────────────────────┘ │
71
+ │ ▼ │
72
+ │ ┌───────────────────────────────────────┐ │
73
+ │ │ Domain Layer │ │
74
+ │ │ Session → Track → Playlist → Region │ │
75
+ │ │ Automation, Plugins, MIDI, Markers │ │
76
+ │ └───────────────────────────────────────┘ │
77
+ │ │
78
+ @drop-ai/core
79
+ └──────────────────────────────────────────────────┘
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Core Concepts
85
+
86
+ ### Session
87
+
88
+ The root container for a DAW project. Manages tracks, sources, markers, ranges, tempo, and transport state.
89
+
90
+ ```typescript
91
+ import { Session, TrackType } from '@drop-ai/core';
92
+
93
+ const session = new Session('My Song', undefined, 44100);
94
+
95
+ // Tracks
96
+ const vocal = session.addTrack('Vocals', TrackType.AUDIO);
97
+ const bass = session.addTrack('Bass', TrackType.AUDIO);
98
+ const synth = session.addTrack('Synth', TrackType.MIDI);
99
+ const reverb = session.addAuxTrack('Reverb Bus');
100
+
101
+ // Transport
102
+ session.setTempo(120);
103
+ session.setTimeSignature(4, 4);
104
+
105
+ // Markers
106
+ session.addMarker('Chorus', 44100 * 30); // at 30 seconds
107
+
108
+ // Ranges
109
+ const loopRange = session.addRange('Loop A', 44100 * 10, 44100 * 20);
110
+ session.setLoopRange(loopRange.id);
111
+ session.setLoopEnabled(true);
112
+
113
+ // Serialization
114
+ const snapshot = session.toJSON();
115
+ const restored = Session.fromJSON(snapshot);
116
+ ```
117
+
118
+ ### Track
119
+
120
+ Represents an audio, MIDI, aux, bus, folder, or VCA track. Each track has a `Route` (signal chain) and a `Playlist` (region container).
121
+
122
+ ```typescript
123
+ const track = session.addTrack('Lead Guitar', TrackType.AUDIO);
124
+
125
+ track.setMute(false);
126
+ track.setSolo(true);
127
+ track.setArmed(true);
128
+ track.setColor('#ff6b6b');
129
+ track.setMonitorMode(MonitorMode.AUTO);
130
+
131
+ // React to changes
132
+ track.muteChanged.connect((muted) => console.log('Mute:', muted));
133
+ track.soloChanged.connect((soloed) => console.log('Solo:', soloed));
134
+ ```
135
+
136
+ **Track Types:**
137
+
138
+ | Type | Description |
139
+ |------|-------------|
140
+ | `AUDIO` | Standard audio track with region playback |
141
+ | `MIDI` | MIDI track with note data and virtual instruments |
142
+ | `AUX` | Auxiliary bus for send effects (reverb, delay) |
143
+ | `BUS` | Mix bus for subgroup routing |
144
+ | `FOLDER` | Folder track for organizing child tracks |
145
+ | `VCA` | VCA fader for linked level control |
146
+
147
+ ### Region
148
+
149
+ A segment of audio on the timeline, referencing a `Source`.
150
+
151
+ ```typescript
152
+ import { Region } from '@drop-ai/core';
153
+
154
+ const region = new Region(
155
+ 'region-1', // id
156
+ 'source-1', // sourceId
157
+ 0, // start (frames)
158
+ 44100 * 10, // length (10 seconds at 44.1kHz)
159
+ 0, // sourceStart
160
+ 'Vocal Take 1' // name
161
+ );
162
+
163
+ region.setFadeIn(4410); // 100ms fade in
164
+ region.setFadeOut(4410); // 100ms fade out
165
+ region.move(44100 * 5); // move to 5 seconds
166
+ region.resize(44100 * 8); // resize to 8 seconds
167
+ ```
168
+
169
+ ### AudioEngine
170
+
171
+ Central controller connecting the session to an audio backend. Uses the singleton pattern with dependency injection.
172
+
173
+ ```typescript
174
+ import { AudioEngine, AudioProvider } from '@drop-ai/core';
175
+
176
+ // Initialize with your backend implementation
177
+ const engine = AudioEngine.getInstance(myBackend);
178
+ await engine.initialize();
179
+
180
+ // Transport
181
+ await engine.start();
182
+ engine.pause();
183
+ engine.seek(10.5); // seek to 10.5 seconds
184
+ engine.stop();
185
+
186
+ // Metering
187
+ const meter = engine.getMeterData('track-1');
188
+ console.log('Peak:', meter.peak, 'RMS:', meter.rms);
189
+
190
+ // Export
191
+ await engine.exportAudio(engine.getExportConfig(), engine.getExportStatus());
192
+
193
+ // Swap backend at runtime
194
+ engine.setBackend(new DifferentBackend());
195
+ ```
196
+
197
+ ### AudioProvider Interface
198
+
199
+ Implement this interface to connect @drop-ai/core to any audio system.
200
+
201
+ ```typescript
202
+ import { AudioProvider } from '@drop-ai/core';
203
+
204
+ class WebAudioBackend implements AudioProvider {
205
+ async initialize(): Promise<void> { /* ... */ }
206
+
207
+ // Transport
208
+ start(): void { /* ... */ }
209
+ stop(): void { /* ... */ }
210
+ pause(): void { /* ... */ }
211
+ seek(time: number): void { /* ... */ }
212
+
213
+ // Track management
214
+ createTrack(trackId, name, inputId, outputId): void { /* ... */ }
215
+ deleteTrack(trackId): void { /* ... */ }
216
+
217
+ // Region scheduling
218
+ scheduleRegion(trackId, region): void { /* ... */ }
219
+ updateRegions(trackId, regions): void { /* ... */ }
220
+ removeRegion(trackId, regionId): void { /* ... */ }
221
+
222
+ // Metering
223
+ getMeterData(trackId): MeterData { /* ... */ }
224
+ getMasterMeterData(): MeterData { /* ... */ }
225
+
226
+ // ... and more (see full interface in source)
227
+ }
228
+ ```
229
+
230
+ **Included backend examples (in the drop.ai app, not in this package):**
231
+
232
+ | Backend | Environment | Description |
233
+ |---------|-------------|-------------|
234
+ | `ToneAudioProvider` | Browser | Tone.js + Web Audio API |
235
+ | `HeadlessAudioProvider` | Node.js | No-op backend for CLI/testing |
236
+ | `MockAudioProvider` | Test | Mock backend for unit tests |
237
+
238
+ ---
239
+
240
+ ## Command System
241
+
242
+ All state mutations can go through the command system, providing validation (via Zod), handler routing, and undo/redo support.
243
+
244
+ ### Executing Commands
245
+
246
+ ```typescript
247
+ import { CommandExecutor, CommandType } from '@drop-ai/core';
248
+
249
+ const executor = CommandExecutor.getInstance();
250
+
251
+ // Add a track
252
+ await executor.execute({
253
+ type: CommandType.ADD_TRACK,
254
+ payload: { name: 'Vocals', trackType: 'audio' },
255
+ });
256
+
257
+ // Set volume
258
+ await executor.execute({
259
+ type: CommandType.SET_VOLUME,
260
+ payload: { trackId: 'track-1', volume: 0.75 },
261
+ });
262
+
263
+ // Split region at playhead
264
+ await executor.execute({
265
+ type: CommandType.SPLIT_AT_PLAYHEAD,
266
+ payload: { trackId: 'track-1', frame: 44100 * 15 },
267
+ });
268
+
269
+ // Add a plugin
270
+ await executor.execute({
271
+ type: CommandType.ADD_PLUGIN,
272
+ payload: { trackId: 'track-1', pluginId: 'internal-eq6' },
273
+ });
274
+ ```
275
+
276
+ ### Undo / Redo
277
+
278
+ ```typescript
279
+ const history = executor.history;
280
+
281
+ await history.undo();
282
+ await history.redo();
283
+ await history.undoMultiple(3); // undo 3 steps
284
+
285
+ console.log(history.canUndo); // true
286
+ console.log(history.nextUndoLabel); // "Add Track"
287
+
288
+ // Transaction: group multiple commands into one undo step
289
+ history.beginTransaction('Move and resize');
290
+ // ... execute multiple commands ...
291
+ await history.commitTransaction();
292
+ ```
293
+
294
+ ### Registering Custom Handlers
295
+
296
+ ```typescript
297
+ import { CommandHandler, CommandResult } from '@drop-ai/core';
298
+
299
+ class MyCustomHandler implements CommandHandler {
300
+ readonly handledTypes = ['MY_CUSTOM_COMMAND'];
301
+
302
+ async execute(type: string, payload: any): Promise<CommandResult> {
303
+ // your logic here
304
+ return { success: true };
305
+ }
306
+ }
307
+
308
+ CommandExecutor.getInstance().registerHandler(new MyCustomHandler());
309
+ ```
310
+
311
+ ### Command Types
312
+
313
+ **Transport:** `PLAY`, `PAUSE`, `STOP`, `SEEK`, `SET_TEMPO`, `SET_TIME_SIGNATURE`, `TOGGLE_METRONOME`, `START_RECORDING`, `STOP_RECORDING`
314
+
315
+ **Tracks:** `ADD_TRACK`, `REMOVE_TRACK`, `SET_VOLUME`, `SET_PAN`, `MUTE_TRACK`, `SOLO_TRACK`, `ARM_TRACK`, `SET_TRACK_MONITOR`
316
+
317
+ **Regions:** `ADD_REGION`, `REMOVE_REGION`, `MOVE_REGION`, `RESIZE_REGION`, `SPLIT_AT_PLAYHEAD`, `DUPLICATE_REGION`, `COPY_REGION`, `PASTE_REGION`, `MERGE_REGIONS`, `TRIM_REGION`, `SET_REGION_FADES`, `REVERSE_REGION`, `NORMALIZE_REGION`, `STRIP_SILENCE`, `TIME_STRETCH_REGION`, `LOCK_REGION`, `GROUP_REGIONS`, `UNGROUP_REGIONS`
318
+
319
+ **Automation:** `ADD_AUTOMATION`, `MOVE_AUTOMATION_POINT`, `REMOVE_AUTOMATION_POINT`
320
+
321
+ **Plugins:** `ADD_PLUGIN`, `REMOVE_PLUGIN`, `SET_PLUGIN_PARAMETER`
322
+
323
+ **Ranges:** `ADD_RANGE`, `REMOVE_RANGE`, `SET_RANGE`, `SET_LOOP_RANGE`, `SET_PUNCH_RANGE`, `TOGGLE_LOOP`
324
+
325
+ **Markers:** `ADD_MARKER`, `REMOVE_MARKER`, `MOVE_MARKER`
326
+
327
+ **IO/Routing:** `CONNECT_IO`, `DISCONNECT_IO`, `ADD_SEND_BUS`, `REMOVE_SEND_BUS`, `SET_SEND_LEVEL`
328
+
329
+ **Session:** `EXPORT`, `NEW_SESSION`, `LOAD_SESSION`, `SAVE_SESSION`, `SAVE_SNAPSHOT`
330
+
331
+ **History:** `UNDO`, `REDO`, `SELECTION_UNDO`, `SELECTION_REDO`
332
+
333
+ ---
334
+
335
+ ## Plugins
336
+
337
+ 20+ built-in audio effect plugins, managed by `PluginManager`.
338
+
339
+ ```typescript
340
+ import { PluginManager } from '@drop-ai/core';
341
+
342
+ const manager = PluginManager.getInstance();
343
+
344
+ // List all available plugins
345
+ const plugins = manager.getAvailablePlugins();
346
+ plugins.forEach(p => console.log(p.id, p.name));
347
+
348
+ // Create a plugin instance
349
+ const eq = manager.createPlugin('internal-eq6');
350
+ eq.setParameter('band1-freq', 100);
351
+ eq.setParameter('band1-gain', 3.0);
352
+
353
+ // Get/set full state (presets)
354
+ const state = eq.getState();
355
+ eq.setState(state);
356
+
357
+ // React to parameter changes
358
+ eq.parameterChanged.connect(({ id, value }) => {
359
+ console.log(`${id} changed to ${value}`);
360
+ });
361
+ ```
362
+
363
+ ### Available Plugins
364
+
365
+ | ID | Name | Description |
366
+ |----|------|-------------|
367
+ | `internal-eq6` | Parametric EQ | 6-band parametric equalizer |
368
+ | `internal-compressor` | Compressor | Dynamics compressor |
369
+ | `internal-multiband-comp` | Multiband Compressor | Multi-band dynamics |
370
+ | `internal-expander` | Expander | Expander/gate |
371
+ | `internal-gate` | Gate | Noise gate |
372
+ | `internal-deesser` | De-Esser | Sibilance reduction |
373
+ | `internal-reverb` | Reverb | Algorithmic reverb |
374
+ | `internal-convolver` | Convolution Reverb | IR-based reverb |
375
+ | `internal-delay` | Delay | Simple delay |
376
+ | `internal-sync-delay` | Sync Delay | BPM-synced delay |
377
+ | `internal-chorus` | Chorus | Chorus effect |
378
+ | `internal-phaser` | Phaser | Phaser effect |
379
+ | `internal-tremolo` | Tremolo | Tremolo effect |
380
+ | `internal-vibrato` | Vibrato | Vibrato effect |
381
+ | `internal-autopan` | Auto Pan | Automatic panning |
382
+ | `internal-distortion` | Distortion | Distortion/overdrive |
383
+ | `internal-tape-sat` | Tape Saturation | Analog tape emulation |
384
+ | `internal-filter` | Filter | Multi-mode filter |
385
+ | `internal-eq3` | 3-Band EQ | Simple 3-band EQ |
386
+ | `internal-gain` | Gain | Utility gain |
387
+
388
+ ---
389
+
390
+ ## Automation
391
+
392
+ Per-parameter automation with multiple recording modes.
393
+
394
+ ```typescript
395
+ import { AutomationList, AutomationMode } from '@drop-ai/core';
396
+
397
+ const automation = new AutomationList();
398
+
399
+ // Add points
400
+ automation.addPoint(0, 0.5); // value 0.5 at time 0
401
+ automation.addPoint(2.0, 1.0); // value 1.0 at time 2s
402
+ automation.addPoint(4.0, 0.0); // value 0.0 at time 4s
403
+
404
+ // Read interpolated value
405
+ const value = automation.getValueAt(1.0); // ~0.75 (linear interpolation)
406
+
407
+ // Modes
408
+ automation.mode = AutomationMode.READ; // playback only
409
+ automation.mode = AutomationMode.WRITE; // overwrite
410
+ automation.mode = AutomationMode.TOUCH; // write while touching, snap back on release
411
+ automation.mode = AutomationMode.LATCH; // write while touching, hold last value
412
+
413
+ // Range operations
414
+ const copied = automation.copy(1.0, 3.0);
415
+ automation.paste(copied, 5.0);
416
+ automation.eraseRange(1.0, 3.0);
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Signal (Event System)
422
+
423
+ Type-safe event emitter inspired by Qt's Signal/Slot pattern. Used throughout the domain layer.
424
+
425
+ ```typescript
426
+ import { Signal } from '@drop-ai/core';
427
+
428
+ const signal = new Signal<number>();
429
+
430
+ // Subscribe
431
+ const sub = signal.connect((value) => {
432
+ console.log('Received:', value);
433
+ });
434
+
435
+ // Emit
436
+ signal.emit(42); // logs "Received: 42"
437
+
438
+ // Unsubscribe
439
+ sub.dispose();
440
+
441
+ // Or disconnect by reference
442
+ const handler = (v: number) => console.log(v);
443
+ signal.connect(handler);
444
+ signal.disconnect(handler);
445
+
446
+ // Clear all listeners
447
+ signal.clear();
448
+ ```
449
+
450
+ ### Common Signals
451
+
452
+ ```typescript
453
+ // Session
454
+ session.trackAdded.connect((track) => { /* ... */ });
455
+ session.trackRemoved.connect((trackId) => { /* ... */ });
456
+ session.tempoChanged.connect((bpm) => { /* ... */ });
457
+ session.playingChanged.connect((isPlaying) => { /* ... */ });
458
+ session.selectionChanged.connect((selectedIds) => { /* ... */ });
459
+ session.markerAdded.connect((marker) => { /* ... */ });
460
+
461
+ // Track
462
+ track.muteChanged.connect((muted) => { /* ... */ });
463
+ track.soloChanged.connect((soloed) => { /* ... */ });
464
+ track.armChanged.connect((armed) => { /* ... */ });
465
+
466
+ // CommandExecutor
467
+ executor.commandExecuted.connect(({ type, payload }) => { /* ... */ });
468
+
469
+ // CommandHistory
470
+ history.historyChanged.connect(() => { /* ... */ });
471
+ ```
472
+
473
+ ---
474
+
475
+ ## Actions & Key Bindings
476
+
477
+ Map keyboard shortcuts to commands.
478
+
479
+ ```typescript
480
+ import { ActionRegistry, ActionCategory } from '@drop-ai/core';
481
+
482
+ const registry = ActionRegistry.getInstance();
483
+
484
+ // Register default actions (typically done at app bootstrap)
485
+ registry.registerDefaults([
486
+ {
487
+ id: 'transport.play',
488
+ label: 'Play/Pause',
489
+ category: ActionCategory.TRANSPORT,
490
+ defaultKey: 'Space',
491
+ commandFactory: () => ({ type: CommandType.PLAY, payload: {} }),
492
+ },
493
+ {
494
+ id: 'edit.undo',
495
+ label: 'Undo',
496
+ category: ActionCategory.EDIT,
497
+ defaultKey: 'Ctrl+Z',
498
+ commandFactory: () => ({ type: CommandType.UNDO, payload: {} }),
499
+ },
500
+ ]);
501
+
502
+ // Execute by action ID
503
+ await registry.execute('transport.play');
504
+
505
+ // Query
506
+ const actions = registry.getActionsByCategory();
507
+ const key = registry.getEffectiveKey('transport.play'); // 'Space'
508
+ ```
509
+
510
+ ### Custom Key Bindings
511
+
512
+ ```typescript
513
+ import { KeyBindings } from '@drop-ai/core';
514
+
515
+ const bindings = KeyBindings.getInstance();
516
+
517
+ bindings.setBinding('transport.play', 'Enter');
518
+ bindings.getBinding('transport.play'); // 'Enter'
519
+ bindings.removeBinding('transport.play'); // back to default
520
+ bindings.resetToDefaults();
521
+ ```
522
+
523
+ ---
524
+
525
+ ## Preferences
526
+
527
+ Persistent settings with defaults.
528
+
529
+ ```typescript
530
+ import { Preferences } from '@drop-ai/core';
531
+
532
+ const prefs = Preferences.getInstance();
533
+
534
+ prefs.set('sampleRate', 48000);
535
+ prefs.set('audioBufferSize', 256);
536
+ prefs.set('theme', 'dark');
537
+ prefs.set('snapToGrid', true);
538
+ prefs.set('historyDepth', 100);
539
+
540
+ const sr = prefs.get('sampleRate'); // 48000
541
+
542
+ // React to changes
543
+ prefs.preferenceChanged.connect(() => {
544
+ console.log('Settings updated');
545
+ });
546
+
547
+ // Reset
548
+ prefs.resetToDefaults();
549
+ ```
550
+
551
+ **Available Keys:** `audioBufferSize`, `sampleRate`, `theme`, `autoSaveInterval`, `snapToGrid`, `gridSubdivision`, `meterType`, `showMinimap`, `followPlayhead`, `countInBars`, `historyDepth`, `saveHistory`, `saveHistoryDepth`
552
+
553
+ ---
554
+
555
+ ## Storage
556
+
557
+ Session persistence via IndexedDB (browser) or localStorage fallback.
558
+
559
+ ```typescript
560
+ import { SessionStorage } from '@drop-ai/core';
561
+
562
+ const storage = SessionStorage.getInstance();
563
+
564
+ // Save
565
+ await storage.saveSession(session);
566
+
567
+ // List
568
+ const sessions = await storage.listSessions();
569
+ // [{ id: '...', name: 'My Song', modified: Date }]
570
+
571
+ // Load
572
+ const snapshot = await storage.loadSession(sessions[0].id);
573
+ const restored = Session.fromJSON(snapshot);
574
+
575
+ // Snapshots (named save points)
576
+ const snapId = await storage.saveSnapshot(session.id, 'Before mixing', session.toJSON());
577
+ const snap = await storage.loadSnapshot(snapId);
578
+
579
+ // Delete
580
+ await storage.deleteSession(session.id);
581
+ ```
582
+
583
+ ---
584
+
585
+ ## Processing Chain
586
+
587
+ Each track has a `Route` containing an ordered chain of processors.
588
+
589
+ ```typescript
590
+ import {
591
+ GainProcessor,
592
+ PanProcessor,
593
+ PluginInsert,
594
+ SendProcessor,
595
+ MeterProcessor,
596
+ } from '@drop-ai/core';
597
+
598
+ // Processor types available in the chain:
599
+ // GainProcessor — Fader / Trim level control
600
+ // PanProcessor — Stereo panning and width
601
+ // PluginInsert — Plugin effect slot
602
+ // SendProcessor — Pre/Post fader send to aux bus
603
+ // MeterProcessor — Peak/RMS metering
604
+ ```
605
+
606
+ ---
607
+
608
+ ## Usage Examples
609
+
610
+ ### Node.js CLI
611
+
612
+ ```typescript
613
+ import { AudioEngine, Session, CommandExecutor, CommandType } from '@drop-ai/core';
614
+
615
+ // Headless backend (no audio output)
616
+ class HeadlessBackend implements AudioProvider {
617
+ async initialize() {}
618
+ start() {}
619
+ stop() {}
620
+ // ... no-op implementations
621
+ }
622
+
623
+ const engine = AudioEngine.getInstance(new HeadlessBackend());
624
+ const session = engine.session;
625
+
626
+ session.addTrack('Track 1', TrackType.AUDIO);
627
+ console.log('Tracks:', session.tracks.map(t => t.name));
628
+
629
+ const snapshot = session.toJSON();
630
+ // Save to file, process offline, etc.
631
+ ```
632
+
633
+ ### Electron App
634
+
635
+ ```typescript
636
+ import { AudioEngine, AudioProvider } from '@drop-ai/core';
637
+
638
+ class ElectronAudioBackend implements AudioProvider {
639
+ // Use PortAudio or native audio APIs
640
+ // ...
641
+ }
642
+
643
+ const engine = AudioEngine.getInstance(new ElectronAudioBackend());
644
+ await engine.initialize();
645
+ ```
646
+
647
+ ### React Integration
648
+
649
+ ```typescript
650
+ import { useEffect, useState } from 'react';
651
+ import { AudioEngine, Session } from '@drop-ai/core';
652
+
653
+ function useDAWEngine(backend: AudioProvider) {
654
+ const [engine] = useState(() => AudioEngine.getInstance(backend));
655
+
656
+ useEffect(() => {
657
+ const sub = engine.session.tempoChanged.connect((bpm) => {
658
+ // update React state
659
+ });
660
+ return () => sub.dispose();
661
+ }, [engine]);
662
+
663
+ return engine;
664
+ }
665
+ ```
666
+
667
+ ---
668
+
669
+ ## API Reference
670
+
671
+ ### Singletons
672
+
673
+ | Class | Access | Description |
674
+ |-------|--------|-------------|
675
+ | `AudioEngine` | `getInstance(backend?)` | Audio engine with session and transport |
676
+ | `CommandExecutor` | `getInstance()` | Command dispatch with validation |
677
+ | `PluginManager` | `getInstance()` | Plugin factory |
678
+ | `ActionRegistry` | `getInstance()` | Keyboard shortcut ↔ command mapping |
679
+ | `Preferences` | `getInstance()` | User settings |
680
+ | `KeyBindings` | `getInstance()` | Custom key binding overrides |
681
+ | `SessionStorage` | `getInstance()` | Session persistence |
682
+
683
+ ### Domain Models
684
+
685
+ | Class | Description |
686
+ |-------|-------------|
687
+ | `Session` | Project root — tracks, sources, markers, ranges, tempo |
688
+ | `Track` | Audio/MIDI/AUX/BUS/FOLDER/VCA track |
689
+ | `Region` | Audio segment on the timeline |
690
+ | `Playlist` | Region collection within a track |
691
+ | `Source` | Audio file reference (URL, duration, sampleRate) |
692
+ | `Range` | Loop/punch/selection range |
693
+ | `Marker` | Timeline marker (position + name) |
694
+ | `MidiNote` | Single MIDI note event |
695
+ | `MidiRegion` | MIDI note collection on the timeline |
696
+ | `SendBus` | Pre/post fader send bus |
697
+ | `Route` | Signal chain (input → processors → output) |
698
+ | `TempoMap` | BPM change events over time |
699
+ | `GridSettings` | Grid type and snap mode |
700
+ | `CrossfadeEngine` | Automatic crossfade calculation |
701
+ | `MixerScene` | Mixer snapshot save/restore |
702
+ | `TrackGroup` | Track grouping for linked control |
703
+
704
+ ### Type Definitions
705
+
706
+ ```typescript
707
+ type FrameCount = number // sample frame position
708
+ type SampleRate = number // e.g. 44100, 48000, 96000
709
+ type Gain = number // 0.0 to 1.0+
710
+ type DB = number // decibels
711
+
712
+ type TrackId = string
713
+ type RegionId = string
714
+ type SourceId = string
715
+ type RangeId = string
716
+ type ProcessorId = string
717
+ type RouteId = string
718
+ ```
719
+
720
+ ---
721
+
722
+ ## Dependencies
723
+
724
+ | Package | Type | Description |
725
+ |---------|------|-------------|
726
+ | `zod` | runtime | Command payload validation |
727
+ | `lamejs` | peer (optional) | MP3 export support |
728
+ | `soundtouchjs` | peer (optional) | Time-stretch / pitch-shift |
729
+
730
+ ---
731
+
732
+ ## License
733
+
734
+ MIT