@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
package/README.md CHANGED
@@ -1,316 +1,734 @@
1
- # @drop-ai/core
1
+ # drop-daw
2
2
 
3
- drop.ai DAW 헤드리스 코어 라이브러리. 오디오 편집 도메인 로직, 커맨드 시스템, 오토메이션, 플러그인, MIDI UI 독립적인 모든 기능을 포함한다.
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
4
 
5
- ## 왜 분리했는가
5
+ ```bash
6
+ npm install drop-daw
7
+ ```
8
+
9
+ ## Features
6
10
 
7
- 기존에는 `src/core/`에 있던 코어 로직이 Next.js 앱과 같은 디렉토리에 섞여 있었다. 문제점:
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.
8
19
 
9
- - **Tone.js 커플링**: `AudioEngine`이 `ToneAudioProvider`를 직접 import하여 브라우저 없이 사용 불가
10
- - **Zustand 커플링**: `EditorHandler`, `defaultActions`, `dawQueryTool`이 `useDAWStore`를 직접 import
11
- - **테스트 격리 불가**: Node.js CLI나 headless 환경에서 코어 로직만 테스트하기 어려움
12
- - **재사용 불가**: 다른 프레임워크(Electron, React Native 등)에서 코어 로직 사용 불가
20
+ ---
13
21
 
14
- 분리 후:
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
+ }
15
38
 
16
- - `@drop-ai/core`는 **브라우저/프레임워크 의존성 제로**
17
- - Node.js CLI, 테스트, 다른 프레임워크에서 독립적으로 사용 가능
18
- - 향후 npm publish 가능
39
+ // 2. Initialize the engine with your backend
40
+ const engine = AudioEngine.getInstance(new MyAudioBackend());
19
41
 
20
- ## 아키텍처
42
+ // 3. Work with the session directly
43
+ const track = engine.session.addTrack('Vocals', TrackType.AUDIO);
21
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
+ });
22
50
  ```
23
- ┌─────────────────────────────────────────────────────────┐
24
- │ Next.js App (src/) │
25
- │ ┌──────────┐ ┌──────────────┐ ┌──────────────────────┐ │
26
- │ │Components│ │ Stores │ │ App-level modules │ │
27
- │ │(React) │ │ (Zustand) │ │ - ToneAudioProvider │ │
28
- │ │ │ │ useDAWStore │ │ - EditorHandler │ │
29
- │ │ │ │ │ │ - defaultActions │ │
30
- │ │ │ │ │ │ - dawQueryTool │ │
31
- │ └────┬─────┘ └──────┬───────┘ └──────────┬───────────┘ │
32
- │ │ │ │ │
33
- │ └──────────────┼─────────────────────┘ │
34
- │ │ │
35
- ├──────────────────────┼───────────────────────────────────┤
36
- │ ▼ │
37
- │ @drop-ai/core (packages/core/) │
38
- │ ┌────────┐ ┌────────┐ ┌──────────┐ ┌────────────────┐ │
39
- │ │Domain │ │Commands│ │Audio │ │Automation │ │
40
- │ │Session │ │Executor│ │Engine │ │List, Curve, │ │
41
- │ │Track │ │History │ │Backend(I)│ │Mode │ │
42
- │ │Region │ │55 Impls│ │Exporter │ └────────────────┘ │
43
- │ │Playlist│ │15 Hdlrs│ │Meter │ ┌────────────────┐ │
44
- │ │Source │ └────────┘ └──────────┘ │Plugins │ │
45
- │ │Range │ ┌────────┐ ┌──────────┐ │EQ, Reverb, │ │
46
- │ │Marker │ │Lib │ │Processing│ │Compressor, ... │ │
47
- │ │MIDI │ │Signal │ │Gain, Pan │ └────────────────┘ │
48
- │ └────────┘ └────────┘ └──────────┘ │
49
- └─────────────────────────────────────────────────────────┘
51
+
52
+ ---
53
+
54
+ ## Architecture
55
+
50
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.
51
89
 
52
- ## 모듈 구조 (193 파일)
53
-
54
- ### `domain/` — 도메인 모델 (42 파일)
55
-
56
- DAW의 핵심 데이터 구조. Ardour의 도메인 모델을 참고하여 설계됨.
57
-
58
- | 클래스 | 설명 |
59
- |--------|------|
60
- | `Session` | 프로젝트 루트. 트랙, 소스, 마커, 레인지, 템포맵 관리 |
61
- | `Track` | 오디오/MIDI/Bus/AUX 트랙. Route(IO + 프로세서 체인) 포함 |
62
- | `Region` | 타임라인 위의 오디오 구간. start, length, sourceStart, fades |
63
- | `Playlist` | 트랙 내 Region 컬렉션. 레이어, 크로스페이드 지원 |
64
- | `Source` | 오디오 파일 참조. URL, duration, sampleRate |
65
- | `Range` | 루프/펀치/선택 범위 (start, end) |
66
- | `Marker` | 타임라인 마커 (위치 + 이름) |
67
- | `MidiNote` / `MidiRegion` | MIDI 데이터 |
68
- | `SendBus` | 센드 버스 (pre/post fader) |
69
- | `GridSettings` | 그리드 타입, 스냅 모드 |
70
- | `TempoMap` | BPM 변경 이벤트 관리 |
71
- | `CrossfadeEngine` | 리전 겹침 시 자동 크로스페이드 계산 |
72
- | `TransportFSM` | 재생/정지/녹음 상태 머신 |
73
- | `MixerScene` | 믹서 스냅샷 저장/불러오기 |
74
-
75
- 모든 도메인 객체는 `Signal` 기반 이벤트를 발행한다:
76
90
  ```typescript
