7.1 KiB
CLIENT-SIDE EXECUTION FLOW (SF3 + SPESSASYNTH + INDEXEDDB)
This document describes the step-by-step processing chain that takes place inside the Client Browser, from launching the Web DAW application, downloading and buffering .sf3 instrument files, and setting up MIDI channels, to outputting real-time audio.
1. SEQUENCE DIAGRAM
[ USER / UI ] [ APP / CLIENT ] [ INDEXEDDB ] [ SERVER API ] [ SPESSASYNTH ENGINE ]
| | | | |
1. Open Web Page ---------> | Initial AudioCtx | | |
| | Init SpessaSynth -----------------------------------------------> | Connect Destination
| | Fetch Catalog --------------------------->| Get /catalog |
| | | | |
2. Select Instrument -----> | Read (sf_id, bank, prog) | |
(e.g., Pipa) | Query SF3 Buffer --->| Check Key (sf_id) | |
| | | -- (Miss) -------->| Fetch /download/sf_id |
| | | | Return .sf3 (~4MB) |
| | <--------------------| Save ArrayBuffer --| |
| | Load SF3 Memory ------------------------------------------------> | addSoundFont(buffer)
| | | | |
3. Channel Router --------> | Switch Bank/Program -------------------------------------------> | controllerChange(ch, 0, bank)
| | | | | programChange(ch, prog)
| | | | |
4. Trigger MIDI Key ------> | Raw MIDI Event | | |
(or Timeline Play) | (noteOn: pitch, vel) -------------------------------------------> | noteOn(ch, pitch, vel)
| | | | | AudioWorklet Synthesis
| | <------------------------------------------------------------------ | Audio Out (User Speakers)
2. DETAILED PROCESSING PHASES
PHASE 1: BOOTSTRAPPING & ENGINE INIT
- Web Audio Context Initialization: Upon the user's first interaction with the web page (Mouse Click/Keypress), the application initializes the
AudioContext. - SpessaSynth Synthesizer Initialization: The
soundfontPlayer.jsmodule instantiatesSpessaSynthClassand connects its output directly toaudioCtx.destination:
this.synthInstance = new window.SpessaSynthClass(this.audioCtx.destination);
- Instrument Catalog Load (Catalog Context): The Frontend dispatches a
GET /api/v1/plugins/soundfonts/catalogrequest to load thecondensed_catalog, which contains lookup tables forsf_id,bank, andprogram.
PHASE 2: .SF3 ASSET LOADING & CACHING
Triggered when a user selects an instrument via the Synth UI button (or when the AI Copilot spawns a new Track with a designated instrument, e.g., dsk_asian_dreamz):
- Query Browser Cache (IndexedDB): The Client calls
sfStorage.getBuffer(sfId)to search for the.sf3file'sArrayBufferinside theDAW_SoundFont_Cachedatabase. - Handling Cache Hit vs Cache Miss:
- Cache Hit (
0\text{ms}): Retrieves theArrayBufferdirectly from the browser's RAM/Storage. - Cache Miss:
- Sends a
GET /api/v1/plugins/soundfonts/download/{sf_id}request to the Server. - Downloads the compressed, optimized
.sf3asset (ultra-lightweight size\sim 3.5 - 5.5\text{ MB}). - Invokes
sfStorage.saveBuffer(sfId, arrayBuffer)to store it inside IndexedDB for subsequent visits.
- Load Data into SpessaSynth Wasm/JS Memory: Passes the
ArrayBufferto SpessaSynth Engine'sSoundFontManager:
await this.synthInstance.soundFontManager.addSoundFont(buffer);
PHASE 3: BANK/PROGRAM ROUTING & MIDI CHANNEL SETUP
This is the most critical phase to resolve No preset found for 0:0:0 errors.
-
MIDI Channel Assignment:
-
Melodic Instruments (Piano, Pipa, Strings, Brass, etc.): Allocated to Channels 0 through 8.
-
Percussion / Drum Kits (Bank 128): Mandatory allocation to Channel 9 (GM Standard Channel 10).
-
Dispatch Bank Select & Program Change to SpessaSynth Engine: Prior to scheduling any note events, the Client triggers two simultaneous control events:
// 1. Select Bank (Control Change 0)
this.synthInstance.controllerChange(channel, 0, bank);
// 2. Select Program (Program Change)
this.synthInstance.programChange(channel, program);
Example for Pipa (dsk_asian_dreamz): Calls controllerChange(0, 0, 0) and programChange(0, 0). SpessaSynth switches Channel 0's state to the Pipa instrument patch.
PHASE 4: REALTIME SYNTHESIS & AUDIO OUTPUT
Triggered when receiving note-control signals (from a Hardware MIDI Keyboard or Timeline Transport Playback):
- Scenario A: User plays a Hardware MIDI Keyboard (e.g., Nektar SE49)
- The browser receives a Raw MIDI Event: Web MIDI API captures message
[144, 65, 78](NoteOn,Pitch 65,Velocity 78). - Latency Compensation: Calculates real-time offsets and issues
NoteOnto SpessaSynth:
const midiPitch = pitch;
const midiVelocity = Math.floor(velocity * 127);
this.synthInstance.noteOn(channel, midiPitch, midiVelocity);
- Key Release: Triggers a
NoteOffevent:
this.synthInstance.noteOff(channel, midiPitch);
- Scenario B: User triggers Play on Timeline / Piano Roll
- Transport Controller & Scheduler (
PrecisionAudioScheduler): Scans for MIDI notes located within the moving Playhead window. - Note Scheduling:
-
Converts beat positions to precise audio timing based on BPM tempo (
exactAudioTime). -
Dispatches
noteOn(channel, pitch, velocity)at the exact timestampT_{\text{start}}. -
Dispatches
noteOff(channel, pitch)at timestampT_{\text{start}} + T_{\text{duration}}. -
Audio Worklet Audio Rendering: SpessaSynth Engine reads Ogg/WAV sample data inside the
.sf3asset, applies Envelopes (ADSR), Modulators, and Gain Control parameters on the designated Channel, and pushes PCM audio data directly to user speakers with0\text{ms}latency.
3. 100% RELIABILITY VERIFICATION CHECKLIST
.sf3files loaded into the browser open without triggeringCorrupted Fileerrors.- The
sfStorage.getBufferfunction successfully stores and retrievesArrayBufferdata from IndexedDB. - Both
controllerChange(channel, 0, bank)andprogramChange(channel, program)are invoked immediately upon changing instruments on the UI. - Percussion/Drum instruments are persistently allocated to Channel 9.
- Console logs confirm:
[SonicSF] Switched Channel X -> Bank: B, Program: P.