Commit Graph

102 Commits

Author SHA1 Message Date
3dtours ea40f0c540 revert: playhead fixes cause cannot play on MAIN/SECTION-TAB
Revert two changes from 5d31563:
1. Explicit requestAnimationFrame in handlePlayPause (redundant,
   useEffect already handles RAF start after setIsPlaying)
2. setCurrentTime(0) in handleEditSectionInTab (resets global
   currentTime, interferes with MAIN session position)
2026-07-28 09:22:44 +07:00
3dtours 5d31563df6 fix: playhead not moving in SECTION-TAB with empty tracks
Two fixes:
1. handlePlayPause: add explicit requestAnimationFrame(updatePlayhead)
   after setIsPlaying(true) to ensure RAF starts immediately.
2. handleEditSectionInTab: add setCurrentTime(0) to reset playhead
   to section start. Without this, currentTime may be outside
   the section's timeline range (e.g. from main session playback).
2026-07-28 09:20:31 +07:00
3dtours 2f2f84066c fix: main playback default program 0 loads MAIN SoundFont
Line 10283 same issue as 10393: when instrumentProgram is
undefined (section cloned tracks), program defaults to 0.
_playNoteFluid calls program_change(ch,0) on FluidSynth,
which loads program 0 from whatever SoundFont is loaded
(MAIN session's SF). Fix: pass undefined -> oscillator
fallback for all tracks without assigned instrument.
2026-07-28 09:15:51 +07:00
3dtours 52ec9379d6 fix: section sub-track MIDI default program 0 loads MAIN SoundFont
Line 10393 defaulted program to 0 when subTrack.instrumentProgram
was undefined (section clone with no instrument). _playNoteFluid
receives program=0, calls program_change(ch,0) on FluidSynth,
which picks program 0 from whatever SoundFont is loaded (MAIN
session's SF). Fix: pass undefined -> _playNoteFluid takes
oscillator fallback, no SoundFont loading.
2026-07-28 09:10:33 +07:00
3dtours 9c2fa52e1b revert: Synth button conditional on section items - track can have both
815a6fa hid Synth when track has sections. But a track
can contain both section items AND midi items. Synth
applies to MIDI items regardless of sections. Section
instrument isolation is handled by section clone
nullifying all soundfont fields (9befc20).
2026-07-28 08:50:13 +07:00
3dtours 815a6faaca fix: Synth button shown on section/audio tracks
Synth button was unconditional in TCP. Now gated:
track.midiItems?.length > 0 && !track.sections?.length
Section tracks: Synth hidden (sections are containers).
MIDI tracks: Synth shown.
Audio tracks: Synth hidden.
FX button stays unconditional for all track types.
2026-07-28 08:37:31 +07:00
3dtours 9befc20851 fix: section track inherits soundfont_id/bank/program via ...t spread
...t in fallback branch copied soundfont_id, soundfont_bank,
soundfont_program, instrument_source from parent MAIN track
even though instrumentProgram and synth_engine were nulled.
FluidSynth picks up these fields and auto-loads the SoundFont.
Fix: override all soundfont/synth fields to null/undefined.
2026-07-28 08:32:21 +07:00
3dtours 18e177fa2d revert: section tracks inherit parent instrument, auto-loads SF prog0
Previous fix f2ac70e inherited instrumentId/program/name
from parent MAIN track. This causes SECTION-TAB to auto-load
program 0 of whatever SoundFont is loaded on MAIN, even
though user didn't select any instrument for the section.
Section tracks now keep null instrument + synth_engine
undefined. User can still load instrument manually via
Synth button (routed by updateActiveTracks fix).
2026-07-28 08:27:27 +07:00
3dtours f2ac70eee0 fix: section sub-tracks nullify instrument instead of inheriting
handleEditSectionInTab fallback branch explicitly set
instrumentId: null, instrumentProgram: undefined,
instrumentName: null, overriding parent track's values
spread by ...t. Changed to inherit from parent track:
instrumentId: t.instrumentId || null,
instrumentProgram: t.instrumentProgram,
instrumentName: t.instrumentName || null
2026-07-28 08:18:43 +07:00
3dtours ed51cab765 fix: instrument load from PIANO_ROLL in SECTION-TAB writes to main
updateActiveTracksRef checks sessionTabs by currentActiveTab.
When activeTab is a PIANO_ROLL sub-tab (midi_xxx), none matches
-> falls to setTracks (main). Instrument changes are lost.
Fix: also check subTabs for PIANO_ROLL type, resolve parent
session tab via parent_tab_id, route to setSessionTabs.
2026-07-28 08:11:36 +07:00
3dtours 447504ea67 fix: Ctrl+Click on section/MIDI items toggled selection, locked item
Ctrl+Click handler toggled selection + set pending drag.
Once selected, drag system treated it as 'move selection'
instead of 'copy'. Removed selection toggle - Ctrl+Click
now only sets pending drag for copy operation.
2026-07-28 08:07:49 +07:00
3dtours e4d6405b37 fix: PIANO_ROLL activeTracks resolves main tracks, not section
When PIANO_ROLL sub-tab is opened from SECTION-TAB,
activeTab switches to midi_xxx, so activeTracks fell
back to main project tracks. Section trackIds don't
exist in main tracks -> dropdown empty, ghost layers
empty, instrument data wrong.
Fix: check subTabs for PIANO_ROLL type, resolve parent
section tab from parent_tab_id, return its tracks.
2026-07-28 08:01:22 +07:00
3dtours 2baf034852 fix: section tab clears midiItems, breaks ghost+dropdown
handleEditSectionInTab overwrote midiItems: [] when cloning
section.tracks, stripping all MIDI data from section context.
PianoRollTabEditor uses activeTracks which resolves section
tracks -- midiItems must be preserved for dropdown switcher,
ghost note extraction, and instrument settings to work.
2026-07-28 07:51:08 +07:00
3dtours 14e3a561a3 feat: instrument selector modal 2-column layout
Modal max-w-md -> max-w-4xl. Font 14px (text-sm).
Left column: soundfont list. Right column: instruments
of selected SF. All Instruments view when none selected.
Search filters both columns.
2026-07-28 07:20:01 +07:00
3dtours d0def4bf1e feat: auto-scan soundfont for Synth instrument list
Background daemon (30s interval) tracks scanned files via
sf_scan_state.json (size+mtime). Only inspects new/changed SFs.
Catalog served from scanner cache, no full re-scan per request.
Upload/delete trigger immediate re-scan.
2026-07-28 07:06:37 +07:00
3dtours fd24c2dcd8 feat: Ctrl+drag sweep select + multi-item copy/drag
- Ctrl+drag on empty space: sweep range selection overlay
- Mouseup selects all items (MIDI, sections, clips) in sweep
- Selected items rendered with amber border highlight
- Ctrl+drag on section/MIDI item: duplicates the item
- Drag selected items: moves entire selected group together
- Ctrl+drag selected items: duplicates the entire group
2026-07-27 21:46:20 +07:00
3dtours 80a5352645 feat: Ctrl+drag on ruler creates global selection
handleRulerMouseDown's Ctrl+click branch previously only
cleared selection. Now it sets selectionMode='global',
records drag start, and enables isDraggingRulerRef so the
existing document-level mousemove handler updates the
selection range in real-time.
2026-07-27 21:38:23 +07:00
3dtours 8beef7cb4d fix: multi-track ARM routes MIDI to all armed tracks
- Use filter(t => t.isArmed) instead of find() to route
  MIDI input to ALL armed tracks simultaneously
- Use getTrackMidiChannel per track instead of raw
  MIDI hardware channel (msg.data[0] & 0x0F)
- NoteOff, CC, PitchBend also routed to each armed
  track's dedicated channel
- Previous code sent to channel 0 + first armed track only
2026-07-27 21:31:10 +07:00
3dtours 081a17d537 docs: add _playNoteFluid else branch fix to wiki 2026-07-27 21:27:04 +07:00
3dtours b42190e6bc feat: implement md/41_INSTRUMENT.md spec
- PianoRollTabService: getParentTrackByItemId, buildActiveScope,
  getTrackMidiChannel helpers
- parent_track_id on all MIDI items for reverse track lookup
- handleSwitchMidiItem uses active_scope pattern
- Toolbar shows parent track context labels
- Channel assignment simplified to trackIndex % 16
- All playNote calls use unified getTrackMidiChannel
2026-07-27 20:48:14 +07:00
3dtours 40502eda86 fix: pass channel+synth_engine to playNote in all MIDI playback paths
6 call sites were missing channel parameter, causing FluidSynth
to use ch=0 for all tracks -> program_change on channel 0
overwrote instrument across tracks during playback.

Fixes: startTrackPlayback, section sub-track MIDI, playMidiPreviewNote,
piano roll Alt+scroll preview, note click preview, keybed preview.
2026-07-27 20:42:45 +07:00
3dtours f429f6b1d3 docs: verify instrument assignment rules for MAIN SESSION
All 4 rules confirmed working:
1. MIDI item inherits track instrument
2. Section item does NOT inherit
3. Track isolation preserved
4. Piano roll instrument change propagates back to track
2026-07-27 20:32:30 +07:00
3dtours 035d75e504 feat(piano-roll): ghost notes + dropdown item switcher + session sync
- MIDI ghost notes: all non-selected items rendered at 25% opacity
- Dropdown at tab title: switch active edit target across all tracks
- Session Sync mode (default): viewport aligned to session bars
- Isolated mode toggle: bar 0, no ghost notes
- Ghost toggle: show/hide ghost layer (only in session mode)
- Auto-scroll to session position in session sync mode
- Bar labels show absolute session bar numbers
2026-07-27 17:08:59 +07:00
3dtours 095a0680e8 fix(build): remove extra brace at L6795, Babel build now succeeds; feat(ai-copilot): rows=4, resize-y, cursor-aware ArrowUp/Down 2026-07-27 16:36:26 +07:00
3dtours 4ed0b1e5be fix(ai-copilot): patch trực tiếp app.precompiled.js rows=4 + cursor check cho ArrowUp/Down 2026-07-27 16:21:24 +07:00
3dtours 29206d62a3 fix(ai-copilot): tăng chiều cao prompt input rows=4 + resize-y, sửa ArrowUp/ArrowDown chỉ gọi history khi cursor ở đầu/cuối text 2026-07-27 16:16:26 +07:00
3dtours 57235e68d2 docs: wiki entry program_select fix 2026-07-27 16:16:00 +07:00
3dtours 15ec35d8d9 docs: wiki entry activeNotes array fix 2026-07-27 16:00:42 +07:00
3dtours 7a2ac3a851 docs: wiki entry multi-track ARM + activeNotes 2026-07-27 15:48:43 +07:00
3dtours ef1238b87d feat: migrate SpessaSynth → FluidSynth WASM (SF3 native, loop Gen 54 fix)
Replace SpessaSynth JS/AudioWorklet with FluidSynth C++ WASM
(@enikey87/fluidsynth-emscripten@0.1.1). CDN for dev, self-host
for prod. Fixes stuck Tremolo/Saxophone notes via compliant
Gen 44 loop mode processing. 100% audio parity with server
pyfluidsynth render (same C++ core).

- soundfontPlayer.js: FluidSynth WASM engine, preserve SonicSF API
- fluidsynthLoader.js: auto-select CDN (dev) vs self-host (prod)
- fluidsynth-bridge.js: PCM bridge AudioWorklet processor
- index.html: remove SpessaSynth importmap + module, add loader
- vendor/: libfluidsynth-2.3.0-sf3.js + .wasm (1.8MB self-host)
2026-07-27 12:48:30 +07:00
3dtours 18d2503cb9 fix: bypass SpessaSynth AudioWorklet MIDI pipeline for looped voice release
SpessaSynth 4.3.1 bug: looped voices (Tremolo Strings, Trumpet) ignore
release envelope + CC 120 when processed through MIDI message pipeline
(processMessage). Fix: send stopAll directly to worklet via
handleMessage post() bypass, plus noteOn(vel=0) as alternate note-off.
2026-07-27 12:27:51 +07:00
3dtours 187686aa82 chore: add wiki entry for CC120 fix 2026-07-27 12:12:15 +07:00
3dtours 9357e4fcc8 chore: add wiki log 2026-07-27 11:43:43 +07:00
3dtours 62ac2e2d88 chore: add wiki log 2026-07-27 11:22:01 +07:00
3dtours d5ef016d49 chore: add wiki log 2026-07-27 11:06:43 +07:00
3dtours 138d05698a chore: add wiki log 2026-07-27 10:12:59 +07:00
3dtours d18c0085b6 chore: add wiki log 2026-07-27 09:28:45 +07:00
3dtours 720d80dbf9 chore: add wiki log 2026-07-27 08:53:53 +07:00
3dtours bf0469558a chore: add wiki log 2026-07-27 08:41:48 +07:00
3dtours e739eb54bf chore: add wiki log 2026-07-27 08:25:58 +07:00
3dtours 6a409b954d chore: add wiki log 2026-07-27 08:21:26 +07:00
3dtours 5915049260 chore: add wiki log 2026-07-27 08:03:12 +07:00
3dtours e4dadb3158 chore: add wiki log 2026-07-26 22:03:56 +07:00
3dtours 3b6f1ad05a chore: add wiki log 2026-07-26 21:32:14 +07:00
3dtours 8155b4f2fa chore: add wiki log 2026-07-26 21:16:55 +07:00
3dtours 1daf355dd4 chore: add loop fix log 2026-07-26 21:03:24 +07:00
3dtours 87655f4275 chore: add timeline fix log 2026-07-26 20:47:28 +07:00
3dtours 63496f27f4 chore: add final wiki log 2026-07-26 20:17:04 +07:00
3dtours 0d1ef0f895 chore: add SpessaSynth fix log to wiki 2026-07-26 18:05:54 +07:00
3dtours 3d2930dca5 chore: add SF3+SpessaSynth log to wiki 2026-07-26 17:51:48 +07:00