@drop-ai/core 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +734 -734
- package/dist/analysis/AudioAnalyzer.d.ts +0 -2
- package/dist/analysis/AudioAnalyzer.d.ts.map +1 -1
- package/dist/analysis/AudioAnalyzer.js +0 -2
- package/dist/analysis/AudioAnalyzer.js.map +1 -1
- package/dist/audio/Auditioner.d.ts +0 -2
- package/dist/audio/Auditioner.d.ts.map +1 -1
- package/dist/audio/Auditioner.js +0 -2
- package/dist/audio/Auditioner.js.map +1 -1
- package/dist/audio/BWFMetadata.d.ts +0 -2
- package/dist/audio/BWFMetadata.d.ts.map +1 -1
- package/dist/audio/BWFMetadata.js +0 -2
- package/dist/audio/BWFMetadata.js.map +1 -1
- package/dist/audio/BufferPool.d.ts +0 -3
- package/dist/audio/BufferPool.d.ts.map +1 -1
- package/dist/audio/BufferPool.js +0 -3
- package/dist/audio/BufferPool.js.map +1 -1
- package/dist/audio/ChannelSplitter.d.ts +0 -1
- package/dist/audio/ChannelSplitter.d.ts.map +1 -1
- package/dist/audio/ChannelSplitter.js +0 -1
- package/dist/audio/ChannelSplitter.js.map +1 -1
- package/dist/audio/ExportAnalyzer.d.ts +0 -1
- package/dist/audio/ExportAnalyzer.d.ts.map +1 -1
- package/dist/audio/ExportAnalyzer.js +0 -1
- package/dist/audio/ExportAnalyzer.js.map +1 -1
- package/dist/audio/LufsNormalizer.d.ts +0 -1
- package/dist/audio/LufsNormalizer.d.ts.map +1 -1
- package/dist/audio/LufsNormalizer.js +0 -1
- package/dist/audio/LufsNormalizer.js.map +1 -1
- package/dist/audio/MeterUtils.d.ts +0 -2
- package/dist/audio/MeterUtils.d.ts.map +1 -1
- package/dist/audio/MeterUtils.js +0 -2
- package/dist/audio/MeterUtils.js.map +1 -1
- package/dist/audio/OfflineExporter.d.ts +0 -1
- package/dist/audio/OfflineExporter.d.ts.map +1 -1
- package/dist/audio/OfflineExporter.js +0 -1
- package/dist/audio/OfflineExporter.js.map +1 -1
- package/dist/audio/ProcessingGraph.d.ts +0 -1
- package/dist/audio/ProcessingGraph.d.ts.map +1 -1
- package/dist/audio/ProcessingGraph.js +0 -1
- package/dist/audio/ProcessingGraph.js.map +1 -1
- package/dist/audio/RoutingGraph.d.ts +1 -1
- package/dist/audio/RoutingGraph.js +2 -2
- package/dist/audio/SampleRateConverter.d.ts +0 -1
- package/dist/audio/SampleRateConverter.d.ts.map +1 -1
- package/dist/audio/SampleRateConverter.js +0 -1
- package/dist/audio/SampleRateConverter.js.map +1 -1
- package/dist/audio/SilencePadding.d.ts +0 -2
- package/dist/audio/SilencePadding.d.ts.map +1 -1
- package/dist/audio/SilencePadding.js +0 -2
- package/dist/audio/SilencePadding.js.map +1 -1
- package/dist/audio/SourceCache.d.ts +0 -3
- package/dist/audio/SourceCache.d.ts.map +1 -1
- package/dist/audio/SourceCache.js +0 -3
- package/dist/audio/SourceCache.js.map +1 -1
- package/dist/audio/engine/Declick.d.ts +0 -1
- package/dist/audio/engine/Declick.d.ts.map +1 -1
- package/dist/audio/engine/Declick.js +0 -1
- package/dist/audio/engine/Declick.js.map +1 -1
- package/dist/audio/engine/DiskIO.d.ts +0 -2
- package/dist/audio/engine/DiskIO.d.ts.map +1 -1
- package/dist/audio/engine/DiskIO.js +0 -2
- package/dist/audio/engine/DiskIO.js.map +1 -1
- package/dist/audio/engine/MultiTrackRecorder.d.ts +0 -2
- package/dist/audio/engine/MultiTrackRecorder.d.ts.map +1 -1
- package/dist/audio/engine/MultiTrackRecorder.js.map +1 -1
- package/dist/audio/engine/PlaylistEngine.d.ts +1 -1
- package/dist/audio/engine/PlaylistEngine.d.ts.map +1 -1
- package/dist/audio/engine/PlaylistEngine.js +1 -1
- package/dist/audio/engine/PlaylistEngine.js.map +1 -1
- package/dist/audio/engine/PunchRecordManager.d.ts +0 -2
- package/dist/audio/engine/PunchRecordManager.d.ts.map +1 -1
- package/dist/audio/engine/PunchRecordManager.js.map +1 -1
- package/dist/audio/engine/RoutingGraph.d.ts +0 -2
- package/dist/audio/engine/RoutingGraph.d.ts.map +1 -1
- package/dist/audio/engine/RoutingGraph.js.map +1 -1
- package/dist/audio/engine/SidechainRouter.d.ts +0 -2
- package/dist/audio/engine/SidechainRouter.d.ts.map +1 -1
- package/dist/audio/engine/SidechainRouter.js +0 -2
- package/dist/audio/engine/SidechainRouter.js.map +1 -1
- package/dist/audio/export/CDMarkerExporter.d.ts +0 -2
- package/dist/audio/export/CDMarkerExporter.d.ts.map +1 -1
- package/dist/audio/export/CDMarkerExporter.js +0 -2
- package/dist/audio/export/CDMarkerExporter.js.map +1 -1
- package/dist/audio/export/ExportGraphBuilder.d.ts +0 -2
- package/dist/audio/export/ExportGraphBuilder.d.ts.map +1 -1
- package/dist/audio/export/ExportGraphBuilder.js +0 -2
- package/dist/audio/export/ExportGraphBuilder.js.map +1 -1
- package/dist/audio/export/ExportPresetManager.d.ts +0 -2
- package/dist/audio/export/ExportPresetManager.d.ts.map +1 -1
- package/dist/audio/export/ExportPresetManager.js +0 -2
- package/dist/audio/export/ExportPresetManager.js.map +1 -1
- package/dist/automation/AutomationList.d.ts +0 -1
- package/dist/automation/AutomationList.d.ts.map +1 -1
- package/dist/automation/AutomationList.js +0 -1
- package/dist/automation/AutomationList.js.map +1 -1
- package/dist/automation/AutomationMode.d.ts +0 -1
- package/dist/automation/AutomationMode.d.ts.map +1 -1
- package/dist/automation/AutomationMode.js +0 -1
- package/dist/automation/AutomationMode.js.map +1 -1
- package/dist/commands/CommandHistory.d.ts +1 -4
- package/dist/commands/CommandHistory.d.ts.map +1 -1
- package/dist/commands/CommandHistory.js +6 -9
- package/dist/commands/CommandHistory.js.map +1 -1
- package/dist/commands/CommandRegistry.d.ts +1 -2
- package/dist/commands/CommandRegistry.d.ts.map +1 -1
- package/dist/commands/CommandRegistry.js +1 -2
- package/dist/commands/CommandRegistry.js.map +1 -1
- package/dist/commands/UndoTransaction.d.ts +0 -2
- package/dist/commands/UndoTransaction.d.ts.map +1 -1
- package/dist/commands/UndoTransaction.js +1 -3
- package/dist/commands/UndoTransaction.js.map +1 -1
- package/dist/commands/handlers/HistoryHandler.d.ts +5 -5
- package/dist/commands/handlers/HistoryHandler.js +10 -10
- package/dist/commands/handlers/HistoryHandler.js.map +1 -1
- package/dist/commands/handlers/MarkerHandler.d.ts +0 -1
- package/dist/commands/handlers/MarkerHandler.d.ts.map +1 -1
- package/dist/commands/handlers/MarkerHandler.js +0 -1
- package/dist/commands/handlers/MarkerHandler.js.map +1 -1
- package/dist/commands/impl/CopyRegionCommand.d.ts +0 -1
- package/dist/commands/impl/CopyRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/CopyRegionCommand.js +0 -1
- package/dist/commands/impl/CopyRegionCommand.js.map +1 -1
- package/dist/commands/impl/DuplicateRegionCommand.d.ts +0 -1
- package/dist/commands/impl/DuplicateRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/DuplicateRegionCommand.js +0 -1
- package/dist/commands/impl/DuplicateRegionCommand.js.map +1 -1
- package/dist/commands/impl/ExportCommand.d.ts +0 -1
- package/dist/commands/impl/ExportCommand.d.ts.map +1 -1
- package/dist/commands/impl/ExportCommand.js +0 -1
- package/dist/commands/impl/ExportCommand.js.map +1 -1
- package/dist/commands/impl/FreezeTrackCommand.d.ts +1 -1
- package/dist/commands/impl/FreezeTrackCommand.js +1 -1
- package/dist/commands/impl/PasteRegionCommand.d.ts +0 -1
- package/dist/commands/impl/PasteRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/PasteRegionCommand.js +0 -1
- package/dist/commands/impl/PasteRegionCommand.js.map +1 -1
- package/dist/commands/impl/SaveSnapshotCommand.d.ts +1 -1
- package/dist/commands/impl/SaveSnapshotCommand.js +1 -1
- package/dist/commands/impl/SetLoopRangeCommand.d.ts +0 -1
- package/dist/commands/impl/SetLoopRangeCommand.d.ts.map +1 -1
- package/dist/commands/impl/SetLoopRangeCommand.js +0 -1
- package/dist/commands/impl/SetLoopRangeCommand.js.map +1 -1
- package/dist/commands/impl/SetPunchRangeCommand.d.ts +0 -1
- package/dist/commands/impl/SetPunchRangeCommand.d.ts.map +1 -1
- package/dist/commands/impl/SetPunchRangeCommand.js +0 -1
- package/dist/commands/impl/SetPunchRangeCommand.js.map +1 -1
- package/dist/commands/impl/SplitAtPlayheadCommand.d.ts +0 -2
- package/dist/commands/impl/SplitAtPlayheadCommand.d.ts.map +1 -1
- package/dist/commands/impl/SplitAtPlayheadCommand.js +0 -2
- package/dist/commands/impl/SplitAtPlayheadCommand.js.map +1 -1
- package/dist/commands/impl/SplitRegionCommand.d.ts +0 -1
- package/dist/commands/impl/SplitRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/SplitRegionCommand.js +0 -1
- package/dist/commands/impl/SplitRegionCommand.js.map +1 -1
- package/dist/commands/impl/StripSilenceCommand.d.ts +0 -1
- package/dist/commands/impl/StripSilenceCommand.d.ts.map +1 -1
- package/dist/commands/impl/StripSilenceCommand.js +0 -1
- package/dist/commands/impl/StripSilenceCommand.js.map +1 -1
- package/dist/commands/impl/TimeStretchRegionCommand.d.ts +1 -2
- package/dist/commands/impl/TimeStretchRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/TimeStretchRegionCommand.js +1 -2
- package/dist/commands/impl/TimeStretchRegionCommand.js.map +1 -1
- package/dist/commands/impl/TrimRegionCommand.d.ts +1 -1
- package/dist/commands/impl/TrimRegionCommand.js +2 -2
- package/dist/commands/impl/TrimRegionCommand.js.map +1 -1
- package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts +0 -1
- package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts.map +1 -1
- package/dist/commands/impl/TrimRegionToPlayheadCommand.js +0 -1
- package/dist/commands/impl/TrimRegionToPlayheadCommand.js.map +1 -1
- package/dist/commands/impl/TrimRegionToRangeCommand.d.ts +0 -1
- package/dist/commands/impl/TrimRegionToRangeCommand.d.ts.map +1 -1
- package/dist/commands/impl/TrimRegionToRangeCommand.js +0 -1
- package/dist/commands/impl/TrimRegionToRangeCommand.js.map +1 -1
- package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts +0 -1
- package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts.map +1 -1
- package/dist/commands/impl/TrimToAdjacentRegionCommand.js +0 -1
- package/dist/commands/impl/TrimToAdjacentRegionCommand.js.map +1 -1
- package/dist/domain/ABComparison.d.ts +0 -1
- package/dist/domain/ABComparison.d.ts.map +1 -1
- package/dist/domain/ABComparison.js +0 -1
- package/dist/domain/ABComparison.js.map +1 -1
- package/dist/domain/CDMarker.d.ts +0 -1
- package/dist/domain/CDMarker.d.ts.map +1 -1
- package/dist/domain/CDMarker.js +0 -1
- package/dist/domain/CDMarker.js.map +1 -1
- package/dist/domain/ClockMode.d.ts +0 -1
- package/dist/domain/ClockMode.d.ts.map +1 -1
- package/dist/domain/ClockMode.js +0 -1
- package/dist/domain/ClockMode.js.map +1 -1
- package/dist/domain/DragManager.d.ts +0 -2
- package/dist/domain/DragManager.d.ts.map +1 -1
- package/dist/domain/DragManager.js +0 -2
- package/dist/domain/DragManager.js.map +1 -1
- package/dist/domain/EditMode.d.ts +0 -1
- package/dist/domain/EditMode.d.ts.map +1 -1
- package/dist/domain/EditMode.js +0 -1
- package/dist/domain/EditMode.js.map +1 -1
- package/dist/domain/ExportConfig.d.ts +0 -1
- package/dist/domain/ExportConfig.d.ts.map +1 -1
- package/dist/domain/ExportConfig.js +0 -1
- package/dist/domain/ExportConfig.js.map +1 -1
- package/dist/domain/ExportPreset.d.ts +0 -2
- package/dist/domain/ExportPreset.d.ts.map +1 -1
- package/dist/domain/ExportPreset.js +0 -2
- package/dist/domain/ExportPreset.js.map +1 -1
- package/dist/domain/ExportStatus.d.ts +0 -1
- package/dist/domain/ExportStatus.d.ts.map +1 -1
- package/dist/domain/ExportStatus.js +0 -1
- package/dist/domain/ExportStatus.js.map +1 -1
- package/dist/domain/GridSettings.d.ts +0 -3
- package/dist/domain/GridSettings.d.ts.map +1 -1
- package/dist/domain/GridSettings.js +0 -3
- package/dist/domain/GridSettings.js.map +1 -1
- package/dist/domain/Marker.d.ts +0 -1
- package/dist/domain/Marker.d.ts.map +1 -1
- package/dist/domain/Marker.js +0 -1
- package/dist/domain/Marker.js.map +1 -1
- package/dist/domain/MeterData.d.ts +0 -2
- package/dist/domain/MeterData.d.ts.map +1 -1
- package/dist/domain/MeterType.d.ts +0 -2
- package/dist/domain/MeterType.d.ts.map +1 -1
- package/dist/domain/MeterType.js +0 -2
- package/dist/domain/MeterType.js.map +1 -1
- package/dist/domain/MonitorMode.d.ts +0 -1
- package/dist/domain/MonitorMode.d.ts.map +1 -1
- package/dist/domain/MonitorMode.js +0 -1
- package/dist/domain/MonitorMode.js.map +1 -1
- package/dist/domain/MouseMode.d.ts +0 -1
- package/dist/domain/MouseMode.d.ts.map +1 -1
- package/dist/domain/MouseMode.js +0 -1
- package/dist/domain/MouseMode.js.map +1 -1
- package/dist/domain/OverlapType.d.ts +0 -2
- package/dist/domain/OverlapType.d.ts.map +1 -1
- package/dist/domain/OverlapType.js +0 -2
- package/dist/domain/OverlapType.js.map +1 -1
- package/dist/domain/Range.d.ts +0 -1
- package/dist/domain/Range.d.ts.map +1 -1
- package/dist/domain/Range.js +0 -1
- package/dist/domain/Range.js.map +1 -1
- package/dist/domain/RecordMode.d.ts +0 -1
- package/dist/domain/RecordMode.d.ts.map +1 -1
- package/dist/domain/RecordMode.js +0 -1
- package/dist/domain/RecordMode.js.map +1 -1
- package/dist/domain/Region.d.ts +3 -3
- package/dist/domain/Region.js +4 -4
- package/dist/domain/Region.js.map +1 -1
- package/dist/domain/RegionClipboard.d.ts +1 -3
- package/dist/domain/RegionClipboard.d.ts.map +1 -1
- package/dist/domain/RegionClipboard.js +1 -2
- package/dist/domain/RegionClipboard.js.map +1 -1
- package/dist/domain/RulerType.d.ts +0 -1
- package/dist/domain/RulerType.d.ts.map +1 -1
- package/dist/domain/RulerType.js +0 -1
- package/dist/domain/RulerType.js.map +1 -1
- package/dist/domain/SelectionHistory.d.ts +0 -3
- package/dist/domain/SelectionHistory.d.ts.map +1 -1
- package/dist/domain/SelectionHistory.js +0 -3
- package/dist/domain/SelectionHistory.js.map +1 -1
- package/dist/domain/SendBus.d.ts +0 -1
- package/dist/domain/SendBus.d.ts.map +1 -1
- package/dist/domain/SendBus.js +0 -1
- package/dist/domain/SendBus.js.map +1 -1
- package/dist/domain/SidechainConfig.d.ts +0 -1
- package/dist/domain/SidechainConfig.d.ts.map +1 -1
- package/dist/domain/SidechainConfig.js +0 -1
- package/dist/domain/SidechainConfig.js.map +1 -1
- package/dist/domain/Take.d.ts +0 -1
- package/dist/domain/Take.d.ts.map +1 -1
- package/dist/domain/Take.js +0 -1
- package/dist/domain/Take.js.map +1 -1
- package/dist/domain/ThawList.d.ts +0 -1
- package/dist/domain/ThawList.d.ts.map +1 -1
- package/dist/domain/ThawList.js +0 -1
- package/dist/domain/ThawList.js.map +1 -1
- package/dist/domain/TrackGroup.d.ts +0 -1
- package/dist/domain/TrackGroup.d.ts.map +1 -1
- package/dist/domain/TrackGroup.js +0 -1
- package/dist/domain/TrackGroup.js.map +1 -1
- package/dist/domain/TransportFSM.d.ts +0 -1
- package/dist/domain/TransportFSM.d.ts.map +1 -1
- package/dist/domain/TransportFSM.js +0 -1
- package/dist/domain/TransportFSM.js.map +1 -1
- package/dist/domain/TransportMode.d.ts +0 -1
- package/dist/domain/TransportMode.d.ts.map +1 -1
- package/dist/domain/TransportMode.js +0 -1
- package/dist/domain/TransportMode.js.map +1 -1
- package/dist/domain/TriggerBox.d.ts +0 -2
- package/dist/domain/TriggerBox.d.ts.map +1 -1
- package/dist/domain/TriggerBox.js +0 -2
- package/dist/domain/TriggerBox.js.map +1 -1
- package/dist/domain/VCATrack.d.ts +0 -2
- package/dist/domain/VCATrack.d.ts.map +1 -1
- package/dist/domain/VCATrack.js +0 -2
- package/dist/domain/VCATrack.js.map +1 -1
- package/dist/domain/VideoExportConfig.d.ts +0 -1
- package/dist/domain/VideoExportConfig.d.ts.map +1 -1
- package/dist/domain/VideoExportConfig.js +0 -1
- package/dist/domain/VideoExportConfig.js.map +1 -1
- package/dist/domain/ZoomFocus.d.ts +0 -1
- package/dist/domain/ZoomFocus.d.ts.map +1 -1
- package/dist/domain/ZoomFocus.js +0 -1
- package/dist/domain/ZoomFocus.js.map +1 -1
- package/dist/domain/temporal/TempoMap.d.ts +3 -4
- package/dist/domain/temporal/TempoMap.d.ts.map +1 -1
- package/dist/domain/temporal/TempoMap.js +2 -2
- package/dist/domain/temporal/TempoMap.js.map +1 -1
- package/dist/domain/temporal/types.d.ts +1 -1
- package/dist/domain/temporal/types.d.ts.map +1 -1
- package/dist/domain/temporal/types.js +1 -1
- package/dist/domain/temporal/types.js.map +1 -1
- package/dist/lib/Signal.d.ts +1 -1
- package/dist/lib/ThawList.d.ts +1 -3
- package/dist/lib/ThawList.d.ts.map +1 -1
- package/dist/lib/ThawList.js +1 -3
- package/dist/lib/ThawList.js.map +1 -1
- package/dist/midi/MidiFileParser.d.ts +0 -1
- package/dist/midi/MidiFileParser.d.ts.map +1 -1
- package/dist/midi/MidiFileParser.js +0 -1
- package/dist/midi/MidiFileParser.js.map +1 -1
- package/dist/midi/MidiFileWriter.d.ts +0 -1
- package/dist/midi/MidiFileWriter.d.ts.map +1 -1
- package/dist/midi/MidiFileWriter.js +0 -1
- package/dist/midi/MidiFileWriter.js.map +1 -1
- package/dist/plugins/PluginManager.js +2 -2
- package/dist/plugins/PluginManager.js.map +1 -1
- package/dist/plugins/impl/ExpanderPlugin.d.ts +1 -1
- package/dist/plugins/impl/ExpanderPlugin.js +1 -1
- package/dist/plugins/impl/ParametricEQPlugin.d.ts +1 -1
- package/dist/plugins/impl/ParametricEQPlugin.js +1 -1
- package/dist/processing/InternalSend.d.ts +0 -2
- package/dist/processing/InternalSend.d.ts.map +1 -1
- package/dist/processing/InternalSend.js.map +1 -1
- package/dist/processing/MeterDSP.d.ts +0 -1
- package/dist/processing/MeterDSP.d.ts.map +1 -1
- package/dist/processing/MeterDSP.js +0 -1
- package/dist/processing/MeterDSP.js.map +1 -1
- package/dist/processing/MeterProcessor.d.ts +0 -1
- package/dist/processing/MeterProcessor.d.ts.map +1 -1
- package/dist/processing/MeterProcessor.js +0 -1
- package/dist/processing/MeterProcessor.js.map +1 -1
- package/dist/processing/Panner.d.ts +1 -2
- package/dist/processing/Panner.d.ts.map +1 -1
- package/dist/processing/Panner.js +1 -2
- package/dist/processing/Panner.js.map +1 -1
- package/dist/processing/PolarityProcessor.d.ts +1 -1
- package/dist/processing/PolarityProcessor.js +1 -1
- package/dist/processing/SendProcessor.d.ts +0 -1
- package/dist/processing/SendProcessor.d.ts.map +1 -1
- package/dist/processing/SendProcessor.js +0 -1
- package/dist/processing/SendProcessor.js.map +1 -1
- package/dist/processing/SurroundPanner.d.ts +0 -2
- package/dist/processing/SurroundPanner.d.ts.map +1 -1
- package/dist/processing/SurroundPanner.js +0 -2
- package/dist/processing/SurroundPanner.js.map +1 -1
- package/dist/processing/TruePeakLimiter.d.ts +0 -2
- package/dist/processing/TruePeakLimiter.d.ts.map +1 -1
- package/dist/processing/TruePeakLimiter.js +0 -2
- package/dist/processing/TruePeakLimiter.js.map +1 -1
- package/dist/storage/SessionStorage.d.ts +1 -1
- package/dist/utils/BwfMetadataWriter.d.ts +0 -1
- package/dist/utils/BwfMetadataWriter.d.ts.map +1 -1
- package/dist/utils/BwfMetadataWriter.js +0 -1
- package/dist/utils/BwfMetadataWriter.js.map +1 -1
- package/dist/utils/DitherProcessor.d.ts +0 -1
- package/dist/utils/DitherProcessor.d.ts.map +1 -1
- package/dist/utils/DitherProcessor.js +0 -1
- package/dist/utils/DitherProcessor.js.map +1 -1
- package/dist/utils/FilenameTemplate.d.ts +0 -1
- package/dist/utils/FilenameTemplate.d.ts.map +1 -1
- package/dist/utils/FilenameTemplate.js +0 -1
- package/dist/utils/FilenameTemplate.js.map +1 -1
- package/dist/utils/FlacEncoder.d.ts +0 -1
- package/dist/utils/FlacEncoder.d.ts.map +1 -1
- package/dist/utils/FlacEncoder.js +0 -1
- package/dist/utils/FlacEncoder.js.map +1 -1
- package/dist/utils/Mp4ChapterGenerator.d.ts +0 -1
- package/dist/utils/Mp4ChapterGenerator.d.ts.map +1 -1
- package/dist/utils/Mp4ChapterGenerator.js +0 -1
- package/dist/utils/Mp4ChapterGenerator.js.map +1 -1
- package/dist/utils/OggEncoder.d.ts +0 -2
- package/dist/utils/OggEncoder.d.ts.map +1 -1
- package/dist/utils/OggEncoder.js +0 -2
- package/dist/utils/OggEncoder.js.map +1 -1
- package/dist/utils/TocGenerator.d.ts +0 -1
- package/dist/utils/TocGenerator.d.ts.map +1 -1
- package/dist/utils/TocGenerator.js +0 -1
- package/dist/utils/TocGenerator.js.map +1 -1
- package/package.json +1 -1
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-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
|