77
- session.trackAdded.connect((track: Track) => { ... });
78
- session.tempoChanged.connect((bpm: number) => { ... });
79
- track.muteChanged.connect((muted: boolean) => { ... });
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));
80
134
  ```
81
135
 
82
- ### `commands/` — 커맨드 시스템 (62 파일)
136
+ **Track Types:**
83
137
 
84
- Undo/Redo 지원 커맨드 패턴 구현.
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 |
85
146
 
86
- - **`CommandExecutor`**: Zod 스키마 검증 → 핸들러 라우팅 → 실행. 싱글톤.
87
- - **`CommandHistory`**: Undo/Redo 스택 관리. depth 설정 가능.
88
- - **15개 핸들러**: Transport, Track, Region, Range, Automation, Export, IO, SendBus, Session, Marker, Midi, MixerScene, TrackGroup, History + 앱에서 등록하는 EditorHandler
89
- - **55개 커맨드 구현체**: AddTrack, MoveRegion, SplitAtPlayhead, SetTrackVolume 등
147
+ ### Region
148
+
149
+ A segment of audio on the timeline, referencing a `Source`.
90
150
 
91
151
  ```typescript
92
- // 커맨드 실행
93
- await CommandExecutor.getInstance().execute({
94
- type: CommandType.ADD_TRACK,
95
- payload: { name: 'Vocals', trackType: 'audio' }
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 },
96
267
  });
97
268
 
98
- // 앱에서 커스텀 핸들러 등록
99
- CommandExecutor.getInstance().registerHandler(new EditorHandler());
269
+ // Add a plugin
270
+ await executor.execute({
271
+ type: CommandType.ADD_PLUGIN,
272
+ payload: { trackId: 'track-1', pluginId: 'internal-eq6' },
273
+ });
100
274
  ```
101
275
 
102
- ### `audio/` 오디오 엔진 (10 파일)
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
103
284
 
104
- - **`AudioEngine`**: 세션과 백엔드를 연결하는 중앙 컨트롤러. 싱글톤.
105
- - 트랜스포트 (play/stop/pause/seek)
106
- - 녹음 (audio + MIDI, 펀치, 루프 레코딩)
107
- - 미터링 (peak/RMS/LUFS)
108
- - 프로세서 체인 동기화
109
- - **`AudioProvider`**: 인터페이스. 실제 오디오 I/O 추상화.
110
- - 앱: `ToneAudioProvider` (Tone.js + Web Audio API)
111
- - CLI: `HeadlessAudioProvider`
112
- - 테스트: `MockAudioProvider`
113
- - **`OfflineExporter`**: WAV/MP3/OGG/FLAC 오프라인 렌더링
114
- - **`PlaylistEngine`**: 샘플 정확도 리전 렌더링 (AudioWorklet용)
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
115
295
 
116
296
  ```typescript
