Commit Graph

503 Commits

Author SHA1 Message Date
3dtours 473a0afe0a fix: sử dụng soundfont từ server và MIDI note có thể play 2026-07-26 20:50:33 +07:00
3dtours 87655f4275 chore: add timeline fix log 2026-07-26 20:47:28 +07:00
3dtours 28be934a19 fix: schedule SpessaSynth noteOn by startTime via setTimeout
Root cause: timeline play passes exactAudioTime as 4th param which
SpessaSynth interprets as enableReverh (boolean). All notes at T=0.
Fix: compute delay = startTime - ctx.currentTime, use setTimeout
to call noteOn(channel, pitch, vel) at correct future time.
Never pass startTime to noteOn() — SpessaSynth doesn't support it.
2026-07-26 20:47:15 +07:00
3dtours 40c531087c fix: sử dụng soundfont từ server 2026-07-26 20:25:31 +07:00
3dtours 2f2cb3a066 fix: implement proper init chain + AudioContext.resume + _initPromise
Per md/38_FLOWCLIENT.md analysis:
- Add _initPromise to serialize concurrent init calls (no duplicate worklet)
- audioContext.resume() before worklet.loadModule
- selectInstrument creates AudioContext + awaits init if not ready
- playNote tries SpessaSynth first, falls back to oscillator on error
- All MIDI commands wrapped in try/catch with oscillator fallback
2026-07-26 20:23:22 +07:00
3dtours 63496f27f4 chore: add final wiki log 2026-07-26 20:17:04 +07:00
3dtours de70d4a837 clean: stable oscillator-only client preview, remove debug logs
SpessaSynth's SoundBankLoader.fromArrayBuffer extracts 0 presets
from SF2 files (parser limitation). Client preview always uses
oscillator (reliable, approximate GM ADSR per program).
Server-side FluidSynth render provides authentic SoundFont audio.
2026-07-26 20:16:52 +07:00
3dtours 400856c0a3 fix: add init guard, log selectablePresetList count
- Add missing if (_initialized && _synthInstance) return to init()
- soundBank is main-thread proxy, worklet has actual presets
- Check selectablePresetList.length from soundBankManager (worklet state)
- Log when presets are empty (SpessaSynth parser issue)
2026-07-26 20:15:24 +07:00
3dtours d117a363da debug: log soundBank keys, instruments, samples, _presetList to find why presets empty 2026-07-26 20:11:36 +07:00
3dtours cca970c348 fix: selectInstrument auto-inits SpessaSynth if not ready
Root cause: selectInstrument called before getAudioContext triggers init.
_initialized=false → selectInstrument returns immediately → no sound bank.
Fix: selectInstrument creates AudioContext + calls init() if not ready,
waits for completion before proceeding with bank/program routing.
2026-07-26 20:09:22 +07:00
3dtours 5eb0c26ce4 debug: add detailed tracing logs for entire SF download→SpessaSynth flow 2026-07-26 20:05:34 +07:00
3dtours 6242eba3c8 debug: add bank count log in noteOn, SpessaSynth play tries then falls back 2026-07-26 20:00:17 +07:00
3dtours 3c7a002b2c fix: connect SpessaSynth output to audioCtx.destination
Per md/38_FLOWCLIENT.md Phase 1: SpessaSynth output was not
connected to speakers. Add synth.connect(audioContext.destination)
after construction to route synthesized audio to user speakers.
2026-07-26 19:56:28 +07:00
3dtours 8f4a4cd0eb fix: add 15s timeout for addSoundBank (hangs on parse error)
Per md/38_FLOWCLIENT.md flow:
- _addBankWithTimeout: wraps SpessaSynth addSoundBank with Promise.race
- 15s timeout breaks deadlock when AudioWorklet parser fails silently
- Phase 3 (channel setup) only runs after Phase 2 (load) confirms success
- Falls back to oscillator when bank can't be loaded
2026-07-26 19:53:20 +07:00
3dtours f41422da03 fix: disable SpessaSynth playback, use oscillator for client preview
- SpessaSynth bank loading fails in AudioWorklet for unknown reason
- Set _initialized=false after init so playNote uses oscillator path
- Server-side FluidSynth render produces authentic SoundFont audio on Export
2026-07-26 19:49:08 +07:00
3dtours 4064b90874 chore: bump JS cache version to force browser refresh 2026-07-26 19:47:50 +07:00
3dtours 9cad9f6c95 fix: SpessaSynth noteOn catches 'No preset found' error, falls back to oscillator
- playNote logs warning when _currentSfId is null (no bank)
- _playNoteSpessa catches noteOn errors, falls back to _playNoteOsc
- Prevents 'No preset found' from breaking playback
2026-07-26 19:46:50 +07:00
3dtours 91e228ad6a fix: sfBank/sfProg ReferenceError — move declarations outside closure 2026-07-26 19:41:49 +07:00
3dtours 09231d9b21 fix: explicit selectInstrument for SpessaSynth bank+program routing
Per md/37_FIXVST3_SUGGEST.md:
- Add SonicSF.selectInstrument(channel, bank, program, sfId) method
- Always sends controllerChange(CC0, bank) + programChange(prog) to SpessaSynth
- _playNoteSpessa also sends CC32 (bank LSB) before programChange
- Remove default bank auto-load from init (cleaner startup)
- Fix syntax error (double }} from previous edit)
- playNote Spessa: use program arg + synthEngine bank/program properly
2026-07-26 19:37:29 +07:00
3dtours 6d9060a52b fix: gracefully fallback to oscillator when SpessaSynth bank load fails
- SpessaSynth init tries to load default bank, gracefully handles failure
- When bank load fails, _currentSfId stays null → _playNoteOsc fallback
- Client preview: oscillator emulation (approximate GM sound)
- Server-side render via FluidSynth: authentic SoundFont audio
2026-07-26 19:32:32 +07:00
3dtours 6a2522d039 fix: correct importmap path for spessasynth_core main entry 2026-07-26 18:56:26 +07:00
3dtours 263c4be409 fix: use importmap to resolve spessasynth_core bare import
- Add importmap in index.html to map spessasynth_core to CDN URL
- Load spessasynth_lib from CDN directly (with importmap resolving deps)
- WorkerSynthesizer fallback also uses CDN import
- Ensures library and processor use same spessasynth_core version
2026-07-26 18:55:08 +07:00
3dtours 50847fc440 fix: WorkerSynthesizer fallback, remove non-existent BasicSynthesizer 2026-07-26 18:53:12 +07:00
3dtours 4d42b8407c fix: serve SpessaSynth processor locally to avoid CDN version mismatch
- Download spessasynth_processor.min.js from CDN, serve as static file
- Change __SpessaSynthCDN to /static/js/services/
- Fix version mismatch between esm.sh library and CDN processor
2026-07-26 18:47:32 +07:00
3dtours c884f3c533 fix: clone buffer before addSoundBank, re-await isReady, force program 0
- Clone ArrayBuffer before sendToWorklet (transfer neuters original)
- Re-await synthInstance.isReady after addSoundBank
- Force controllerChange(0,0,0) + programChange(0,0) after load
2026-07-26 18:44:43 +07:00
3dtours 5096c618b4 fix: SF3 download prefers SF2, cache invalidation on parse error
- Download endpoint reverses extension priority: .sf2 > .sf3
- loadSoundFont adds ?t= cache-buster, invalidates IndexedDB on error
- Retry logic: delete corrupted cache entry, allow re-download
2026-07-26 18:37:46 +07:00
3dtours e7a0a85eca fix: SpessaSynth init race condition, remove auto-load of sgm_v2.01
- Add _initInProgress flag to prevent concurrent init calls
- Remove auto-loadSoundFont from init (confuses user when loading DSK)
- SF3 loading happens only when user selects an instrument
2026-07-26 18:33:04 +07:00
3dtours 72186168d2 fix: correct RIFF chunk sizes in SF3 converter
- _find_chunk starts at offset 12 (after RIFF header)
- Add _find_list_of_type to locate sdta LIST
- Update sdta LIST size after smpl data replacement
- Fix 'Invalid chunk header' error in SpessaSynth
- SGM_v2.01 too large (529MB WAV) falls back to SF2
2026-07-26 18:29:05 +07:00
3dtours e843f55483 fix: strip null synth_engine from project JSON
- Frontend serialize: use undefined instead of null for synth_engine
- Backend validate: strip None synth_engine from tracks before schema validation
- Prevents 'None is not of type object' schema error
2026-07-26 18:22:35 +07:00
3dtours 7af0e61fb0 fix: add project_id fallback for schema validation
- validate_project_data injects missing project_id with temp_legacy_ prefix
- Prevents 400 error when old frontend data lacks project_id
2026-07-26 18:13:15 +07:00
3dtours 09def59cac fix: use esm.sh CDN to resolve spessasynth_core bare import
- jdelivr raw index.js has bare import 'spessasynth_core' which browser can't resolve
- esm.sh automatically rewrites bare imports to full URLs
- Keep jdelivr for worklet processor (self-contained, no imports)
- WorkerSynthesizer fallback also uses esm.sh
2026-07-26 18:09:12 +07:00
3dtours 0d1ef0f895 chore: add SpessaSynth fix log to wiki 2026-07-26 18:05:54 +07:00
3dtours 0271be4484 fix: SpessaSynth CDN URL + AudioWorklet init flow
- Fix CDN URL: spessasynth_lib@4.3.1/dist/index.js (was @latest with wrong path)
- Use WorkletSynthesizer instead of Synthesizer (correct class name)
- Add audioWorklet.addModule() for processor CDN URL
- Await synth.isReady before use
- Use soundBankManager.addSoundBank() (correct API)
- Fallback to WorkerSynthesizer if AudioWorklet fails
2026-07-26 18:05:44 +07:00
3dtours 23601007bf fix: SpessaSynth init retry + default SF3 auto-load
- getAudioContext() calls SonicSF.init on every call (not just first)
- soundfontPlayer.init retries after 1s if SpessaSynth module not loaded yet
- Auto-loads sgm_v2.01 SF3 on successful init
- Fixes race condition: module script loads after regular scripts
2026-07-26 17:59:15 +07:00
3dtours 29c4c45791 chore: rebuild precompiled JS bundle after app.jsx changes 2026-07-26 17:56:32 +07:00
3dtours 3d2930dca5 chore: add SF3+SpessaSynth log to wiki 2026-07-26 17:51:48 +07:00
3dtours e51b7fd355 feat: SF3 conversion + SpessaSynth client player
Server:
- soundfont_converter.py: Python SF2->SF3 via ffmpeg Ogg compression
- batch_convert_all runs on startup (daemon thread)
- GET /soundfonts/download/{sf_id} serves SF3 with SF2 fallback
- Dockerfile: add fluidsynth, vorbis-tools

