{"_id":"@anaidev/daw-engine-core","name":"@anaidev/daw-engine-core","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@anaidev/daw-engine-core","version":"1.0.0","description":"Headless DAW engine — domain models, command system, audio engine, automation, plugins, MIDI","license":"MIT","publishConfig":{"access":"public"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./*":{"types":"./dist/*.d.ts","import":"./dist/*.js"}},"sideEffects":false,"engines":{"node":">=18"},"scripts":{"build":"tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json --resolve-full-paths --resolve-full-extension .js","clean":"rm -rf dist","prepack":"npm run build","test":"vitest run","typecheck":"tsc --noEmit"},"dependencies":{"lamejs":"^1.2.1","zod":"^4.3.6"},"peerDependencies":{"soundtouchjs":"^0.3.0"},"peerDependenciesMeta":{"soundtouchjs":{"optional":true}},"devDependencies":{"@types/node":"^18.19.0","tsc-alias":"^1.9.1","typescript":"^5.7.2","vite":"^6.1.0","vitest":"3.2.4"},"keywords":["daw","audio","music","editor","midi","automation","plugin","headless"],"repository":{"type":"git","url":"git+https://github.com/HURRAEY/daw-engine.git","directory":"core"},"_id":"@anaidev/daw-engine-core@1.0.0","bugs":{"url":"https://github.com/HURRAEY/daw-engine/issues"},"homepage":"https://github.com/HURRAEY/daw-engine#readme","_integrity":"sha512-dZYsLX4l93reNQfa93IaRGCJLjTmO0+qZT1DvYyB9YjGZWS3oSWpXTD1zQifVgklDsjMghxunQA1qP7CzSKvEQ==","_resolved":"C:\\code\\AnAI\\daw-engine-anaidev\\.release-check\\anaidev-daw-engine-core-1.0.0.tgz","_from":"file:C:/code/AnAI/daw-engine-anaidev/.release-check/anaidev-daw-engine-core-1.0.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-dZYsLX4l93reNQfa93IaRGCJLjTmO0+qZT1DvYyB9YjGZWS3oSWpXTD1zQifVgklDsjMghxunQA1qP7CzSKvEQ==","shasum":"3d04042bcd9e1367872dbd0e3433b07ebe94141c","tarball":"https://registry.npmjs.org/@anaidev/daw-engine-core/-/daw-engine-core-1.0.0.tgz","fileCount":967,"unpackedSize":2904918,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHQZs2kw2gLQwCmrbgFbdSw0OiAvO/aDqMkoV2/frtqFAiAQKmZeE8DbwjgbXssDwTbm0ByoIAg6/PrpdiHoWkdyZA=="}]},"_npmUser":{"name":"anaidev","email":"dev@an-ai.ai"},"directories":{},"maintainers":[{"name":"anaidev","email":"dev@an-ai.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/daw-engine-core_1.0.0_1785147292924_0.43759386073073947"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T10:14:52.764Z","1.0.0":"2026-07-27T10:14:53.118Z","modified":"2026-07-27T10:14:53.342Z"},"maintainers":[{"name":"anaidev","email":"dev@an-ai.ai"}],"description":"Headless DAW engine — domain models, command system, audio engine, automation, plugins, MIDI","homepage":"https://github.com/HURRAEY/daw-engine#readme","keywords":["daw","audio","music","editor","midi","automation","plugin","headless"],"repository":{"type":"git","url":"git+https://github.com/HURRAEY/daw-engine.git","directory":"core"},"bugs":{"url":"https://github.com/HURRAEY/daw-engine/issues"},"license":"MIT","readme":"# @anaidev/daw-engine-core\n\nHeadless 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.\n\n```bash\nnpm install @anaidev/daw-engine-core\n```\n\n## Features\n\n- **Headless** — No browser, no React, no framework required. Runs in Node.js, Electron, or any JS runtime.\n- **Command Pattern** — All mutations go through `CommandExecutor` with built-in Undo/Redo.\n- **Dependency Injection** — Bring your own audio backend via the `AudioProvider` interface.\n- **60+ Commands** — Transport, tracks, regions, automation, plugins, MIDI, markers, ranges, export.\n- **20+ Built-in Plugins** — EQ, compressor, reverb, delay, saturation, de-esser, and more.\n- **Signal-based Events** — Type-safe reactive event system (Qt Signal/Slot pattern).\n- **Serialization** — Full session save/load with JSON snapshots.\n- **TypeScript-first** — Complete type definitions included.\n\n---\n\n## Quick Start\n\n```typescript\nimport {\n  AudioEngine,\n  Session,\n  Track,\n  TrackType,\n  CommandExecutor,\n  CommandType,\n} from \"@anaidev/daw-engine-core\";\n\n// 1. Implement AudioProvider interface for your platform\nclass MyAudioBackend implements AudioProvider {\n  // ... implement the interface methods\n}\n\n// 2. Initialize the engine with your backend\nconst engine = AudioEngine.getInstance(new MyAudioBackend());\n\n// 3. Work with the session directly\nconst track = engine.session.addTrack(\"Vocals\", TrackType.AUDIO);\n\n// 4. Or use the command system (with undo/redo support)\nawait CommandExecutor.getInstance().execute({\n  type: CommandType.ADD_TRACK,\n  payload: { name: \"Guitar\", trackType: \"audio\" },\n});\n```\n\n---\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────┐\n│  Your App                                        │\n│  (React, Electron, Node.js CLI, etc.)            │\n│                                                  │\n│  ┌─────────────┐  ┌────────────────────────────┐ │\n│  │ UI Layer    │  │ AudioProvider (impl)        │ │\n│  │ (optional)  │  │ e.g. Web Audio, PortAudio  │ │\n│  └──────┬──────┘  └─────────────┬──────────────┘ │\n├─────────┼───────────────────────┼────────────────┤\n│         ▼                       ▼                │\n│  ┌─────────────┐  ┌────────────────────────────┐ │\n│  │ Command     │  │ AudioEngine                │ │\n│  │ Executor    │  │ (session + backend)        │ │\n│  └──────┬──────┘  └────────────────────────────┘ │\n│         ▼                                        │\n│  ┌───────────────────────────────────────┐       │\n│  │ Domain Layer                          │       │\n│  │ Session → Track → Playlist → Region   │       │\n│  │ Automation, Plugins, MIDI, Markers    │       │\n│  └───────────────────────────────────────┘       │\n│                                                  │\n│  @anaidev/daw-engine-core                             │\n└──────────────────────────────────────────────────┘\n```\n\n---\n\n## Core Concepts\n\n### Session\n\nThe root container for a DAW project. Manages tracks, sources, markers, ranges, tempo, and transport state.\n\n```typescript\nimport { Session, TrackType } from \"@anaidev/daw-engine-core\";\n\nconst session = new Session(\"My Song\", undefined, 44100);\n\n// Tracks\nconst vocal = session.addTrack(\"Vocals\", TrackType.AUDIO);\nconst bass = session.addTrack(\"Bass\", TrackType.AUDIO);\nconst synth = session.addTrack(\"Synth\", TrackType.MIDI);\nconst reverb = session.addAuxTrack(\"Reverb Bus\");\n\n// Transport\nsession.setTempo(120);\nsession.setTimeSignature(4, 4);\n\n// Markers\nsession.addMarker(\"Chorus\", 44100 * 30); // at 30 seconds\n\n// Ranges\nconst loopRange = session.addRange(\"Loop A\", 44100 * 10, 44100 * 20);\nsession.setLoopRange(loopRange.id);\nsession.setLoopEnabled(true);\n\n// Serialization\nconst snapshot = session.toJSON();\nconst restored = Session.fromJSON(snapshot);\n```\n\n### Track\n\nRepresents an audio, MIDI, aux, bus, folder, or VCA track. Each track has a `Route` (signal chain) and a `Playlist` (region container).\n\n```typescript\nconst track = session.addTrack(\"Lead Guitar\", TrackType.AUDIO);\n\ntrack.setMute(false);\ntrack.setSolo(true);\ntrack.setArmed(true);\ntrack.setColor(\"#ff6b6b\");\ntrack.setMonitorMode(MonitorMode.AUTO);\n\n// React to changes\ntrack.muteChanged.connect((muted) => console.log(\"Mute:\", muted));\ntrack.soloChanged.connect((soloed) => console.log(\"Solo:\", soloed));\n```\n\n**Track Types:**\n\n| Type     | Description                                       |\n| -------- | ------------------------------------------------- |\n| `AUDIO`  | Standard audio track with region playback         |\n| `MIDI`   | MIDI track with note data and virtual instruments |\n| `AUX`    | Auxiliary bus for send effects (reverb, delay)    |\n| `BUS`    | Mix bus for subgroup routing                      |\n| `FOLDER` | Folder track for organizing child tracks          |\n| `VCA`    | VCA fader for linked level control                |\n\n### Region\n\nA segment of audio on the timeline, referencing a `Source`.\n\n```typescript\nimport { Region } from \"@anaidev/daw-engine-core\";\n\nconst region = new Region(\n  \"region-1\", // id\n  \"source-1\", // sourceId\n  0, // start (frames)\n  44100 * 10, // length (10 seconds at 44.1kHz)\n  0, // sourceStart\n  \"Vocal Take 1\", // name\n);\n\nregion.setFadeIn(4410); // 100ms fade in\nregion.setFadeOut(4410); // 100ms fade out\nregion.move(44100 * 5); // move to 5 seconds\nregion.resize(44100 * 8); // resize to 8 seconds\n```\n\n### AudioEngine\n\nCentral controller connecting the session to an audio backend. Uses the singleton pattern with dependency injection.\n\n```typescript\nimport { AudioEngine, AudioProvider } from \"@anaidev/daw-engine-core\";\n\n// Initialize with your backend implementation\nconst engine = AudioEngine.getInstance(myBackend);\nawait engine.initialize();\n\n// Transport\nawait engine.start();\nengine.pause();\nengine.seek(10.5); // seek to 10.5 seconds\nengine.stop();\n\n// Metering\nconst meter = engine.getMeterData(\"track-1\");\nconsole.log(\"Peak:\", meter.peak, \"RMS:\", meter.rms);\n\n// Export\nawait engine.exportAudio(engine.getExportConfig(), engine.getExportStatus());\n\n// Swap backend at runtime\nengine.setBackend(new DifferentBackend());\n```\n\n### AudioProvider Interface\n\nImplement this interface to connect @anaidev/daw-engine-core to any audio system.\n\n```typescript\nimport { AudioProvider } from \"@anaidev/daw-engine-core\";\n\nclass WebAudioBackend implements AudioProvider {\n  async initialize(): Promise<void> {\n    /* ... */\n  }\n\n  // Transport\n  start(): void {\n    /* ... */\n  }\n  stop(): void {\n    /* ... */\n  }\n  pause(): void {\n    /* ... */\n  }\n  seek(time: number): void {\n    /* ... */\n  }\n\n  // Track management\n  createTrack(trackId, name, inputId, outputId): void {\n    /* ... */\n  }\n  deleteTrack(trackId): void {\n    /* ... */\n  }\n\n  // Region scheduling\n  scheduleRegion(trackId, region): void {\n    /* ... */\n  }\n  updateRegions(trackId, regions): void {\n    /* ... */\n  }\n  removeRegion(trackId, regionId): void {\n    /* ... */\n  }\n\n  // Metering\n  getMeterData(trackId): MeterData {\n    /* ... */\n  }\n  getMasterMeterData(): MeterData {\n    /* ... */\n  }\n\n  // ... and more (see full interface in source)\n}\n```\n\n**Included backend examples (in the drop.ai app, not in this package):**\n\n| Backend                 | Environment | Description                   |\n| ----------------------- | ----------- | ----------------------------- |\n| `ToneAudioProvider`     | Browser     | Tone.js + Web Audio API       |\n| `HeadlessAudioProvider` | Node.js     | No-op backend for CLI/testing |\n| `MockAudioProvider`     | Test        | Mock backend for unit tests   |\n\n---\n\n## Command System\n\nAll state mutations can go through the command system, providing validation (via Zod), handler routing, and undo/redo support.\n\n### Executing Commands\n\n```typescript\nimport { CommandExecutor, CommandType } from \"@anaidev/daw-engine-core\";\n\nconst executor = CommandExecutor.getInstance();\n\n// Add a track\nawait executor.execute({\n  type: CommandType.ADD_TRACK,\n  payload: { name: \"Vocals\", trackType: \"audio\" },\n});\n\n// Set volume\nawait executor.execute({\n  type: CommandType.SET_VOLUME,\n  payload: { trackId: \"track-1\", volume: 0.75 },\n});\n\n// Split region at playhead\nawait executor.execute({\n  type: CommandType.SPLIT_AT_PLAYHEAD,\n  payload: { trackId: \"track-1\", frame: 44100 * 15 },\n});\n\n// Add a plugin\nawait executor.execute({\n  type: CommandType.ADD_PLUGIN,\n  payload: { trackId: \"track-1\", pluginId: \"internal-eq6\" },\n});\n```\n\n### Undo / Redo\n\n```typescript\nconst history = executor.history;\n\nawait history.undo();\nawait history.redo();\nawait history.undoMultiple(3); // undo 3 steps\n\nconsole.log(history.canUndo); // true\nconsole.log(history.nextUndoLabel); // \"Add Track\"\n\n// Transaction: group multiple commands into one undo step\nhistory.beginTransaction(\"Move and resize\");\n// ... execute multiple commands ...\nawait history.commitTransaction();\n```\n\n### Registering Custom Handlers\n\n```typescript\nimport { CommandHandler, CommandResult } from \"@anaidev/daw-engine-core\";\n\nclass MyCustomHandler implements CommandHandler {\n  readonly handledTypes = [\"MY_CUSTOM_COMMAND\"];\n\n  async execute(type: string, payload: any): Promise<CommandResult> {\n    // your logic here\n    return { success: true };\n  }\n}\n\nCommandExecutor.getInstance().registerHandler(new MyCustomHandler());\n```\n\n### Command Types\n\n**Transport:** `PLAY`, `PAUSE`, `STOP`, `SEEK`, `SET_TEMPO`, `SET_TIME_SIGNATURE`, `TOGGLE_METRONOME`, `START_RECORDING`, `STOP_RECORDING`\n\n**Tracks:** `ADD_TRACK`, `REMOVE_TRACK`, `SET_VOLUME`, `SET_PAN`, `MUTE_TRACK`, `SOLO_TRACK`, `ARM_TRACK`, `SET_TRACK_MONITOR`\n\n**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`\n\n**Automation:** `ADD_AUTOMATION`, `MOVE_AUTOMATION_POINT`, `REMOVE_AUTOMATION_POINT`\n\n**Plugins:** `ADD_PLUGIN`, `REMOVE_PLUGIN`, `SET_PLUGIN_PARAMETER`\n\n**Ranges:** `ADD_RANGE`, `REMOVE_RANGE`, `SET_RANGE`, `SET_LOOP_RANGE`, `SET_PUNCH_RANGE`, `TOGGLE_LOOP`\n\n**Markers:** `ADD_MARKER`, `REMOVE_MARKER`, `MOVE_MARKER`\n\n**IO/Routing:** `CONNECT_IO`, `DISCONNECT_IO`, `ADD_SEND_BUS`, `REMOVE_SEND_BUS`, `SET_SEND_LEVEL`\n\n**Session:** `EXPORT`, `NEW_SESSION`, `LOAD_SESSION`, `SAVE_SESSION`, `SAVE_SNAPSHOT`\n\n**History:** `UNDO`, `REDO`, `SELECTION_UNDO`, `SELECTION_REDO`\n\n---\n\n## Plugins\n\n20+ built-in audio effect plugins, managed by `PluginManager`.\n\n```typescript\nimport { PluginManager } from \"@anaidev/daw-engine-core\";\n\nconst manager = PluginManager.getInstance();\n\n// List all available plugins\nconst plugins = manager.getAvailablePlugins();\nplugins.forEach((p) => console.log(p.id, p.name));\n\n// Create a plugin instance\nconst eq = manager.createPlugin(\"internal-eq6\");\neq.setParameter(\"band1-freq\", 100);\neq.setParameter(\"band1-gain\", 3.0);\n\n// Get/set full state (presets)\nconst state = eq.getState();\neq.setState(state);\n\n// React to parameter changes\neq.parameterChanged.connect(({ id, value }) => {\n  console.log(`${id} changed to ${value}`);\n});\n```\n\n### Available Plugins\n\n| ID                        | Name                 | Description                 |\n| ------------------------- | -------------------- | --------------------------- |\n| `internal-eq6`            | Parametric EQ        | 6-band parametric equalizer |\n| `internal-compressor`     | Compressor           | Dynamics compressor         |\n| `internal-multiband-comp` | Multiband Compressor | Multi-band dynamics         |\n| `internal-expander`       | Expander             | Expander/gate               |\n| `internal-gate`           | Gate                 | Noise gate                  |\n| `internal-deesser`        | De-Esser             | Sibilance reduction         |\n| `internal-reverb`         | Reverb               | Algorithmic reverb          |\n| `internal-convolver`      | Convolution Reverb   | IR-based reverb             |\n| `internal-delay`          | Delay                | Simple delay                |\n| `internal-sync-delay`     | Sync Delay           | BPM-synced delay            |\n| `internal-chorus`         | Chorus               | Chorus effect               |\n| `internal-phaser`         | Phaser               | Phaser effect               |\n| `internal-tremolo`        | Tremolo              | Tremolo effect              |\n| `internal-vibrato`        | Vibrato              | Vibrato effect              |\n| `internal-autopan`        | Auto Pan             | Automatic panning           |\n| `internal-distortion`     | Distortion           | Distortion/overdrive        |\n| `internal-tape-sat`       | Tape Saturation      | Analog tape emulation       |\n| `internal-filter`         | Filter               | Multi-mode filter           |\n| `internal-eq3`            | 3-Band EQ            | Simple 3-band EQ            |\n| `internal-gain`           | Gain                 | Utility gain                |\n\n---\n\n## Automation\n\nPer-parameter automation with multiple recording modes.\n\n```typescript\nimport { AutomationList, AutomationMode } from \"@anaidev/daw-engine-core\";\n\nconst automation = new AutomationList();\n\n// Add points\nautomation.addPoint(0, 0.5); // value 0.5 at time 0\nautomation.addPoint(2.0, 1.0); // value 1.0 at time 2s\nautomation.addPoint(4.0, 0.0); // value 0.0 at time 4s\n\n// Read interpolated value\nconst value = automation.getValueAt(1.0); // ~0.75 (linear interpolation)\n\n// Modes\nautomation.mode = AutomationMode.READ; // playback only\nautomation.mode = AutomationMode.WRITE; // overwrite\nautomation.mode = AutomationMode.TOUCH; // write while touching, snap back on release\nautomation.mode = AutomationMode.LATCH; // write while touching, hold last value\n\n// Range operations\nconst copied = automation.copy(1.0, 3.0);\nautomation.paste(copied, 5.0);\nautomation.eraseRange(1.0, 3.0);\n```\n\n---\n\n## Signal (Event System)\n\nType-safe event emitter inspired by Qt's Signal/Slot pattern. Used throughout the domain layer.\n\n```typescript\nimport { Signal } from \"@anaidev/daw-engine-core\";\n\nconst signal = new Signal<number>();\n\n// Subscribe\nconst sub = signal.connect((value) => {\n  console.log(\"Received:\", value);\n});\n\n// Emit\nsignal.emit(42); // logs \"Received: 42\"\n\n// Unsubscribe\nsub.dispose();\n\n// Or disconnect by reference\nconst handler = (v: number) => console.log(v);\nsignal.connect(handler);\nsignal.disconnect(handler);\n\n// Clear all listeners\nsignal.clear();\n```\n\n### Common Signals\n\n```typescript\n// Session\nsession.trackAdded.connect((track) => {\n  /* ... */\n});\nsession.trackRemoved.connect((trackId) => {\n  /* ... */\n});\nsession.tempoChanged.connect((bpm) => {\n  /* ... */\n});\nsession.playingChanged.connect((isPlaying) => {\n  /* ... */\n});\nsession.selectionChanged.connect((selectedIds) => {\n  /* ... */\n});\nsession.markerAdded.connect((marker) => {\n  /* ... */\n});\n\n// Track\ntrack.muteChanged.connect((muted) => {\n  /* ... */\n});\ntrack.soloChanged.connect((soloed) => {\n  /* ... */\n});\ntrack.armChanged.connect((armed) => {\n  /* ... */\n});\n\n// CommandExecutor\nexecutor.commandExecuted.connect(({ type, payload }) => {\n  /* ... */\n});\n\n// CommandHistory\nhistory.historyChanged.connect(() => {\n  /* ... */\n});\n```\n\n---\n\n## Actions & Key Bindings\n\nMap keyboard shortcuts to commands.\n\n```typescript\nimport { ActionRegistry, ActionCategory } from \"@anaidev/daw-engine-core\";\n\nconst registry = ActionRegistry.getInstance();\n\n// Register default actions (typically done at app bootstrap)\nregistry.registerDefaults([\n  {\n    id: \"transport.play\",\n    label: \"Play/Pause\",\n    category: ActionCategory.TRANSPORT,\n    defaultKey: \"Space\",\n    commandFactory: () => ({ type: CommandType.PLAY, payload: {} }),\n  },\n  {\n    id: \"edit.undo\",\n    label: \"Undo\",\n    category: ActionCategory.EDIT,\n    defaultKey: \"Ctrl+Z\",\n    commandFactory: () => ({ type: CommandType.UNDO, payload: {} }),\n  },\n]);\n\n// Execute by action ID\nawait registry.execute(\"transport.play\");\n\n// Query\nconst actions = registry.getActionsByCategory();\nconst key = registry.getEffectiveKey(\"transport.play\"); // 'Space'\n```\n\n### Custom Key Bindings\n\n```typescript\nimport { KeyBindings } from \"@anaidev/daw-engine-core\";\n\nconst bindings = KeyBindings.getInstance();\n\nbindings.setBinding(\"transport.play\", \"Enter\");\nbindings.getBinding(\"transport.play\"); // 'Enter'\nbindings.removeBinding(\"transport.play\"); // back to default\nbindings.resetToDefaults();\n```\n\n---\n\n## Preferences\n\nPersistent settings with defaults.\n\n```typescript\nimport { Preferences } from \"@anaidev/daw-engine-core\";\n\nconst prefs = Preferences.getInstance();\n\nprefs.set(\"sampleRate\", 48000);\nprefs.set(\"audioBufferSize\", 256);\nprefs.set(\"theme\", \"dark\");\nprefs.set(\"snapToGrid\", true);\nprefs.set(\"historyDepth\", 100);\n\nconst sr = prefs.get(\"sampleRate\"); // 48000\n\n// React to changes\nprefs.preferenceChanged.connect(() => {\n  console.log(\"Settings updated\");\n});\n\n// Reset\nprefs.resetToDefaults();\n```\n\n**Available Keys:** `audioBufferSize`, `sampleRate`, `theme`, `autoSaveInterval`, `snapToGrid`, `gridSubdivision`, `meterType`, `showMinimap`, `followPlayhead`, `countInBars`, `historyDepth`, `saveHistory`, `saveHistoryDepth`\n\n---\n\n## Storage\n\nSession persistence via IndexedDB (browser) or localStorage fallback.\n\n```typescript\nimport { SessionStorage } from \"@anaidev/daw-engine-core\";\n\nconst storage = SessionStorage.getInstance();\n\n// Save\nawait storage.saveSession(session);\n\n// List\nconst sessions = await storage.listSessions();\n// [{ id: '...', name: 'My Song', modified: Date }]\n\n// Load\nconst snapshot = await storage.loadSession(sessions[0].id);\nconst restored = Session.fromJSON(snapshot);\n\n// Snapshots (named save points)\nconst snapId = await storage.saveSnapshot(\n  session.id,\n  \"Before mixing\",\n  session.toJSON(),\n);\nconst snap = await storage.loadSnapshot(snapId);\n\n// Delete\nawait storage.deleteSession(session.id);\n```\n\n---\n\n## Processing Chain\n\nEach track has a `Route` containing an ordered chain of processors.\n\n```typescript\nimport {\n  GainProcessor,\n  PanProcessor,\n  PluginInsert,\n  SendProcessor,\n  MeterProcessor,\n} from \"@anaidev/daw-engine-core\";\n\n// Processor types available in the chain:\n// GainProcessor  — Fader / Trim level control\n// PanProcessor   — Stereo panning and width\n// PluginInsert   — Plugin effect slot\n// SendProcessor  — Pre/Post fader send to aux bus\n// MeterProcessor — Peak/RMS metering\n```\n\n---\n\n## Usage Examples\n\n### Node.js CLI\n\n```typescript\nimport {\n  AudioEngine,\n  Session,\n  CommandExecutor,\n  CommandType,\n} from \"@anaidev/daw-engine-core\";\n\n// Headless backend (no audio output)\nclass HeadlessBackend implements AudioProvider {\n  async initialize() {}\n  start() {}\n  stop() {}\n  // ... no-op implementations\n}\n\nconst engine = AudioEngine.getInstance(new HeadlessBackend());\nconst session = engine.session;\n\nsession.addTrack(\"Track 1\", TrackType.AUDIO);\nconsole.log(\n  \"Tracks:\",\n  session.tracks.map((t) => t.name),\n);\n\nconst snapshot = session.toJSON();\n// Save to file, process offline, etc.\n```\n\n### Electron App\n\n```typescript\nimport { AudioEngine, AudioProvider } from \"@anaidev/daw-engine-core\";\n\nclass ElectronAudioBackend implements AudioProvider {\n  // Use PortAudio or native audio APIs\n  // ...\n}\n\nconst engine = AudioEngine.getInstance(new ElectronAudioBackend());\nawait engine.initialize();\n```\n\n### React Integration\n\n```typescript\nimport { useEffect, useState } from \"react\";\nimport { AudioEngine, Session } from \"@anaidev/daw-engine-core\";\n\nfunction useDAWEngine(backend: AudioProvider) {\n  const [engine] = useState(() => AudioEngine.getInstance(backend));\n\n  useEffect(() => {\n    const sub = engine.session.tempoChanged.connect((bpm) => {\n      // update React state\n    });\n    return () => sub.dispose();\n  }, [engine]);\n\n  return engine;\n}\n```\n\n---\n\n## API Reference\n\n### Singletons\n\n| Class             | Access                  | Description                             |\n| ----------------- | ----------------------- | --------------------------------------- |\n| `AudioEngine`     | `getInstance(backend?)` | Audio engine with session and transport |\n| `CommandExecutor` | `getInstance()`         | Command dispatch with validation        |\n| `PluginManager`   | `getInstance()`         | Plugin factory                          |\n| `ActionRegistry`  | `getInstance()`         | Keyboard shortcut ↔ command mapping    |\n| `Preferences`     | `getInstance()`         | User settings                           |\n| `KeyBindings`     | `getInstance()`         | Custom key binding overrides            |\n| `SessionStorage`  | `getInstance()`         | Session persistence                     |\n\n### Domain Models\n\n| Class             | Description                                            |\n| ----------------- | ------------------------------------------------------ |\n| `Session`         | Project root — tracks, sources, markers, ranges, tempo |\n| `Track`           | Audio/MIDI/AUX/BUS/FOLDER/VCA track                    |\n| `Region`          | Audio segment on the timeline                          |\n| `Playlist`        | Region collection within a track                       |\n| `Source`          | Audio file reference (URL, duration, sampleRate)       |\n| `Range`           | Loop/punch/selection range                             |\n| `Marker`          | Timeline marker (position + name)                      |\n| `MidiNote`        | Single MIDI note event                                 |\n| `MidiRegion`      | MIDI note collection on the timeline                   |\n| `SendBus`         | Pre/post fader send bus                                |\n| `Route`           | Signal chain (input → processors → output)             |\n| `TempoMap`        | BPM change events over time                            |\n| `GridSettings`    | Grid type and snap mode                                |\n| `CrossfadeEngine` | Automatic crossfade calculation                        |\n| `MixerScene`      | Mixer snapshot save/restore                            |\n| `TrackGroup`      | Track grouping for linked control                      |\n\n### Type Definitions\n\n```typescript\ntype FrameCount = number; // sample frame position\ntype SampleRate = number; // e.g. 44100, 48000, 96000\ntype Gain = number; // 0.0 to 1.0+\ntype DB = number; // decibels\n\ntype TrackId = string;\ntype RegionId = string;\ntype SourceId = string;\ntype RangeId = string;\ntype ProcessorId = string;\ntype RouteId = string;\n```\n\n---\n\n## Dependencies\n\n| Package        | Type            | Description                |\n| -------------- | --------------- | -------------------------- |\n| `zod`          | runtime         | Command payload validation |\n| `lamejs`       | dependency      | MP3 export support         |\n| `soundtouchjs` | peer (optional) | Time-stretch / pitch-shift |\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-bfa0ee85a9a11fcfb2ed0a609d1be6ef"}