117
- // 백엔드 주입 (Dependency Injection)
118
- const engine = AudioEngine.getInstance(new ToneAudioProvider());
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
+ }
119
307
 
120
- // 또는 headless 환경
121
- const engine = AudioEngine.getInstance(new HeadlessAudioProvider());
308
+ CommandExecutor.getInstance().registerHandler(new MyCustomHandler());
122
309
  ```
123
310
 
124
- ### `automation/` — 오토메이션 (6 파일)
125
-
126
- | 클래스 | 설명 |
127
- |--------|------|
128
- | `AutomationList` | 파라미터별 오토메이션 포인트 컬렉션 |
129
- | `AutomationCurve` | 보간 (linear, exponential, s-curve) |
130
- | `AutomationMode` | Read, Write, Touch, Latch |
131
- | `PointThinning` | 실시간 녹음 시 포인트 간소화 |
132
- | `ParameterDescriptor` | 파라미터 메타데이터 (min, max, default) |
133
-
134
- ### `plugins/` 플러그인 시스템 (16 파일)
135
-
136
- 내장 오디오 플러그인:
137
-
138
- | 플러그인 | 설명 |
139
- |----------|------|
140
- | `ParametricEQPlugin` | 6밴드 파라메트릭 EQ |
141
- | `MultibandCompressorPlugin` | 멀티밴드 컴프레서 |
142
- | `ConvolutionReverbPlugin` | 컨볼루션 리버브 |
143
- | `SyncDelayPlugin` | BPM 동기 딜레이 |
144
- | `TapeSaturationPlugin` | 테이프 새추레이션 |
145
- | `DeEsserPlugin` | 디에서 |
146
- | `ExpanderPlugin` | 익스팬더/게이트 |
147
- | `PhaserPlugin` | 페이저 |
148
- | `TremoloPlugin` | 트레몰로 |
149
- | `VibratoPlugin` | 비브라토 |
150
- | `AutoPanPlugin` | 오토 |
151
-
152
- `PluginManager`로 등록/생성:
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
+
153
339
  ```typescript
340
+ import { PluginManager } from 'drop-daw';
341
+
154
342
  const manager = PluginManager.getInstance();
155
- const eq = manager.createPlugin('internal-parametric-eq');
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
+ });
156
361
  ```
157
362
 
158
- ### `processing/` — 신호 처리 체인 (8 파일)
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';
159
396
 
160
- Route(트랙 프로세서 체인)를 구성하는 프로세서들:
397
+ const automation = new AutomationList();
161
398
 
162
- - `GainProcessor` (Fader / Trim)
163
- - `PanProcessor` (스테레오 패닝 + 조절)
164
- - `PolarityProcessor` (위상 반전)
165
- - `SendProcessor` (Pre/Post fader 센드)
166
- - `MeterProcessor` (피크/RMS 미터링)
167
- - `PluginInsert` (플러그인 삽입 슬롯)
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
168
403
 
169
- ### `lib/` 유틸리티
404
+ // Read interpolated value
405
+ const value = automation.getValueAt(1.0); // ~0.75 (linear interpolation)
170
406
 
171
- - **`Signal<T>`**: 타입 안전 이벤트 시스템. Qt의 Signal/Slot 패턴.
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.
172
424
 
173
425
  ```typescript
426
+ import { Signal } from 'drop-daw';
427
+
174
428
  const signal = new Signal<number>();