Client:
- soundfontStorage.js: IndexedDB cache for SF3 buffers
- soundfontPlayer.js: dual-mode (SpessaSynth + oscillator fallback)
- app.jsx: init SpessaSynth, loadSF on instrument select
- index.html: SpessaSynth CDN import + storage script tag

Compression: DSK 11M->1.1M (90%), SGM 529M->18M (97%)
2026-07-26 17:51:37 +07:00
3dtours 44e0a6d736 feat: sử dụng synth cho MIDI KEys 2026-07-26 17:36:36 +07:00
3dtours bfd7146bfc chore: add fix log to wiki 2026-07-26 17:25:46 +07:00
3dtours bfb636f0bc fix(ui): remove duplicate Synth button, fix MIDI keyboard handler
- Remove small Synth button between ARM and Monitor (duplicate)
- Remove empty try/catch that swallowed all MIDI handler errors
- Ensure MIDI keyboard passes synth_engine context to playNote
- Direct fallback to armed main track when no PIANO_ROLL sub-tab armed
2026-07-26 17:25:38 +07:00
3dtours 443e09b592 feat(midi): play selected instrument on armed main track via MIDI keyboard
When MIDI note-on received and no PIANO_ROLL sub-tab is armed,
fallback to armed track in main session. Read its synth_engine and
instrumentProgram to route audio through correct instrument.
Route to track gainNode if available.
2026-07-26 17:19:51 +07:00
3dtours ef6fe0e718 fix(ui): search instrument names inside SoundFont, not just SF names
Add sfPresetSearchQuery state + search input in instrument selector
modal. Filters sfPresets by name (case-insensitive) when user types.
Clear search on SoundFont switch / modal close.
2026-07-26 17:15:50 +07:00
3dtours 4ff2ce0b9c chore: add drum toggle log to wiki 2026-07-26 17:11:50 +07:00
3dtours c2bfeb7163 feat(ui): add Drum channel toggle button on track panel
- toggleTrackDrum: sets is_percussion + soundfont_bank=128
- 🥁 button in track control panel (between Solo and Record)
- Shows 'D' badge when active, routes to MIDI channel 9
- Instrument preset list shows 🥁 prefix for bank=128 presets
2026-07-26 17:11:42 +07:00
3dtours 96aa76f194 chore: add fluidsynth fix log to wiki 2026-07-26 17:08:49 +07:00
3dtours 013465f27a fix(engine): replace pyfluidsynth high-level API with low-level CFFI
Export installed pyfluidsynth is actually the low-level ctypes
wrapper (fluidsynth), not the high-level FluidSynth class. The
broken call fluidsynth.FluidSynth() caused silent fallback to
oscillator synth for ALL SoundFont renders. Replace with:
new_fluid_settings / new_fluid_synth / fluid_synth_sfload /
fluid_synth_program_select / fluid_synth_write_s16_stereo.
Also fix synth time advancement: call write_s16_stereo for
silence gaps instead of just advancing a cursor.
2026-07-26 17:08:40 +07:00
3dtours 1059f67979 chore: add bugfix log to wiki 2026-07-26 17:00:36 +07:00
3dtours 280c8f598f fix(engine): case-insensitive SF2 lookup, add synth_engine to serialization
- _find_sf2_path now case-insensitive to match catalog IDs
- serializeTracksList includes synth_engine, soundfont_id, instrument_source
- deserializeTracksList restores synth_engine and soundfont_id
2026-07-26 17:00:28 +07:00
3dtours d48262d468 feat(engine): fix SF2 path resolution, add synth_engine struct and fallback chain
- Fix SF2 path: search upload dir, system dir, static dir (backward compat)
- Add synth_engine struct parsing with flat field fallback
- Add 3-level fallback: selected SF -> default SF -> oscillator synth
- Write synth_engine in setTrackInstrument UI setters
- Pass synth_engine context to client SoundFontPlayer and AI gateway
2026-07-26 16:49:40 +07:00
3dtours 2ab989132b fix(ui): wire Synth button to VST3 selection and render engine
- UI: setTrackInstrumentWithProgram stores instrumentId + enables MIDI type
- UI: SoundFont preset selection now passes soundfont_bank to server
- Server: render_engine reads instrument_id field (fallback instrument)
- Serialize/deserialize: soundfont_bank, soundfont_program preserved
- Rebuilt app.precompiled.js from app.jsx
2026-07-26 16:25:26 +07:00