150 lines
6.5 KiB
Markdown
150 lines
6.5 KiB
Markdown
# OpenSpec Change: enterprise-browser-audio-plugins-fx
|
|
|
|
- **Change ID**: enterprise-browser-audio-plugins-fx
|
|
- **Package**: `@suaveplan/audio-plugins-fx`
|
|
- **Category**: browser
|
|
- **Target path**: `browser/audio/audio-plugins-fx`
|
|
- **Status**: IN PROGRESS
|
|
- **Date**: 2026-04-24
|
|
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/audio-plugins-fx.md`
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Deliver `@suaveplan/audio-plugins-fx` on the genesis branch from scratch at enterprise quality. The package ships twelve `AudioPlugin` subclasses built on `@suaveplan/audio-engine`, each exposed from its own subpath entry point for surgical tree-shaking: EQ (multi-band parametric with presets), Reverb (IR convolver), Delay, Compressor, Pitch Shifter (AudioWorklet), Synthesizer (oscillators/envelopes/voice pool), Audio Analyzer (FFT/tempo/key/spectral), Microphone (simulation), Mixer (channel strips, sends), GLaDOS voice effect, Game Audio (spatial/proximity/music layers), and Audio Player. Together these provide the core DSP surface for the monorepo's audio UI packages.
|
|
|
|
---
|
|
|
|
## Current-state audit (genesis)
|
|
|
|
The package does not exist on genesis yet — fresh build.
|
|
|
|
---
|
|
|
|
## Available workspace deps on genesis
|
|
|
|
| Package | Role |
|
|
|---|---|
|
|
| `@suaveplan/audio-engine` (`workspace:^`) | `AudioPlugin` base class, `AudioGraph`, `AudioWorkletManager`, `PluginRegistry` |
|
|
| `@suaveplan/error` (`workspace:^`) | Typed errors for DSP failures, preset validation |
|
|
| `@suaveplan/types` (`workspace:^`) | `LoggerLike`, injectable clock |
|
|
| `@suaveplan/events` (`workspace:^`) | Typed event maps per plugin |
|
|
| `@suaveplan/schema-registry` (`workspace:^`) | Register preset Zod schemas |
|
|
| `zod` (`catalog:forms`) | Schema for every `*Preset` type |
|
|
| `@opentelemetry/api` (`catalog:observability`) | Latency histograms, CPU counters per plugin |
|
|
| `standardized-audio-context` (`catalog:browser`) | Web Audio context shim |
|
|
| `tslib` (`catalog:build`) | Runtime helpers |
|
|
|
|
Optional peer: `essentia.js` — declared in `optionalDependencies`, loaded via dynamic feature-detected import.
|
|
|
|
Dev deps: `vitest`, `@vitest/coverage-istanbul` (`catalog:testing`), `@suaveplan/testing workspace:^`.
|
|
|
|
---
|
|
|
|
## Preserved public API surface (from main branch)
|
|
|
|
Twelve plugin classes with their full config/types/preset surfaces — all preserved verbatim:
|
|
|
|
- `EQPlugin` + `EQBand`, `EQPluginConfig`, `EQ_PRESETS`
|
|
- `ReverbPlugin` + `ReverbType`, `ReverbPluginConfig`, `REVERB_DURATIONS`
|
|
- `DelayPlugin` + `DelayPluginConfig`
|
|
- `CompressorPlugin` + `CompressorPluginConfig`
|
|
- `PitchShifterPlugin` + `PitchShifterConfig`, `PitchShifterPreset`
|
|
- `SynthesizerPlugin` + oscillator/envelope/voice-pool types, `SynthesizerPreset`
|
|
- `AudioAnalyzerPlugin` + 9 analysis types (`FFTData`, `BeatInfo`, `KeyInfo`, `SpectralFeatures`, etc.)
|
|
- `MicrophoneSimulationPlugin` + `createMicrophonePlugin` + 7 mic types, `MicrophonePreset`
|
|
- `MixerPlugin` + 5 mixer types, `MixerPreset` (with complete sends round-trip)
|
|
- `GLaDOSPlugin` + 6 GLaDOS types, `GLaDOSPreset`
|
|
- `GameAudioPlugin` + 9 game audio types, `GameAudioPreset`
|
|
- `AudioPlayerPlugin` + `AudioPlayerConfig`
|
|
|
|
Twelve subpath exports: `./eq`, `./reverb`, `./delay`, `./compressor`, `./pitch-shifter`, `./synthesizer`, `./audio-analyzer`, `./microphone`, `./mixer`, `./glados`, `./game`, `./audio-player`.
|
|
|
|
---
|
|
|
|
## New additions for genesis
|
|
|
|
### 1. Structured errors via `@suaveplan/error`
|
|
|
|
Error codes: `DSP_INIT_FAILED`, `DSP_PROCESSING_FAILED`, `PRESET_VALIDATION_FAILED`, `WORKLET_REQUIRED`, `ESSENTIA_UNAVAILABLE`, `SIDECHAIN_UNAVAILABLE`.
|
|
|
|
### 2. Mixer sends round-trip
|
|
|
|
`MixerPlugin.getPreset()` / `applyPreset()` fully serializes and restores send states (the main-branch TODO is resolved).
|
|
|
|
### 3. PitchShifter worklet URL helper + fallback
|
|
|
|
Export `resolvePitchShifterWorkletUrl()` helper for Vite/Webpack consumers. Add `ScriptProcessorNode` fallback path for environments without AudioWorklet support.
|
|
|
|
### 4. Preset Zod schemas
|
|
|
|
Zod schemas for every `*Preset` type registered in `@suaveplan/schema-registry`. Runtime validation on `applyPreset()` calls.
|
|
|
|
### 5. `essentia.js` optional dep
|
|
|
|
Declared in `optionalDependencies`. Dynamic import with `try/catch` fallback; removes `@ts-expect-error` at call sites. `AudioAnalyzerPlugin` works without essentia.js (no beat/key detection).
|
|
|
|
### 6. OTel latency histograms
|
|
|
|
Per-plugin histogram `audio.plugin_processing_ms{plugin}`, counter `audio.plugin_cpu_usage{plugin}`.
|
|
|
|
### 7. Per-subpath bundle-size snapshots
|
|
|
|
Twelve snapshot tests asserting independent tree-shake (importing `./eq` does not pull in `./synthesizer`).
|
|
|
|
### 8. Sidechain support + mid/side
|
|
|
|
`CompressorPlugin` supports a first-class sidechain input. `EQPlugin` and `CompressorPlugin` expose mid/side processing mode.
|
|
|
|
### 9. Preset marketplace entry points
|
|
|
|
`@suaveplan/audio-plugins-fx/presets/reverb/cathedrals` (and similar) for optional preset packs shipped as separate lazy entry points.
|
|
|
|
---
|
|
|
|
## File layout
|
|
|
|
Each plugin follows the five-file co-located pattern. Large plugins are split into `dsp.ts`, `state.ts`, `preset.ts`, `params.ts`, `plugin.ts` sub-modules each ≤ 300 lines. Tests are `.test.ts` (not `.spec.ts`).
|
|
|
|
```text
|
|
browser/audio/audio-plugins-fx/
|
|
package.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
src/
|
|
index.ts
|
|
error-codes.ts
|
|
plugins/
|
|
eq/ (eq-plugin, eq-presets, eq-params, eq-dsp)
|
|
reverb/ (reverb-plugin, reverb-dsp, reverb-ir, reverb-presets)
|
|
delay/ (delay-plugin, delay-dsp)
|
|
compressor/ (compressor-plugin, compressor-dsp, compressor-sidechain)
|
|
pitch-shifter/ (pitch-shifter-plugin, pitch-shifter-dsp, pitch-shifter-worklet-url, worklet-fallback)
|
|
synthesizer/ (synthesizer-plugin, oscillator, envelope, voice-pool, synth-presets)
|
|
audio-analyzer/(audio-analyzer-plugin, fft, beat-detector, key-detector, essentia-bridge)
|
|
microphone/ (microphone-plugin, mic-simulation, mic-presets)
|
|
mixer/ (mixer-plugin, channel-strip, mixer-sends, mixer-presets)
|
|
glados/ (glados-plugin, glados-dsp, glados-presets)
|
|
game/ (game-audio-plugin, spatial-audio, proximity-voice, music-layers, game-presets)
|
|
audio-player/ (audio-player-plugin, audio-player-controls)
|
|
worklets/
|
|
pitch-shifter.ts (AudioWorklet processor)
|
|
presets/
|
|
reverb/
|
|
cathedrals.ts
|
|
tests/
|
|
integration.test.ts
|
|
bundle-size/
|
|
eq.size.test.ts
|
|
(... one per subpath)
|
|
```
|
|
|
|
---
|
|
|
|
## Impact
|
|
|
|
**Downstream**: `@suaveplan/react-audio`, `@suaveplan/react-audio-player`, `@suaveplan/r3f-audio`, game packages.
|
|
|
|
**Prerequisites**: `@suaveplan/audio-engine` published to Verdaccio.
|