175
- const sub = signal.connect((value) => console.log(value));
176
- signal.emit(42);
177
- sub.dispose(); // 구독 해제
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();
178
448
  ```
179
449
 
180
- ### `actions/` — 액션 레지스트리 (2 파일)
450
+ ### Common Signals
181
451
 
182
- 키보드 단축키 ↔ 커맨드 매핑 시스템.
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
+ ---
183
474
 
184
- - `ActionRegistry`: 액션 등록/조회/실행
185
- - `ActionDefinition`: id, label, category, defaultKey, commandFactory
475
+ ## Actions & Key Bindings
476
+
477
+ Map keyboard shortcuts to commands.
186
478
 
187
479
  ```typescript
480
+ import { ActionRegistry, ActionCategory } from 'drop-daw';
481
+
188
482
  const registry = ActionRegistry.getInstance();
189
- registry.registerDefaults(defaultActions); // 앱에서 등록
190
- await registry.execute('transport.togglePlay');
191
- ```
192
483
 
193
- ### `preferences/` 설정 (3 파일)
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
+ ```
194
509
 
195
- - `Preferences`: 싱글톤. audioBufferSize, sampleRate, theme, gridSubdivision 등
196
- - `KeyBindings`: 커스텀 키 바인딩 오버라이드
510
+ ### Custom Key Bindings
197
511
 
198
- ### `storage/` — 세션 저장 (3 파일)
512
+ ```typescript
513
+ import { KeyBindings } from 'drop-daw';
199
514
 
200
- - `SessionStorage`: IndexedDB/localStorage 기반 세션 저장/불러오기
201
- - `AutoSave`: 주기적 자동 저장
202
- - `SessionTemplate`: 새 세션 템플릿
515
+ const bindings = KeyBindings.getInstance();
203
516
 
204
- ### `ai/` — AI 에이전트 (5 파일)
517
+ bindings.setBinding('transport.play', 'Enter');
518
+ bindings.getBinding('transport.play'); // 'Enter'
519
+ bindings.removeBinding('transport.play'); // back to default
520
+ bindings.resetToDefaults();
521
+ ```
205
522
 
206
- - `DAWAgent`: LLM 기반 DAW 제어 에이전트
207
- - `dawCommandTool`: AI가 커맨드를 실행하는 도구
208
- - `dawSystemPrompt`: DAW 컨텍스트 시스템 프롬프트
523
+ ---
209
524
 
210
- ## 앱에서의 사용법
525
+ ## Preferences
211
526
 
212
- ### 부트스트랩 (useDAWStore.init)
527
+ Persistent settings with defaults.
213
528
 
214
529
  ```typescript
215
- import { AudioEngine } from '@drop-ai/core/audio/AudioEngine';
216
- import { CommandExecutor } from '@drop-ai/core/commands/CommandExecutor';
217
- import { ActionRegistry } from '@drop-ai/core/actions/ActionRegistry';
218
- import { ToneAudioProvider } from '../audio/ToneAudioProvider';
219
- import { EditorHandler } from '../app-commands/EditorHandler';
220
- import { defaultActions } from '../app-actions/defaultActions';
530
+ import { Preferences } from 'drop-daw';
531
+
532
+ const prefs = Preferences.getInstance();
221
533
 
222
- // 1. 오디오 백엔드 주입
223
- AudioEngine.getInstance(new ToneAudioProvider());
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);
224
539
 
225
- // 2. 전용 커맨드 핸들러 등록
226
- CommandExecutor.getInstance().registerHandler(new EditorHandler());
540
+ const sr = prefs.get('sampleRate'); // 48000
227
541
 
228
- // 3. 기본 액션(키보드 단축키) 등록
229
- ActionRegistry.getInstance().registerDefaults(defaultActions);
542
+ // React to changes
543
+ prefs.preferenceChanged.connect(() => {
544
+ console.log('Settings updated');
545
+ });
546
+
547
+ // Reset
548
+ prefs.resetToDefaults();
230
549
  ```
231
550
 
232
- ### Import 패턴
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.
233
558
 
