Files
suaveplan/openspec/archive/2026-05-20-enterprise-react-audio-midi/specs/react-audio/spec.md
2026-05-27 23:29:53 +01:00

2.2 KiB

Capability Spec Delta: react-audio (enterprise-react-audio-midi)

Package: @suaveplan/react-audio Status: PROPOSED — Phase 3 of 3 (MIDI learn-mode) Blocked on: Phases 1 and 2 shipping first.

Every requirement carries **Verified by:**.

ADDED Requirements

Requirement: MidiControllerSetup learn-mode panel

<MidiControllerSetup> SHALL render the connected controllers from the provider's MidiControllerRegistry (sourced via @suaveplan/audio-controllers) and expose a learn-mode UI: the user selects a target parameter on a plugin, presses a control on the hardware, and the panel calls bindParameter(plugin, paramId, capturedSource, { smoothingMs }) from @suaveplan/audio-controllers. Captured bindings SHALL be persisted via the provider's preset store (the same store used by <PresetManager>) and re-bound on next mount. An Unbind button SHALL invoke the unsubscribe function returned by bindParameter. The package SHALL also export the useMidiController(controllerId) hook returning the controller instance + a learn(target) method.

Scenario: learn captures the next CC and binds it

  • WHEN a user selects eq.lowShelfGain as the target and the fake-device fixture emits CC 1/7 = 64
  • THEN bindParameter(eq, 'lowShelfGain', { type: 'cc', channel: 1, number: 7 }) is called and the panel shows the binding

Scenario: unbind removes the binding

  • WHEN a user clicks Unbind on an active binding
  • THEN subsequent CC events for that source no longer call setParameter on the plugin

Scenario: useMidiController hook subscribes to connection-state changes

  • WHEN the controller transitions disconnected → connecting → connected
  • THEN the component using useMidiController(controllerId) re-renders once per transition with the new state

Verified by: src/components/midi-controller-setup/midi-controller-setup.test.tsx::"learn captures the next CC and binds it" AND src/components/midi-controller-setup/midi-controller-setup.test.tsx::"unbind removes the binding" AND src/hooks/use-midi-controller/use-midi-controller.test.tsx::"re-renders on connection-state transitions"