Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,208 @@
# OpenSpec Change: enterprise-audio-controllers
- **Change ID**: enterprise-audio-controllers
- **Package**: `@suaveplan/audio-controllers`
- **Category**: browser
- **Target path**: `packages/audio/audio-controllers`
- **Status**: PROPOSED
- **Date**: 2026-05-14
- **Design**: `./design.md`
- **Spec delta**: `./specs/audio-controllers/spec.md`
---
## Summary
Deliver `@suaveplan/audio-controllers` on the genesis branch from scratch at enterprise quality. MIDI hardware controller integrations for the genesis monorepo. Built on `@suaveplan/audio-core` and `@suaveplan/audio-transport` for audio-clock-synced sequencing. Provides a universal `MidiControllerPlugin` base class with hot-plug support, LED feedback, CC-mapping DSL, and learn mode.
Controllers run in the browser (Web MIDI API) but their sequencer/arpeggio output feeds into the universal `Transport` and `TimelineEngine`, so patterns can be rendered offline or on the server.
---
## Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build. No prior source, no test results, no coverage data. The old `enterprise-browser-audio-controllers` was browser-only and not tied to the universal transport.
---
## Parity Checklist (vs upstream `../suaveplan/packages/browser/audio-controllers/`)
| Capability | Upstream | Migrated | Notes |
|---|:---:|:---:|---|
| `KontrolS88Plugin` (88-key weighted keyboard) | ✅ | ✅ | Same surface; now consumes `audio-transport` for scale-aware arpeggios instead of `setInterval`. |
| Scale modes (`major`, `minor`, `chromatic`, …) | ✅ | ✅ | Unchanged enum. |
| Arpeggiator | ✅ | ⬆️ | Now transport-synced via `audio-transport` `Transport.schedule`; upstream used `setInterval`. |
| `KontrolS88Preset` save / load | ✅ | ✅ | Now Zod-validated through the package's own preset schemas. |
| Pitch-bend / mod-wheel CC mapping | ✅ | ✅ | Same mapping; routed through the new `bindParameter` helper for FX surfaces. |
| LED feedback / `flushLEDs` | ✅ | ✅ | Same surface; batched per requirement "MIDI input and output mapping". |
| `MaschinePlugin` (16-pad + step sequencer + sample slots) | ✅ | ✅ | Step sequencer now drives off `Sequencer`/`Transport`; sample loading accepts `AbortSignal`. |
| `TraktorS4Plugin` (4-channel DJ controller) | ✅ | ✅ | Same surface; deck-sync now reads transport tempo from `ChainContext.ambient.transport` when hosted in a chain. |
| Web MIDI access via `navigator.requestMIDIAccess` | ✅ | ⬆️ | Now reached only through the injected `MidiAccessAdapter` seam; tests inject fake-device fixtures rather than mocking the platform. |
| Connection-state FSM | ⚠ ad-hoc | ⬆️ | Now `@suaveplan/fsm`-driven with explicit `disconnected/connecting/connected/error` and graceful state recovery on reconnect. |
| Learn mode for CC mapping | – | ⬆️ | Genesis addition. |
| Plugin base class (`AudioPlugin`) | ✅ via `audio-engine` | ⬆️ | Replaced by `MidiControllerPlugin` base whose plugins integrate with `@suaveplan/audio-plugins-fx`'s `AudioFxPlugin` for parameter binding via `bindParameter`. |
| `*.types.ts` files duplicating implementation declarations | ⚠ smell | ⬆️ | Consolidated; one types file per feature module. |
| Unit tests / coverage | ⚠ one `.spec.ts` only | ⬆️ | 100/100/100/100 across every module with real fake-device fixtures (no mocks). |
| Storybook coverage | – | – | n/a — controllers are non-visual. |
No 🚫 rows.
---
## Available workspace deps on genesis
| Package | Role |
|---|---|
| `@suaveplan/audio-core` (`workspace:^`) | `AudioDocument`, `BlockProcessor` |
| `@suaveplan/audio-transport` (`workspace:^`) | `Transport`, `TransportTime` |
| `@suaveplan/events` (`workspace:^`) | Typed event bus for controller events |
| `@suaveplan/error` (`workspace:^`) | `AudioControllersError` base class; `AUDIO_CONTROLLER.*` codes |
| `@suaveplan/types` (`workspace:^`) | `LoggerLike` |
| `@suaveplan/opentelemetry` (`workspace:^`) | OTel spans, counters, histograms |
| `zod` (`catalog:forms`) | Zod schemas for option types |
Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata` (all `catalog:testing`).
---
## Public API
### Core types
```ts
abstract class MidiControllerPlugin {
readonly metadata: ControllerMetadata
async requestAccess(sysex?: boolean): Promise<MIDIAccess>
onStateChange(event: MIDIConnectionEvent): void
flushLEDs(updates: LEDUpdate[]): void
defineMappings(mappings: CCMapping[]): void
enterLearnMode(): void
exitLearnMode(): void
on<K extends keyof ControllerEventMap>(event: K, listener: ControllerEventMap[K]): void
off<K extends keyof ControllerEventMap>(event: K, listener: ControllerEventMap[K]): void
readonly sequencer: Sequencer
initialize(): Promise<void>
destroy(): Promise<void>
}
class Sequencer {
constructor(transport: Transport)
setTempo(bpm: number): void
setSteps(steps: boolean[]): void
setStep(index: number, active: boolean): void
start(): void
stop(): void
reset(): void
onStep(index: number, callback: () => void): void
}
class KontrolS88Plugin extends MidiControllerPlugin {
setScale(mode: ScaleMode): void
setArpMode(mode: ArpMode): void
setPitchBend(value: number): void
setModWheel(value: number): void
sendLED(keyIndex: number, color: LEDColor): void
}
class MaschinePlugin extends MidiControllerPlugin {
setPadVelocity(padIndex: number, velocity: number): void
setStep(padIndex: number, stepIndex: number, active: boolean): void
loadSample(slotIndex: number, sampleId: string): Promise<void>
}
class TraktorS4Plugin extends MidiControllerPlugin {
loadDeck(deckIndex: number, track: DeckTrack): void
setCrossfader(value: number): void
setChannelVolume(channel: number, value: number): void
}
```
---
## New additions for genesis
1. **Universal sequencer base** — `Sequencer` uses `@suaveplan/audio-transport` for sample-accurate scheduling, not `setInterval`.
2. **Transport-synced arpeggiator** — arpeggio patterns are `Transport` event subscribers, renderable offline.
3. **Hot-plug support** — `onStateChange` handles connect/disconnect with graceful state recovery.
4. **CC mapping DSL** — declarative control-change to parameter mapping with learn mode.
5. **LED feedback** — bidirectional MIDI for controller LED/state updates.
6. **OTel instrumentation** — spans for MIDI message handling, sequencer step timing.
7. **Property-based tests** — random step patterns → correct sequence, random CC values → mapped parameters.
8. **Benchmark suite** — MIDI message throughput, sequencer scheduling latency.
---
## File layout
```text
packages/audio/audio-controllers/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
base/
midi-controller-plugin.ts
midi-controller-plugin.md
midi-controller-plugin.types.ts
midi-controller-plugin.test.ts
index.ts
sequencer/
sequencer.ts
sequencer.md
sequencer.types.ts
sequencer.test.ts
index.ts
arpeggiator/
arpeggiator.ts
arpeggiator.md
arpeggiator.test.ts
index.ts
learn/
learn-mode.ts
learn-mode.md
learn-mode.test.ts
index.ts
plugins/
kontrol-s88/
kontrol-s88.ts, kontrol-s88.md, kontrol-s88.test.ts
mapping.ts, state.ts, scale.ts, led.ts, preset.ts
index.ts
maschine/
maschine.ts, maschine.md, maschine.test.ts
mapping.ts, state.ts, sample-loader.ts, preset.ts
index.ts
traktor-s4/
traktor-s4.ts, traktor-s4.md, traktor-s4.test.ts
mapping.ts, deck.ts, mixer.ts, led.ts, preset.ts
index.ts
__benchmarks__/
midi.bench.ts
tests/
integration.test.ts
e2e/
kontrol-s88.e2e.test.ts
maschine.e2e.test.ts
traktor-s4.e2e.test.ts
```
---
## Impact
**Breaking changes**: none — fresh build, package does not yet exist on genesis.
**Prerequisites**: `@suaveplan/audio-core`, `@suaveplan/audio-transport`, `@suaveplan/events`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/opentelemetry`, `@suaveplan/fsm` published to Verdaccio.
### Affected dependents
No dependents in this batch (verified by `bunx turbo ls --filter=...@suaveplan/audio-controllers`). `@suaveplan/audio-controllers` is a leaf integration package — it is consumed directly by application code (`@suaveplan/react-audio*`, game audio surfaces), none of which exist on genesis in this 13-change audio batch. Each future consumer is created against this package's spec delta, not retrofitted.
Once landed, any subsequent change to this package's public surface MUST run `bunx turbo test --filter=...@suaveplan/audio-controllers` per `openspec/AGENTS.md` §13 step 10.