Commit Graph

716 Commits

Author SHA1 Message Date
3dtours 81dc9a0354 refactor: chuyển đổi từ SpessaSynth sang FluidSynth WASM 2026-07-27 12:31:21 +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 fa4a38bf3e fix: stopNote/stoplAll uses CC120 (All Sound Off) instead of CC123 (All Notes Off) to kill sustained instrument voices immediately
Root cause: SpessaSynth's CC123 (All Notes Off) calls stopAllNotes(false)
which enters the SoundFont release envelope. Tremolo Strings (GM#44) and
similar sustained instruments have 2-5s release tails, causing notes to
continue playing after MIDI key release.

Fix: Replace CC 123 with CC 120 (All Sound Off) in stopNote() and
stopAll(). CC 120 calls stopAllNotes(true) which sets voice.isActive=false
instantly, bypassing the release envelope entirely.

Removed redundant noteOff(ch,pitch,0) and resetAllControllers(CC121)
which unnecessarily reset volume/pan/expression on the channel.
2026-07-27 12:11:37 +07:00
3dtours 4def86168b fix: send CC64=0 + CC121=0 before noteOff (reset sustain + all controllers) 2026-07-27 12:02:50 +07:00
3dtours 9357e4fcc8 chore: add wiki log 2026-07-27 11:43:43 +07:00
3dtours f7a46e0baa fix: lazyInit in playNote, oscillator fallback 2s instead of 60s 2026-07-27 11:43:32 +07:00
3dtours 1829b61472 fix: stopNote fires noteOff(3 variants) + allNotesOff + CC123 for redundancy 2026-07-27 11:39:16 +07:00
3dtours 8aeac14e4b fix: only send All Notes Off (CC123) when sustain pedal is not active
- Track sustain state per channel via _sustainStates[]
- sustainActive(channel) returns boolean
- MIDI NoteOn: only send CC123 if !sustainActive(ch)
- Preserves sustained notes when playing new notes
2026-07-27 11:30:35 +07:00
3dtours 48e4047a84 revert: remove 100ms delay from stopNote, keep instant noteOff 2026-07-27 11:27:39 +07:00
3dtours 0e051297b0 fix: stopNote delays noteOff by 100ms for natural release 2026-07-27 11:25:03 +07:00
3dtours 62ac2e2d88 chore: add wiki log 2026-07-27 11:22:01 +07:00
3dtours e785b88ea7 fix: send All Notes Off (CC123) before each MIDI NoteOn to stop lingering release 2026-07-27 11:21:51 +07:00
3dtours e866ad1c0d fix: stopNote sends noteOff(ch,pitch,0) + controllerChange(CC64=0) for safety 2026-07-27 11:17:36 +07:00
3dtours 90ff65f31d fix: add debug log to stopNote for troubleshooting 2026-07-27 11:14:09 +07:00
3dtours 0246255792 fix: immediate notes (MIDI keyboard) have NO auto noteOff timeout
- Scheduled notes (delay>0, timeline playback): still set auto noteOff
- Immediate notes (delay=0, MIDI keyboard): keep sounding until stopNote or stopAll
- Remove _scheduledNotes push/pop for immediate notes (no timeout to track)
2026-07-27 11:10:45 +07:00
3dtours d5ef016d49 chore: add wiki log 2026-07-27 11:06:43 +07:00
3dtours e6439c2d9d fix: MIDI NoteOff stops note immediately (60000ms duration + stopNote)
- NoteOn: durationMs=60000 (1 phút, giữ cho đến khi NoteOff)
- NoteOff: stopNote(ch, pitch) gọi synthInstance.noteOff() ngay
- MIDI channel (msg.data[0] & 0x0F) truyền đúng vào playNote
- CC (sustain/modulation) + pitch bend forward qua SpessaSynth
2026-07-27 11:06:35 +07:00
3dtours 5a49d2012b feat: sustain (CC64), modulation (CC1), pitch bend for MIDI keyboard
- Add controllerChange forwarder for all CC messages (cmd 0xB)
- Add pitchBend method to SonicSF + MIDI handler (cmd 0xE)
- CCs routed to _synthInstance.controllerChange(ch, cc, val)
- Pitch bend routed to _synthInstance.pitchBend(ch, 14bit-val)
2026-07-27 11:02:45 +07:00
3dtours 7eb26a004f fix: nút synth load trực tiếp instruments 2026-07-27 10:59:41 +07:00
3dtours 5c47b68a9d fix: single Synth button opens instrument modal, fix init race condition
- Remove small Synth button (already done earlier)
- Large Synth button now calls openInstrumentSelector (instrument modal)
- Fix _initPromise stale cache: reset to null when init fails
- Module not loaded yet → retries on next select instead of stuck
2026-07-27 10:54:58 +07:00
3dtours cf61b8431d revert: restore small Synth button to dropdown (preserve SF3 flow) 2026-07-27 10:49:42 +07:00
3dtours e5bd442b7c fix: small Synth button opens instrument modal (not SF list dropdown) 2026-07-27 10:40:20 +07:00
3dtours 55a27b5957 fix: remove sf.source references causing ReferenceError in PluginManagerModal 2026-07-27 10:35:42 +07:00
3dtours 981a184176 chore: bump cache version to force browser refresh 2026-07-27 10:18:34 +07:00
3dtours 138d05698a chore: add wiki log 2026-07-27 10:12:59 +07:00
3dtours 3a6b44e195 feat: Synth button opens modal with flat instrument list from all SFs
- openInstrumentSelector builds flat list of all instrument presets
- Modal shows all instruments with search bar
- Each preset shows sf name + program name
- Remove old two-step (SF list -> presets) navigation
- Fix pre-existing closing paren mismatch in PluginManagerModal
2026-07-27 10:11:44 +07:00
3dtours fba3664a1c fix: catalog lookup uses lowercased key for merge
- catalog keys are lowercased (soundfont_inspector: .lower())
- sf.id from _scan_soundfonts has original case (SGM_v2.01)
- Use catalog[sfId.toLowerCase()] || catalog[sfId] to match both
2026-07-27 09:44:28 +07:00
3dtours 2ad29226c4 fix: deduplicate soundfont scan + source label + delete only uploads
- _scan_soundfonts: dict-keyed by base_id to prevent duplicates
- Add 'source' field ('system' | 'upload') to each soundfont entry
- Delete endpoint: only allow deleting upload soundfonts (403 for system)
- Frontend: show (system)/(upload) tag, hide Delete for system fonts
2026-07-27 09:36:58 +07:00
3dtours d18c0085b6 chore: add wiki log 2026-07-27 09:28:45 +07:00
3dtours 7544ee2e5f feat: eager soundfont catalog scan at startup, cache presets locally
- App startup fetches full catalog with all instrument presets
- Merges presets into instrumentSelectorData.soundfonts
- Synth button shows presets from cache (no per-SF API call)
- Fallback: if cache miss, fetch individual SF presets on demand
2026-07-27 09:28:34 +07:00
3dtours d04442ad45 fix: click on ruler moves playhead only (no zero-width selection)
- Remove setSelectionStart/End from simple click (non-drag) path
- Only handleMouseMove (drag) creates/modifies selection
- Sub-tab already correct (no selection set on click)
2026-07-27 09:19:18 +07:00
3dtours dff2c81848 fix: sub-tab ruler drag creates local selection, separate from main
- Add isDraggingSubTabRef/subTabDragStartRef for section-tab drag
- Ctrl+Click on sub-tab ruler clears sub-tab selection
- Sub-tab mousedown: set playhead + start drag
- Sub-tab mousemove/mouseup: update st.selectionStart/End locally
- Section-tab selection doesn't affect main session selection
2026-07-27 09:14:34 +07:00
3dtours ef891e9e04 fix: set selectionFollowsTempo based on which ruler is clicked
- Time Ruler click → setSelectionFollowsTempo(false) → time-based
- Tempo Track Lane click → setSelectionFollowsTempo(true) → tempo-based
- Also handles sub-tab ruler (EDITOR tabs)
- Manual toggle button ♪T/⏱T still works for override
2026-07-27 08:59:50 +07:00
3dtours 720d80dbf9 chore: add wiki log 2026-07-27 08:53:53 +07:00
3dtours 06480516eb fix: equal bar widths + selection tempo/time toggle
- WaveformLane bar grid: integer beat loop (bn*beatDuration) instead
  of accumulating t += beatDuration — no floating point drift
- Add selectionFollowsTempo toggle button (♪T/⏱T) in transport bar
- ♪T (tempo): selection recalculates with BPM
- ⏱T (time): selection fixed in seconds regardless of BPM
2026-07-27 08:53:42 +07:00
3dtours bf0469558a chore: add wiki log 2026-07-27 08:41:48 +07:00
3dtours af6c77b9ee fix: add bar markers to TimelineRuler aligned with TempoTrackLane
- TimelineRuler draws bar lines at bn * barDuration positions
- Same integer beat loop as TempoTrackLane (bn from firstBarNum)
- Bar number labels at center of ruler
- Time markers still shown below bar markers
- All use same bpm prop → always aligned with tempo track
2026-07-27 08:41:36 +07:00
3dtours 3a84323dd8 fix: force canvas redraw after BPM duration recalculation 2026-07-27 08:36:14 +07:00
3dtours 3c12ce2a22 fix: range loop selection maintains bar count on BPM change
- Add prevBpmRef to track previous BPM
- BPM effect recalculates selectionStart/End using bar count
- startBar = oldStart / oldSecondsPerBar
- newStart = startBar * newSecondsPerBar (same for end)
2026-07-27 08:31:12 +07:00
3dtours e739eb54bf chore: add wiki log 2026-07-27 08:25:58 +07:00
3dtours f59cc304d4 fix: TempoTrackLane bar spacing drift with floating-point BPM
- Replace t += beatDuration loop (floating accumulation drifts)
- Iterate by integer beat number: t = bn * beatDuration
- Each bar position computed independently, no cumulative error
- Same fix for snapInterval loop
- Fixes unequal bar widths for BPM like 77, 81
2026-07-27 08:25:47 +07:00
3dtours 6a409b954d chore: add wiki log 2026-07-27 08:21:26 +07:00
3dtours cde29386d2 fix: TempoTrackLane bar spacing by removing broken DOM scrollLeft lookup
- DOM traversal for scrollLeft stops at sticky wrapper (scrollLeft=0)
- Use scrollLeft prop directly instead of traversing parent DOM
- Affects both TimelineRuler and TempoTrackLane canvas effects
- Bars now correctly space when BPM changes
2026-07-27 08:21:16 +07:00
3dtours ea5043c981 fix: auto-compute length_bars for legacy items on BPM change
- Items without length_bars: compute bars from duration/secondsPerBar
- Round to nearest quarter bar for musical accuracy
- Recalculate duration = bars * new secondsPerBar for all items
- Maintains correct bar count for both legacy and new items
2026-07-27 08:10:05 +07:00
3dtours 5915049260 chore: add wiki log 2026-07-27 08:03:12 +07:00
3dtours d97f82e93f fix: maintain item duration in bars when BPM changes
- Add length_bars field to midiItems and sections at creation
- useEffect on bpm recalculates duration = length_bars * secondsPerBar
- Fix section creation: use secondsPerBar instead of hardcoded 4s
- Handle existing items without length_bars (no-op)
2026-07-27 08:03:02 +07:00
3dtours f98ade5d58 fix: context menu flips upward when near viewport bottom
- If click.y + 260 > window.innerHeight: position bottom instead of top
- Also clamp left to prevent right-edge overflow
- Menu now appears above the click point when there's no room below
2026-07-27 07:46:06 +07:00
3dtours 993610ca37 fix: AI items at playhead + context menu scrollable within viewport
- Revert AI item startTime to currentTime (playhead position)
- Context menu: maxHeight 60vh + overflow-y-auto, top clamped to
  window.innerHeight - 200 to prevent bottom clipping
- Same fix for both main session and sub-tab context menus
2026-07-27 07:42:01 +07:00
3dtours 509da0c724 fix: track do AI tạo không đồng đều 2026-07-26 22:22:00 +07:00