234
559
  ```typescript
235
- // barrel import (주요 타입)
236
- import { Session, Track, Region, AudioEngine } from '@drop-ai/core';
237
-
238
- // deep import (특정 모듈)
239
- import { AudioEngine } from '@drop-ai/core/audio/AudioEngine';
240
- import { CommandType } from '@drop-ai/core/commands/types';
241
- import { Signal } from '@drop-ai/core/lib/Signal';
242
- import { TempoMap } from '@drop-ai/core/domain/temporal/TempoMap';
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);
243
581
  ```
244
582
 
245
- ## 앱 쪽에 남긴 파일 (7개)
246
-
247
- 브라우저/스토어 의존성 때문에 코어에 포함할 수 없는 파일들:
248
-
249
- | 파일 | 위치 | 이유 |
250
- |------|------|------|
251
- | `ToneAudioProvider.ts` | `src/audio/` | Tone.js + browser AudioContext |
252
- | `ToneTrack.ts` | `src/audio/` | Tone.js import |
253
- | `TrackProcessor.ts` | `src/audio/worklets/` | AudioWorklet browser API |
254
- | `TimeStretchProcessor.ts` | `src/audio/` | soundtouchjs + OfflineAudioContext |
255
- | `defaultActions.ts` | `src/app-actions/` | useDAWStore import |
256
- | `EditorHandler.ts` | `src/app-commands/` | useDAWStore import |
257
- | `dawQueryTool.ts` | `src/app-ai/` | useDAWStore import |
258
-
259
- ## 디커플링 요약
260
-
261
- | 변경 | Before | After |
262
- |------|--------|-------|
263
- | `AudioEngine` | `ToneAudioProvider` 하드코딩 | 백엔드 주입 필수 (DI) |
264
- | `CommandExecutor` | `EditorHandler` 내장 | `registerHandler()` API |
265
- | `ActionRegistry` | `defaultActions` 자동 로드 | `registerDefaults()` API |
266
- | `KeyBindings` / `Preferences` | `localStorage` 직접 접근 | `typeof localStorage` 가드 |
267
- | `ExportHandler` | `document.createElement` 직접 호출 | `typeof document` 가드 |
268
- | `ai/tools` | `dawQueryTool` 내장 | 앱에서 별도 관리 |
269
-
270
- ## 설정 파일
271
-
272
- ### pnpm-workspace.yaml
273
- ```yaml
274
- packages:
275
- - "packages/*"
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
276
604
  ```
277
605
 
278
- ### 루트 package.json (의존성)
279
- ```json
280
- {
281
- "dependencies": {
282
- "@drop-ai/core": "workspace:*"
283
- }
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
284
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.
285
631
  ```
286
632
 
287
- ### 루트 tsconfig.json (paths)
288
- ```json
289
- {
290
- "paths": {
291
- "@/*": ["./*"],
292
- "@drop-ai/core": ["./packages/core/src"],
293
- "@drop-ai/core/*": ["./packages/core/src/*"]
294
- }
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
+ // ...
295
641
  }
642
+
643
+ const engine = AudioEngine.getInstance(new ElectronAudioBackend());
644
+ await engine.initialize();
296
645
  ```
297
646
 
298
- ## 테스트
647
+ ### React Integration
299
648
 
300
- ```bash
301
- # 전체 단위 테스트 (308개)
302
- pnpm test
649
+ ```typescript
650
+ import { useEffect, useState } from 'react';
651
+ import { AudioEngine, Session } from 'drop-daw';
303
652
 
304
- # 코어 패키지 타입 체크
305
- cd packages/core && npx tsc --noEmit
653
+ function useDAWEngine(backend: AudioProvider) {
654
+ const [engine] = useState(() => AudioEngine.getInstance(backend));
306
655
 
307
- # 루트 프로젝트 타입 체크
308
- npx tsc --noEmit
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
309
718
  ```
310
719
 
311
- ## 향후 계획
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
312
733
 
313
- - [ ] `packages/core/` 빌드 파이프라인 (`tsc` → `dist/`)
314
- - [ ] npm publish (`private: false`)
315
- - [ ] Electron 앱에서 `@drop-ai/core` 재사용
316
- - [ ] 코어 전용 단위 테스트 (`packages/core/test/`)
734
+ MIT