139 lines
6.4 KiB
Markdown
139 lines
6.4 KiB
Markdown
# 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<MidiControllerEventMap>` 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/`.
|