d48262d468
- 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
32 KiB
32 KiB
[2026-07-26 16:45] Task: Implement VST3/SoundFont engine plan
- Tóm tắt thay đổi: Fix SF2 path resolution (hardcoded → multi-dir scan), add
synth_enginestruct parsing in render & UI, 3-level fallback chain, pass context to client SoundFont player. - Các file ảnh hưởng:
app/core/render_engine.py,app/static/js/app.jsx,app/static/js/services/soundfontPlayer.js,app/static/js/services/aiGateway.js - Ghi chú/Test (nếu có): Verified: catalog API returns 31 condensed instruments, render with flat fields + synth_engine struct + drums (bank=128) + missing SF fallback all succeed.
[2026-07-25 06:57] Task: Fix Piano Roll runtime errors (rollBeats TDZ + handleCCMouseMove)
- Tóm tắt thay đổi: Sửa lỗi
Cannot access 'rollBeats' before initializationbằng cách di chuyển khai báorollBeats/rollBeatsReflên trướctotalBeats. Thêm hàmhandleCCMouseMovebị thiếu và cập nhậthandleCCMouseDownhỗ trợ Ctrl+Click paint velocity. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
cd /home/locpham/SonicForgeStudio && npm run build— build passes.
[2026-07-25 07:25] Task: 4 tính năng mới (Piano Roll zoom fill + Shift+scroll playhead + auto-scroll drag + SoundFont cache)
- Tóm tắt thay đổi: (1) Piano Roll zoom-out không còn màn hình đen — bars fill toàn bộ viewport. (2) Shift+scroll trong Piano Roll di chuyển playhead và play notes MIDI như fast-forward. (3) Khi drag section/MIDI/clip đến cạnh phải timeline, auto-scroll container. (4) Server-side cache FluidSynth instances + PluginManager singleton + list_soundfont_instruments cache.
- Các file ảnh hưởng:
app/static/js/app.jsx,app/core/vst_engine.py - Ghi chú/Test (nếu có):
npm run buildpass.vst_engine.pythêmload_soundfont_cached,release_soundfont,get_plugin_manager,_SF_INSTRUMENTS_CACHE— refcount-based cache.
[2026-07-26 09:36] Task: Piano Roll 4 features (SNAP, velocity selected, auto-scroll, Synth button)
- Tóm tắt thay đổi: (1) SNAP trong MIDI tab — grid snap cho note drawing, selection marquee, loop range. (2) Ctrl+drag velocity — selected notes màu xanh dương, affect only selected; no selection = paint all. (3) Auto-scroll Piano Roll khi brush-drag gần cạnh top/bottom. (4) Synth button trong MIDI tab toolbar — mở instrument selector khi nhấn. Layout fix: thêm
h-fullcho outer div. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass. Fix thiếu 1)tại line 5959 return statement (gây build error pre-existing).
[2026-07-26 10:08] Task: Fix auto-scroll continuous + CC velocity batch + flicker
- Tóm tắt thay đổi: (1) Brush-draw gần cạnh top/bottom giờ dùng
setInterval30ms để cuộn liên tục (trước đây cuộn 1 lần per mousemove). Stop interval khi mouseup hoặc chuột rời khỏi threshold. (2) Ctrl+drag velocity cho selected notes — gộp tất cảsetNotesvào 1 batch call (thay vì 1 call per note), tránh flicker do multi re-render. (3)handleCCMouseDownselectedMode cũng batchsetNotes. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass. Thêm refbrushAutoScrollRefcho setInterval auto-scroll. BatchsetNotestrong cảhandleCCMouseDownvàhandleCCMouseMoveđể tránh flicker.
[2026-07-26 10:12] Task: Fix brush pitch-based scroll + CC velocity per-note paint
- Tóm tắt thay đổi: (1) Brush auto-scroll: chuyển từ scroll theo viewport edge (clientY) sang pitch-based — scroll khi note mới được vẽ ở pitch gần rìa visible area (6 note threshold). Dùng
NoteHeight * 2scroll step, setInterval 30ms. (2) CC velocity selected mode: thay vì paint all selected notes cùng lúc, paint từng note một theo vị trí chuột — tìm note gần cursor beat nhất, chỉ paint note đó nếu đang được selected. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass. ThaylastPaintedtrong selectedMode từ array all indices thành array single-node index.
[2026-07-26 10:20] Task: Fix brush scroll speed + CC snap + non-selected flicker
- Tóm tắt thay đổi: (1) Giảm auto-scroll step từ
NoteHeight * 2xuốngmax(1, floor(NoteHeight * 0.5))— cuộn chậm hơn để draw note đúng pitch. (2) CC lanehandleCCMouseDownvàhandleCCMouseMovedùnggetSnapBeat(beat, snapVal)khi tìm note index — snap đúng grid. (3) Non-selected CC flicker: xóapaintNotehelper, inlinesetNotestrực tiếp trong mousedown, không gọi setNotes riêng lẻ gây re-render dư thừa. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-25 07:25] Task: Fix auto-scroll + maxDuration tab isolation + 1-bar margin
- Tóm tắt thay đổi: (1)
maxDurationdùngactiveTracks+ 4-bar buffer. (2) Cách ly MAIN vs SECTION-TAB. (3) Clip/section/MIDI drag/stretch/resize clamp 1-bar from right. (4) Clip drag + stretched clip dùngupdateActiveTracks. (5) Stretched clip handler thêm auto-scroll. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 07:31] Task: Fix zoom cursor + right edge black + AI Copilot for Piano Roll
- Tóm tắt thay đổi: (1) Tách
drawWidth(content) vàcssWidth(CSS) — canvas coordinate system không còn bị sai khi zoom out. (2) Thêmmin-widthfill viewport, không còn mảng đen phải. (3) Thêm AI Copilot input + handler trong Piano Roll — gõ prompt tạo MIDI notes trực tiếp. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-25 08:08] Task: Fix velocity draw position, shift+scroll play, canvas redraw deps
- Tóm tắt thay đổi: (1) CC lane velocity stem vẽ tại start note thay vì center. (2) Shift+scroll chỉ play note khi playhead vượt qua start_beat. (3) Thêm
viewWidth/viewBeatsvào dependency array grid canvas + CC canvas để auto-redraw khi resize/zoom. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-25 08:31] Task: Fix AI Copilot tab scope + hide bottom panels + context menu Insert + autoscroll
- Tóm tắt thay đổi: (1) AI Copilot context dùng
activeTracksthaytracks— chỉ tác động tab đang active. (2) Bottom panels mặc định ẩn. (3) Right-click track timeline có 4 mục Insert. (4) Thêm auto-scroll vào stretched clip resize. SửainsertSectionAtPlayheaddùngupdateActiveTracks. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 08:36] Task: Fix auto-scroll + maxDuration tab isolation + 1-bar margin
- Tóm tắt thay đổi: (1)
maxDurationdùngactiveTracks+ 4-bar buffer. (2) Cách ly MAIN vs SECTION-TAB. (3) Clip/section/MIDI drag/stretch/resize clamp 1-bar from right. (4) Clip drag + stretched clip dùngupdateActiveTracks. (5) Stretched clip handler thêm auto-scroll. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 08:53] Task: Add timeline left/right margin + dynamic buffer expansion
- Tóm tắt thay đổi: (1) PADDING_LEFT thay đổi từ 2s thành 2-bar margin ở cả WaveformLane và TempoTrackLane. (2) Thêm state
scrollBufferExtra+ auto-expand 4 bars khi auto-scroll gần đến rìa timeline. (3)maxDurationthêmscrollBufferExtra+ 6 bars static buffer. (4) Clip drag/stretch dùngactiveTracks+updateActiveTracksthaytracks/setTracks. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:04] Task: Fix left margin 1-beat, items always visible, bar/timeline sync
- Tóm tắt thay đổi: (1) PADDING_LEFT từ 2-bar xuống 1-beat ở cả WaveformLane và TempoTrackLane. (2) Drag clamp left ≥ 1 beat, right ≤ maxDuration - 1 bar. (3) Bar numbers + grid vẽ lại đồng bộ với scroll+zoom.
- Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:08] Task: Fix Piano Roll CC lane always visible + resizable height
- Tóm tắt thay đổi: (1)
showCCdefaulttrue— CC lane luôn hiển thị. (2) ThêmccHeightstate + resize handle (drag top edge) — cho phép thay đổi độ cao CC lane. (3) Canvas dùngccHeightthay hardcoded 80px. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:18] Task: Fix brush velocity isolation from CC lane
- Tóm tắt thay đổi: Thêm
brushVelocityRefriêng biệt (0.8) — brush không còn bị ảnh hưởng bởi velocity paint từ CC lane. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:20] Task: Auto-follow dragged item in viewport
- Tóm tắt thay đổi: (1) Clip drag: sau mỗi update, nếu item ra khỏi vùng 120px viewport edge, tự scroll để item luôn thấy. (2) Section/MIDI drag: tương tự. (3) Section/MIDI resize: theo dõi edge đang kéo.
- Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:23] Task: Sync bar ruler redraw during drag
- Tóm tắt thay đổi: (1) TempoTrackLane nhận
canvasRedrawCountprop + deps — force redraw bar numbers khi drag. (2) Cả 3 drag handler incrementsetCanvasRedrawCountsau auto-follow scroll. (3) Sub-tab TempoTrackLane thêmviewportWidth+scrollLeft+canvasRedrawCount— đồng bộ ruler với timeline. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 09:30] Task: Fix bar numbers disappear past bar 12 during drag
- Tóm tắt thay đổi: TempoTrackLane đọc
scrollLefttừ DOM (walk parent chain tìm scroll container) thay vì React prop — canvas luôn dùng scroll position thực tế, không lag do async state. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
[2026-07-25 09:58] Task: Fix drag speed + bar numbers visibility + snap section items
- Tóm tắt thay đổi: (1) Xoá auto-follow phải (gây jump), chỉ giữ auto-follow trái 60px — scroll phải nhờ
autoScrollTimelinemượt. (2) ThêmPADDING_RIGHTvàotEndở TempoTrackLane và WaveformLane — bar numbers + grid hiển thị đến sát rìa phải. (3)if (localX < 0 || localX > drawWidth) continue;— skip phần tử ngoài canvas. (4) Buffer 12 bars chomaxDuration. (5) ThêmsnapTimevào section/MIDI item drag. (6) Thêm snap option'4'(1 bar). (7) Đồng bộPADDING_LEFT = barDurationở cả 2 lane. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npx babel app/static/js/app.jsx— compile pass.
[2026-07-25 10:08] Task: Merge tempo bar + timebar, beat-based ruler, snap grid
- Tóm tắt thay đổi: Thay thế seconds-based ruler (0.00s, 1.00s...) + TempoTrackLane bằng TimelineRuler (48px canvas) hiển thị bar:beat grid lines + snap sub-ticks + BPM label. Grid WaveformLane khớp ruler, snapTime() đã dùng grid spacing beat — snap items đúng vị trí ruler.
- Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:35] Task: Restore time duration labels on TimelineRuler + TempoTrackLane
- Tóm tắt thay đổi: Thêm time duration labels (formatTimeSimple: "0.00s", "1.00s",...) vào TimelineRuler và TempoTrackLane. Hiển thị dạng màu cam (#ffb464) ở chân ruler, động điều chỉnh interval (1s/2s/5s/10s...) theo zoom level. Time labels đã bị mất từ commit
ff44fd4khi merge time bar + tempo bar thành TimelineRuler. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:39] Task: Sync TempoTrackLane leadIn + time labels on ruler top
- Tóm tắt thay đổi: Thêm
leadInMarginprop vào TempoTrackLane để đồng bộ column-0 (time=0) với vị trí leadIn của TimelineRuler. Thêm CLIP_BUFFER vào TempoTrackLane. Di chuyển time duration labels trong TimelineRuler từ dưới đáy (y=40) lên phía trên (y=11). - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 11:09] Task: Fix TempoTrackLane scroll sync during drag auto-scroll
- Tóm tắt thay đổi: TempoTrackLane/WaveformLane/TimelineRuler hiện đọc scrollLeft trực tiếp từ DOM wrapper (canvases tìm parent scrollable) thay vì React prop. Tránh lệch vị trí khi auto-scroll nhanh trong clip drag do React state batching.
- Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 11:04] Task: Fix PADDING_LEFT alignment + right-side bar rendering
- Tóm tắt thay đổi: Set PADDING_LEFT=0 trong TimelineRuler/WaveformLane/TempoTrackLane để grid column 0 khớp với clip position 0 (trước đây lệch 8px). TempoTrackLane dùng CLIP_BUFFER/zoom cho tEnd thay vì PADDING_LEFT để bar/beat vẽ đủ xa về phía phải khi scroll.
- Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:58] Task: Fix clip/section snap to column 0
- Tóm tắt thay đổi: Xóa
Math.max(beatSec, ...)trong clip drag (10325), section drag (10495), section resize (10576) — thay bằngMath.max(0, ...)để item có thể snap vào column 0. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:54] Task: Fix TempoTrackLane height + clamp selection at column 0
- Tóm tắt thay đổi: Fix TempoTrackLane canvas height = 40px cố định (thay vì parentElement.clientHeight gây tràn). Wrapper
h-10 shrink-0 overflow-hiddenđể không đẩy track lanes lệch TCP. Clamp selLeft/selRight/ruler handlers >= 0 để selection không vào vùng âm. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:44] Task: Zero lead-in, time ruler + tempo track split layout
- Tóm tắt thay đổi: Xóa leadInMargin (về 0) — time 0 tại mép trái, chỉ còn 8px PADDING_LEFT. TimelineRuler đơn giản thành time-only ruler (40px, chỉ hiển thị time labels). Thêm TempoTrackLane ngay dưới (40px, bars/beats/BPM). Selection overlay top từ 48→80px. Đồng bộ WaveformLane PADDING_LEFT=8/zoom.
- Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 10:18] Task: Lead-in margin, bar 0-indexed, grid clip fix
- Tóm tắt thay đổi: Thêm leadInMargin (1 bar) đẩy timeline content sang phải — bar 0, time 0s tại mép margin. Playhead bắt đầu từ đó. Bar numbering 0-indexed (bar 0 thay vì 1). Sửa CLIP_BUFFER từ 200px → max(400, barWidth+200) để bar number không bị che. Đồng bộ leadInMargin vào tStart/tEnd canvas + mouse handlers (ruler, clip drag, section resize).
- Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 11:32] Task: Redraw canvas on section item duration resize
- Tóm tắt thay đổi: Thêm
setCanvasRedrawCount(n => n + 1)trong resize mousemove handler để WaveformLane redraw khi section/MIDI item duration thay đổi. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 17:22] Task: Piano roll toolbar - transport, ARM/INPUT, AI bar range
- Tóm tắt thay đổi: Thêm transport (play/stop/back/next/record), ARM+INPUT select MIDI, AI bar range (bar x-y) vào piano roll toolbar. handleAISend phát hiện piano roll active → MIDI prompt. Thêm selectedMidiInputId + handleMidiInputSelect.
- Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run build— build passes.
[2026-07-25 22:05] Task: Fix piano roll selection, playback, marquee drag/resize/move
- Tóm tắt thay đổi: (1) Fix playback duration — min 16 beats when no notes exist. (2) Selection marquee: green transparent (#22c55e), full-height from top to CC lane. (3) Document-level mousemove/mouseup for marquee drag (không dừng khi ra khỏi grid). (4) Edge resize handles (left/right) cho marquee. (5) Body drag (move) cho marquee. Hiển thị marquee trên cả grid canvas và CC canvas.
- Các file ảnh hưởng:
app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
node --check app/static/js/app.precompiled.js— syntax OK.
[2026-07-25 22:18] Task: Fix marquee mouseleave, loop reschedule, tempo drag
- Tóm tắt thay đổi: (1) Separate onMouseLeave from onMouseUp for grid canvas — preserve marquee when mouse leaves canvas. (2) Add MIDI note rescheduling on piano roll loop restart — 2nd+ loop iteration now plays sound. (3) Tempo bar drag already uses document-level listeners — works across columns.
- Các file ảnh hưởng:
app/static/js/app.precompiled.js
[2026-07-26 10:24] Task: Fix scroll speed match mouse + CC flicker useLayoutEffect
- Tóm tắt thay đổi: (1) Brush auto-scroll: thêm direct scroll target — mỗi mousemove tính pitchPixel, nếu gần rìa visible area (2 note margin) thì scroll trực tiếp tới target để tốc độ cuộn = tốc độ chuột. Giữ interval 16ms fallback cho trường hợp chuột ở rìa viewport. (2) CC flicker: đổi
React.useEffect→React.useLayoutEffectcho CC canvas rendering effect — canvas paint trước browser paint, loại bỏ flash khi state thay đổi. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass. Direct scroll target:container.scrollTop = targettrên mỗi mousemove khi pitch ở gần rìa.
[2026-07-26 10:28] Task: Fix velocity flicker - grid canvas useLayoutEffect
- Tóm tắt thay đổi: Đổi grid canvas effect từ
React.useEffect→React.useLayoutEffect. Nguyên nhân flicker: khi velocity thay đổi, grid canvas (useEffect) vẽ async sau paint → hiển thị velocity fill cũ 1 frame, trong khi CC canvas (useLayoutEffect) đã vẽ sync trước paint → hiển thị stem mới. Sự mismatch giữa 2 canvas tạo flicker. Fix: cả grid + CC canvas đều dùng useLayoutEffect, đồng bộ trước paint. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 10:39] Task: Fix brush shape draw + remove transport + loop repeat sound
- Tóm tắt thay đổi: (1) Brush drawing: thay vì redistribute notes evenly, append từng note mới tại beat position thực tế (
getSnapBeat(beat, snapVal)) — notes theo đúng hình dạng brush stroke. (2) Xóa transport controls (back/play/stop/record/forward) khỏi MIDI tab toolbar — chỉ dùng global transport. (3) Loop repeat: thêmschedulePianoRollMidihelper — reschedule MIDI notes qua SonicSF mỗi khi loop repeat, fix lỗi notes trong vùng chọn không có âm thanh khi play lặp lại. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 10:44] Task: Fix brush drawing smooth - track pitch + beat delta
- Tóm tắt thay đổi: Brush drawing: theo dõi cả
lastDrawBeatvàvisitedPitches. Tạo note mới khi pitch thay đổi HOẶC beat di chuyển >= minBeatStep (25% của grid duration). Dùng rawbeatthay vìgetSnapBeatđể note theo sát vị trí chuột. Khởi tạolastDrawBeat: starttrong draggedNote. Fix lỗi draw bị ngắt quãng do chỉ tạo note khi pitch thay đổi. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 10:47] Task: Fix brush draw only pitch change + CC velocity flicker skip
- Tóm tắt thay đổi: (1) Brush draw: chỉ tạo note mới khi
pitchChanged(pitch chưa visited). Nếu cùng pitch, extendduration_beatscủa note cuối cùng trongbrushIds— không tạo note mới trùng pitch. (2) CC velocity: thêm checkMath.abs(currentVal - val) > 0.001trước mỗisetNotes— skip render khi velocity/pan không thay đổi, loại bỏ flicker cho cả selected + non-selected mode. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass. currentVal tính: velocity = note.velocity || 0.8; pan = (note.pan || 0) / 2 + 0.5.
[2026-07-26 10:49] Task: Fix brush draw per-note duration + noteStartBeats tracking
- Tóm tắt thay đổi: (1) Thêm
noteStartBeatsarray trongdraggedNote— track start beat của từng note. Khi tạo note mới (pitchChanged), fix duration của note trước đó thànhbeat - prevNoteBeat. Khi extend (cùng pitch), chỉ extend note cuối vớibeat - lastNoteBeat(không extend toàn bộ stroke). (2) Khởi tạonoteStartBeats: [start]trong setDraggedNote. Fix lỗi note cuối có duration dài bằng toàn bộ brush stroke. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 10:55] Task: Fix brush draw pitch revisit by comparing lastDrawnPitch
- Tóm tắt thay đổi: Thay
!visited.includes(snappedPitch)bằngsnappedPitch !== lastDrawnPitch. Bug cũ: khi vẽ C→D→C, visited.includes(C) = true → không tạo note mới → note D cũ bị extend. Fix: so sánh với pitch của note cuối cùng, cho phép vẽ tiếp khi pitch thay đổi dù đã visit trước đó. BỏvisitedPitches(không còn dùng). - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 10:58] Task: Fix CC note detection with Y-aware stem matching
- Tóm tắt thay đổi: Thêm
findCCNoteIndex(beat, mouseY, ccH)helper — tìm note trong CC lane dựa trên cả X (beat) và Y (vị trí stem top). Khi nhiều note cùng beat (chord), so sánhmouseYvới stem top của từng note, chọn note có stem gần nhất. Dùng helper này thay thế tất cảnotes.findIndexvà nearest-fallback tronghandleCCMouseDownvàhandleCCMouseMove. Fix lỗi không detect được note khi velocity gần nhau hoặc cùng beat. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:03] Task: Remove MIDI tab loop button + Ctrl+click clear range
- Tóm tắt thay đổi: (1) Xóa nút loop (repeat) khỏi MIDI tab toolbar — dùng global transport loop button thay thế. (2) Ctrl/Meta+Click trên ruler (tempo track lane) xóa loop range: set loopStartBeat/loopEndBeat = null, selectionStart/selectionEnd = null.
- Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:06] Task: Fix MIDI tab real-time instrument change - restart playback
- Tóm tắt thay đổi:
setTrackInstrumentWithProgram: khi đổi instrument, kiểm tra nếu có PIANO_ROLL sub-tab với trackId đang playing → gọistopAllPlayback()+setTimeout50ms đểschedulePianoRollMidi+startSubTabPlaybackvới instrument mới. Fix lỗi MIDI tab không cập nhật realtime khi thay đổi Synth. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:07] Task: Fix instrument change breaks loop playback
- Tóm tắt thay đổi: Khi đổi instrument trong lúc MIDI tab đang play loop, restart code giờ cũng reset
startBufferOffsetRefvà gọirequestAnimationFrame(updatePlayhead)để tiếp tục vòng lặp animation. Fix lỗi loop bị ngắt sau khi change instrument. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:17] Task: Real-time velocity, ruler play, export MIDI button
- Tóm tắt thay đổi: (1) Thêm
onRescheduleMidiprop — khi edit velocity trong CC lane lúc đang play, gọiwindow.SonicSF.stopAll()+schedulePianoRollMidivới velocity mới. (2) Click ruler: setcurrentTime+ nếu đang play thìonStop+setTimeoutonPlayPauseđể play từ vị trí click. (3) Thêm nút Export cạnh Save — inline MIDI writer, xuất.midfile từ notes array. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:27] Task: Fix realtime velocity stale notes + ruler click restart
- Tóm tắt thay đổi: (1) Compute
updatedNotessynchronously trước khi gọisetNotes, pass intoonRescheduleMidi(updatedNotes).schedulePianoRollMidinhận tham sốnotesOverride— dùng notes mới thay vìst.notes(stale). (2) Ruler click: thayonStop()(reset currentTime) bằngstopAllPlayback()trực tiếp +schedulePianoRollMidi+startSubTabPlayback+ RAF từclickTime. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:32] Task: Fix range auto-loop + gain fade-out crackling
- Tóm tắt thay đổi: (1) Xóa
setIsLooping(true)vàisLooping: truekhỏi ruler drag handler — range selection không còn tự động loop, chỉ loop khi nút LOOP global được kích hoạt. (2) Thaywindow.SonicSF.stopAll()abrupt bằng gain fade-out:linearRampToValueAtTime(0.001, +40ms)→ delay 50-60ms →stopAll+ reschedule →linearRampToValueAtTime(volLinear, +15ms). Áp dụng cho cảonRescheduleMidivàsetTrackInstrumentWithProgram. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:35] Task: Fix ruler click playhead - use onStop+onPlayPause props
- Tóm tắt thay đổi: Sửa ruler click handler — xóa calls tới
stopAllPlayback/schedulePianoRollMidi/updatePlayhead(không có trong scope PianoRollTabEditor). Dùng props:setSubTabs({currentTime, isPlaying: false})→onStop()→ timeout 40ms →setSubTabs({currentTime})→onPlayPause(). Playhead di chuyển và play tiếp từ vị trí click. - Các file ảnh hưởng:
app/static/js/app.jsx - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:40] Task: Fix ruler cursor+range drag + SonicSF smooth stopAll
- Tóm tắt thay đổi: (1) Ruler: cursor default, click trong range → drag move (hand cursor → move), click ngoài range → seek/drag tạo selection mới. (2)
soundfontPlayer.js:activeOscillatorslưu{osc, gain}thay vìosc;stopAllramp gain về 0 trong 8ms trước khiosc.stop(10ms)— loại bỏ crackling khi realtime update. Cũng xóasetIsLooping(true)trong ruler drag cũ. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/services/soundfontPlayer.js - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 11:56] Task: Fix Piano Roll playhead seek + sound cracking
- Tóm tắt thay đổi: (1) Click ruler khi Piano Roll đang play → seek đến vị trí mới và tiếp tục play (không dừng). (2) ADSR envelope trong
soundfontPlayer.jsdùnglinearRampToValueAtTimethaysetValueAtTime/exponentialRampToValueAtTimeđể loại bỏ gain jump gây crackling.stopAllramp gain về 0 trong 20ms trước khi stop oscillator. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/services/soundfontPlayer.js,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 12:20] Task: Fix Piano Roll seek-to-start during playback
- Tóm tắt thay đổi: Thêm hàm
seekPlaybackTo(time)xử lý seek khi đang play cho cả sub-tab và main timeline. Nút "Quay lại đầu" (skip-back) và "Đầu vùng chọn" (step-back) giờ restart playback từ vị trí mới: stop → update refs → reschedule MIDI → restart. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 12:13] Task: Fix Piano Roll loop/stop behavior
- Tóm tắt thay đổi: (1) Sub-tab loop selection chỉ active khi nút Loop (st.isLooping) bật — không còn bị ảnh hưởng bởi global isLoopingSelection. (2) Stop dừng ngay lập tức:
SonicSF.stopAll()set gain 0 và stop oscillator tại ctx.currentTime, không ramp. - Các file ảnh hưởng:
app/static/js/app.jsx,app/static/js/services/soundfontPlayer.js,app/static/js/app.precompiled.js - Ghi chú/Test (nếu có):
npm run buildpass.
[2026-07-26 12:31] Task: VST/SoundFont inspection engine + AI schema
- Summary: New
SoundFontInspector(sf2utils) scans .sf2 files, generates full/condensed catalog. Added/soundfonts/catalogAPI. Updated AI tool schema withsoundfont_id/bank/program. Condensed catalog auto-injected into system prompt. Server render now passes bank/program + MIDI channel routing (drums → ch9). AddedDecentSamplerManager+ Pianobook render path. ClientSonicSF:applyAITrackInstrument,controllerChange,programChange. Catalog cache invalidated on upload. - Files:
requirements.txt,app/core/soundfont_inspector.py(new),app/api/v1/plugins.py,app/core/vst_engine.py,app/core/render_engine.py,app/static/js/services/aiGateway.js,app/static/js/services/api.js,app/static/js/services/soundfontPlayer.js,app/static/js/app.jsx,Dockerfile,.gitignore,vst_plugins/(new),samples/pianobook/(new) - Tests:
python3 -m pytest tests/ -v→ 61 passed, 1 pre-existing failure. Python syntax check OK on all modified files.
[2026-07-26 16:11] Task: Mount daw_assets host dirs into Docker
- Summary: Created
/home/locpham/daw_assets/{vst3,soundfonts,pianobook}on host. Mounted them intoweb,worker, andbeatcontainers at/opt/daw_engine/vst3,/opt/daw_engine/soundfonts,/opt/daw_engine/samples/pianobook. - Files:
docker-compose.yml - Tests: N/A
[2026-07-26 16:21] Task: Implement Synth button with VST3 selection
- Summary: Fixed Synth button to properly select and use system-installed VST3 plugins. Fixed field name mismatch (
instrument_idvsinstrument) between UI and render engine. Track auto-switches to MIDI type when VST assigned. SoundFont preset selection now passessoundfont_bank+soundfont_programto server. Serialize/deserialize includes all instrument fields. - Files:
app/static/js/app.jsx,app/static/js/app.precompiled.js,app/core/render_engine.py - Tests:
pytest- 61 passed, 1 pre-existing failure.