4.2 KiB
@suaveplan/audio-fx-plugin-spessasynth — SF2/SF3 SoundFont synthesizer plugin
- Target path:
packages/media/audio-fx/audio-fx-plugin-spessasynth/ - Tier: browser (lazy
import()ofspessasynth_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 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
- NEW package
@suaveplan/audio-fx-plugin-spessasynthatpackages/media/audio-fx/audio-fx-plugin-spessasynth/. - Workspace catalog — add
spessasynth_lib(browser-tier) and the SF2 spec test files (vendored fixtures) undercatalog:audio. SpessaSynthPluginimplementingAudioFxPluginfrom@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 })— lazyimport("spessasynth_lib"), async-loads SF2/SF3 from URL or bytes; rejects withSPESSASYNTH.SOUNDFONT_LOAD_FAILEDon parse failure.dispose()— releases the underlying synth + frees voice buffers.
- MIDI input — accepts
MidiMessageevents via a structuralMidiPortLikeconsumer; 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). - 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). - Voice management — exposes
getActiveVoiceCount(),setMaxPolyphony(n),allNotesOff(channel?). Voice stealing per the SF2 spec. - Preset / snapshot integration — saves selected SoundFont URL, per-channel program selection, per-channel parameter values via
PluginChain's standard snapshot API. - Browser + server tiers — same plugin works under
audio-engine-browser(WebAudio) andaudio-engine-server(offline render); SpessaSynth runs in either context since it's pure JS. - Error codes —
SPESSASYNTH.{SOUNDFONT_LOAD_FAILED, SOUNDFONT_PARSE_FAILED, UNSUPPORTED_FORMAT, VOICE_LIMIT_EXCEEDED, NOT_INITIALIZED}viadefineCodes. - OTel instrumentation — counter
spessasynth_voices_triggered_total, gaugespessasynth_voices_active, histogramspessasynth_process_duration_us. - 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 existingaudio-fx-plugin-baseplugin-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 lazyimport()— gated byoptionalDependenciesso consumers who don't use this plugin don't pay the cost.