# Tasks: enterprise-browser-audio-controllers **Change ID**: enterprise-browser-audio-controllers **Package**: `@suaveplan/audio-controllers` **Target path**: `browser/audio/audio-controllers` **Prerequisite packages on Verdaccio**: `@suaveplan/audio-engine`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events` --- ## 1. Scaffold - [ ] Create `browser/audio/audio-controllers/` directory tree per layout in `proposal.md`. - [ ] Write `package.json` at version `0.1.0`: - `"sideEffects": false` - `exports`: top-level `"."` plus subpaths for each controller and sequencer - `dependencies`: `@suaveplan/audio-engine workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/events workspace:^`, `standardized-audio-context catalog:browser`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `@suaveplan/testing workspace:^`, `@playwright/test catalog:testing` - [ ] Write `tsconfig.json` and `vitest.config.ts` (pool: forks). --- ## 2. Error codes (`src/error-codes.ts`) - [ ] Define `MidiControllerErrorCode`: `MIDI_UNAVAILABLE`, `MIDI_PERMISSION_DENIED`, `MIDI_DEVICE_DISCONNECTED`, `MIDI_SYSEX_REJECTED`, `CONTROLLER_PRESET_INVALID`, `SAMPLE_LOADER_FAILED`. - [ ] Export `registerMidiControllerErrorCodes()` and call eagerly. --- ## 3. Base class (`src/base/midi-controller-plugin/`) - [ ] Implement abstract `MidiControllerPlugin extends AudioPlugin`: - `requestMIDIAccess(sysex?: boolean)`: calls `navigator.requestMIDIAccess`; throws typed `MIDI_UNAVAILABLE` / `MIDI_PERMISSION_DENIED` on failure. - `onStateChange(event: MIDIConnectionEvent)`: detects disconnect / reconnect, emits typed events, auto-rebinds. - `flushLEDs(updates: LEDUpdate[])`: diff engine with per-frame byte budget. - `defineMappings(mappings: CCMapping[])`: CC-learn DSL storage. - Protected `EventEmitter` member — all subclasses use it. - [ ] Write `midi-controller-plugin.test.ts`: permission flow, hot-plug disconnect + reconnect, LED flush budget. - [ ] Write `midi-controller-plugin.md`. --- ## 4. Shared sequencer (`src/sequencer/sequencer/`) - [ ] Implement `Sequencer`: audio-clock-synced step grid, tempo (BPM), step on/off, playback start/stop/reset. - [ ] Clock source: inject via constructor (accepts `AudioContext` for `currentTime`-based scheduling, not `setInterval`). - [ ] Write `sequencer.test.ts`, `sequencer.md`. --- ## 5. KontrolS88Plugin (`src/plugins/kontrol-s88/`) - [ ] `mapping.ts`: CC/note-number → parameter map, type-safe DSL. - [ ] `state.ts`: `KeyState[]`, `TransportState` machine. - [ ] `arpeggio.ts`: `ArpMode` implementations (up/down/random/chord), clock-synced via shared `Sequencer`. - [ ] `scale.ts`: `ScaleMode` quantizer (major, minor, chromatic, etc.), chord voicing. - [ ] `led.ts`: per-key LED feedback, batch flush. - [ ] `preset.ts`: `KontrolS88Preset` Zod schema, serialize/deserialize. - [ ] `kontrol-s88.ts`: plugin orchestrator, hooks into `MidiControllerPlugin` base. - [ ] `kontrol-s88.test.ts`: MIDI byte → state, state → MIDI out, velocity curve, scale transform, arpeggio clock, preset round-trip, hot-plug disconnect + reconnect. - [ ] `kontrol-s88.md`. --- ## 6. MaschinePlugin (`src/plugins/maschine/`) - [ ] `mapping.ts`: pad/CC/button mapping. - [ ] `state.ts`: pad grid state, group states. - [ ] `sequencer.ts`: 16-step sequencer per pad using shared `Sequencer`. - [ ] `sample-loader.ts`: real `SampleLoader` interface — no placeholder; loads via `AudioContext.decodeAudioData`. - [ ] `preset.ts`: `MaschinePreset` Zod schema. - [ ] `maschine.ts`: plugin orchestrator. Event system wired via `EventEmitter` — no placeholder comments. - [ ] `maschine.test.ts`: pad velocity, step grid, sample load, preset round-trip. - [ ] `maschine.md`. --- ## 7. TraktorS4Plugin (`src/plugins/traktor-s4/`) - [ ] `mapping.ts`: CC/button mapping per channel. - [ ] `deck.ts`: `DeckState`, load/play/pause/cue/sync, pitch/tempo. - [ ] `mixer.ts`: channel volumes, EQ per channel, master gain. - [ ] `led.ts`: LED ring/button feedback. - [ ] `preset.ts`: `TraktorS4Preset` Zod schema. - [ ] `traktor-s4.ts`: plugin orchestrator. Event system wired — no placeholder comments. - [ ] `traktor-s4.test.ts`: crossfader, deck sync, mixer state, preset round-trip. - [ ] `traktor-s4.md`. --- ## 8. Learn mode (`src/learn/learn-mode/`) - [ ] Implement `LearnMode`: listens for MIDI CC events, stores custom remapping, persists via injected `StorageAdapter`. - [ ] Default adapter: in-memory; inject `@suaveplan/storage-browser` for durable persistence. - [ ] Write `learn-mode.test.ts`, `learn-mode.md`. --- ## 9. SysEx fuzz test (`tests/integration.test.ts`) - [ ] Write a property-based test (fast-check) that feeds malformed SysEx byte arrays to `onMIDIMessage` on each controller and verifies the plugin does not crash and emits a typed `MIDI_SYSEX_REJECTED` event or safely ignores. --- ## 10. Playwright E2E (`tests/e2e/`) - [ ] Write E2E spec using a virtual MIDI device (Web MIDI API mock via Playwright page context) for each controller: - KontrolS88: MIDI note-on → `KeyState` update, arpeggio output, LED feedback. - Maschine: pad velocity → step sequencer trigger. - TraktorS4: crossfader CC → mixer state. - [ ] Verify hot-plug: simulate device disconnect + reconnect event. --- ## 11. OTel metrics - [ ] Wire in `MidiControllerPlugin` base: - Counter `midi.messages_in_total{controller}`, `midi.messages_out_total{controller}` - Counter `led.frames_total{controller}` - Histogram `midi.input_to_audio_latency_ms{controller}` --- ## 12. Docs - [ ] Write `.md` for every exported module (≥200 words, API reference, examples). - [ ] Write `README.md` with controller matrix table (every supported CC/note/pad per device), preset-pack list, MIDI permission guidance. --- ## 13. Verify and publish - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/audio-controllers` — green. - [ ] `bunx turbo test:coverage --filter=@suaveplan/audio-controllers` — 100%. - [ ] `bun run docs:check --filter=@suaveplan/audio-controllers` — zero errors. - [ ] No `TODO`, placeholder, `any`, `ts-ignore`, `vi.mock`, `.skip` in `src/`. - [ ] Playwright E2E green for all three controllers. - [ ] `bun scripts/publish.ts --package @suaveplan/audio-controllers`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-audio-controllers/`.