Files
2026-05-27 23:29:53 +01:00

36 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @suaveplan/audio-fx-plugin-spessasynth — SF2/SF3 SoundFont synthesizer plugin
- **Target path**: `packages/media/audio-fx/audio-fx-plugin-spessasynth/`
- **Tier**: browser (lazy `import()` of `spessasynth_lib`; universal-tier core fallback for offline rendering)
- **Date**: 2026-05-23
- **Status**: PROPOSED
## Why
The audio-fx-plugin family covers EQ, mixer, distortion, delay, gate, pitch-shifter, phaser, tremolo, sampler, microphone, audio-player, and 5 others — but offers no general-purpose virtual instrument. Piano, organ, drum kits, orchestral instruments, classic synths — all of these are commodity-grade content delivered as SoundFont files (`.sf2` / `.sf3`). [SpessaSynth](https://github.com/spessasus/SpessaSynth) is an MIT-licensed pure-JS SoundFont 2.04 + 2.04+ synth engine with full GM/GS/XG support, 24-bit ogg-compressed SF3 support, polyphony management, modulators, and per-voice DSP — exactly the right primitive to wrap.
Wrapping SpessaSynth as an `AudioFxPlugin` (the same contract every existing fx plugin implements) means it composes inside any `PluginChain`, accepts MIDI from `@suaveplan/react-midi`, renders into `@suaveplan/audio-engine-browser` or `@suaveplan/audio-engine-server`, and exposes its parameter set (per-channel volume/pan/program-change/reverb-send/chorus-send + global master volume) through the same automation/snapshot/preset machinery every other plugin uses.
## What changes
1. **NEW package** `@suaveplan/audio-fx-plugin-spessasynth` at `packages/media/audio-fx/audio-fx-plugin-spessasynth/`.
2. **Workspace catalog** — add `spessasynth_lib` (browser-tier) and the SF2 spec test files (vendored fixtures) under `catalog:audio`.
3. **`SpessaSynthPlugin`** implementing `AudioFxPlugin` from `@suaveplan/audio-fx-plugin-base`:
- `process(input, output, ctx)` — input is ignored (instrument is a source); output is the synth's rendered PCM at the chain's sample rate.
- `init({ soundFontUrl?, soundFontBytes?, sampleRate })` — lazy `import("spessasynth_lib")`, async-loads SF2/SF3 from URL or bytes; rejects with `SPESSASYNTH.SOUNDFONT_LOAD_FAILED` on parse failure.
- `dispose()` — releases the underlying synth + frees voice buffers.
4. **MIDI input** — accepts `MidiMessage` events via a structural `MidiPortLike` consumer; routes channel-voice messages to the synth, program-change to the appropriate SF2 preset, NRPN/RPN to the standard handlers (per-note tuning, master fine-tune).
5. **Parameter surface** — 16 channels × `{ volume, pan, program, reverbSend, chorusSend }` + master gain + per-channel mute/solo. Each is an automatable parameter the chain can drive (so a knob on a control surface can pan channel 1 in real time).
6. **Voice management** — exposes `getActiveVoiceCount()`, `setMaxPolyphony(n)`, `allNotesOff(channel?)`. Voice stealing per the SF2 spec.
7. **Preset / snapshot integration** — saves selected SoundFont URL, per-channel program selection, per-channel parameter values via `PluginChain`'s standard snapshot API.
8. **Browser + server tiers** — same plugin works under `audio-engine-browser` (WebAudio) and `audio-engine-server` (offline render); SpessaSynth runs in either context since it's pure JS.
9. **Error codes** — `SPESSASYNTH.{SOUNDFONT_LOAD_FAILED, SOUNDFONT_PARSE_FAILED, UNSUPPORTED_FORMAT, VOICE_LIMIT_EXCEEDED, NOT_INITIALIZED}` via `defineCodes`.
10. **OTel instrumentation** — counter `spessasynth_voices_triggered_total`, gauge `spessasynth_voices_active`, histogram `spessasynth_process_duration_us`.
11. **Demo SF2 fixture** — small (≤2 MiB) public-domain SoundFont vendored under `tests/fixtures/` for round-trip integration tests.
## Impact
- New package in the `audio-fx-plugin-*` family — automatically picked up by the existing `audio-fx-plugin-base` plugin-discovery / chain machinery.
- Unblocks: virtual piano / drum-kit / synth UIs in `@suaveplan/react-control-surface`, the live-DJ scenario (DJ plays piano remotely, sound renders locally via SpessaSynth), GM/GS/XG playback in `@suaveplan/audio-cli`, multimedia exports in `@suaveplan/audio-engine-server`.
- `spessasynth_lib` (~200 KiB minified) added as a lazy `import()` — gated by `optionalDependencies` so consumers who don't use this plugin don't pay the cost.