FIX: sửa lỗi chuyển từ tab MAIN SESSION sang SECTION-TAB và PIANO ROLL TAB thì bị bypass

This commit is contained in:
2026-08-07 09:13:03 +07:00
parent 23675dab83
commit 8cdf2942b9
4 changed files with 331 additions and 40 deletions
+89
View File
@@ -2272,3 +2272,92 @@
- **FIX (app.jsx):** truyền `active={showMediaExplorer}` vào MediaExplorerPanel + effect `if (active === false) stopMediaPlayback()` — đóng F6 → dừng source + loop + SonicSF.stopAll.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608062345 — sửa typo `</script></script>` kép), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → F6 → preview 1 file → F6 close → âm dừng ngay.
### [2026-08-07 00:00] Task: VU meter SECTION-TAB không animation khi play
- **Báo cáo user:** play ở MAIN → chuyển SECTION-TAB check item đang play → VU meter không animation realtime.
- **Nguyên nhân (2 lỗi):** (1) VU tick (24603) lookup `trackNodes[trackId]` — key THƯỜNG — node của section tab là SUB-NODE (key `<parent>_sub_<trackId>`) → không khớp → node undefined; (2) sub-node KHÔNG có `analyserNode` (chỉ `{gainNode, pannerNode, route}`) → VU không có gì để đọc.
- **FIX (app.jsx):** (1) VU tick — fallback scan `_sub_<trackId>` keys → vNode; đọc analyser từ `vNode.analyserNode`; (2) getOrCreateSubTrackNode — thêm `analyserNode` (gainNode → analyser → routeGain/dryGain) → VU đọc được tín hiệu section.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070000), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → play MAIN → chuyển SECTION-TAB → VU meters nhảy realtime theo track đang play.
### [2026-08-07 00:30] Task: MIDI section bị bypass mastering (route qua parent) + VU section không đúng nhịp
- **Báo cáo user:** play MAIN → nhấp đôi vào section item → (1) VU meter animation không đúng nhịp âm thanh; (2) âm thanh MIDI item bị bypass qua mastering chain.
- **Nguyên nhân:**
(1) **MIDI bypass**: sub-node routeGain nối vào PARENT NODE → qua route của parent track (parent `audio_bypass: true` → routeGain 0/dryGain 1) → MIDI/audio section bị kéo vào DRY bus dù sub-track ♪/A tắt → "bị bypass mastering".
(2) **VU không đúng nhịp**: scheduling MIDI của section item KHÔNG trigger `triggerMidiVuActivity` (main-track midi có ở 19066) → VU chỉ dựa analyser (trễ/smoothing) → không nhảy theo từng note.
- **FIX (app.jsx):**
(1) getOrCreateSubTrackNode — mastering path `routeGain.connect(window.masterBus.input)` TRỰC TIẾP (không qua parent — parent route có bypass riêng); fallback parentNode khi không có masterBus.
(2) Section midi scheduling (19182) — thêm `triggerMidiVuActivity(subTrack.id, note.velocity)` sau mỗi playNote.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070030), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → play MAIN → nhấp đôi section → MIDI qua mastering (nghe EQ/limiter tác dụng) + VU nhảy đúng theo note.
### [2026-08-07 01:00] Task: MIDI section tab bị bypass — createMasteringRoute dùng audioBypass cho MIDI-only track
- **Báo cáo user (kèm log):** nhấp đôi section → `setOutputDestination to: track node (sfEntry)` + noteon chạy nhưng MIDI bị bypass mastering.
- **Nguyên nhân:** SECTION-TAB play dùng PLAIN node (getOrCreateTrackNode) → `createMasteringRoute` đọc `trackAudioBypassMap`/`track.audioBypass` — section track default `audio_bypass: true` (round 48) → route dry → **MIDI kéo vào dry bus dù ♪ tắt**. (sfBypass/SF route đã đúng ♪ ở 1041/18667 — chỉ AUDIO route sai.)
- **FIX (app.jsx createMasteringRoute):** bypass theo LOẠI nội dung — track **MIDI-only** (midiItems, không clips/buffer) → dùng `trackMidiBypassMap`/`midiBypass` (♪); track có clips → `audioBypass` (A) như cũ.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070100), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → nhấp đôi section → MIDI qua mastering (EQ/limiter nghe rõ); log `[Bypass]` routeGain=1/dryGain=0 cho midi track.
### [2026-08-07 01:30] Task: First play sau double-click bị bypass (node STALE) + VU track chứa section item
- **Báo cáo user:** (1) nhấp đôi section → play lần ĐẦU midi bị bypass; stop + play lại → đúng. (2) play section item trên track → VU track đó không animation.
- **Nguyên nhân:**
(1) **Node STALE**: section tab track id TRÙNG main track id — node tạo từ MAIN play (route theo data main — audioBypass=true → dry) được cache lại → first play trong section tab dùng node cũ → bypass; stop (wipe nodes) → play lại → node mới đúng.
(2) **VU track main**: âm section đi thẳng masterBus.input (fix 00:30) → KHÔNG qua node chính → analyser node chính không có tín hiệu → VU đứng yên.
- **FIX (app.jsx):**
(1) Helper `routeBypassFor(track)` (bypass theo content-type — MIDI-only → ♪, có clips → A) — áp: createMasteringRoute (đã có), startTrackPlayback re-apply route mỗi lần schedule (hết stale), mastering-settings effect (14906 thay effAudioBypass).
(2) VU tick — scan sub-nodes (`k.indexOf(trackId + '_sub_') === 0`) khi node chính không có tín hiệu → peak sub-node analyser → VU track main animation theo section.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070130), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → nhấp đôi section → play lần ĐẦU → midi qua mastering ngay; play section trên MAIN → VU track đó nhảy.
### [2026-08-07 02:00] Task: VU MAIN không nhảy cho midi section item — triggerMidiVuActivity thiếu parent
- **Báo cáo user:** (1) first play sau double-click midi vẫn bị bypass (lặp — cần xác nhận bundle 0130); (2) quay về MAIN — section item play midi notes → VU meter không animation.
- **Nguyên nhân (2):** midiVuActivity keyed theo `subTrack.id` (section) — VU MAIN đọc `midiVuActivityRef[mainTrackId]` → miss → VU main đứng yên.
- **FIX (app.jsx 19212):** section midi scheduling trigger CẢ 2 — `triggerMidiVuActivity(subTrack.id, ...)` + `triggerMidiVuActivity(track.id, ...)` (parent/main track) → VU main nhảy theo section item đang play.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070200), `wiki.md`. Rebuild precompiled.
- **Chờ xác nhận bug (1):** user build + test 0130/0200 — nếu first play VẪN bypass → dán console: `[Bypass] node created` (routeGain/dryGain) + `setOutputDestination` lúc nhấp đôi + play lần đầu.
### [2026-08-07 02:30] Task: Re-apply route sub-node khi section item play (main) — hết stale bypass
- **Yêu cầu user:** (1) BẮT BUỘC VU meter hiển thị trên track đang play items (MAIN + SECTION-TAB); (2) chuyển tab MAIN → SECTION-TAB midi item đang play KHÔNG được bypass.
- **FIX (app.jsx 19132):** section item play (main) — sau getOrCreateSubTrackNode — re-apply route sub-node theo `routeBypassFor(subTrack)` (MIDI-only → ♪, clips → A) mỗi lần schedule → hết stale route (tương tự re-apply plain node ở 0130).
- **VU stack hiện tại (các fix trước):** sub-node có analyserNode (00:00) → VU section tab đọc sub-node (00:00); trigger midi VU cho section (00:30); VU main scan sub-nodes khi node chính câm (01:30); trigger parent track cho VU main (02:00). **BẮT BUỘC hiển thị = đã phủ: main track (subPeak + midi activity) + section tab (vNode sub-node + midi activity).**
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070230), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → (1) play section ở MAIN + trong SECTION-TAB → VU nhảy đúng track; (2) MAIN → double-click SECTION-TAB → play lần đầu → MIDI qua mastering (không bypass).
### [2026-08-07 03:30] Task: MIDI section bị bypass khi vào SECTION-TAB — masteringBypass fallback + clone kế thừa flag
- **Báo cáo user:** đang play MAIN SESSION → double-click section item vào SECTION-TAB → âm MIDI item bị bypass (không qua mastering chain).
- **Nguyên nhân (data thật — project "Section test" trong DB):** sub-track section (id TRÙNG main track id 1, 2) lưu `mastering_bypass=True` + `audio_bypass=True` (kế thừa từ track gốc). Mọi hàm quyết định bypass (`effMidiBypass`/`effAudioBypass`/`createMasteringRoute`/`routeBypassFor`/`getOrCreateSubTrackNode`) fallback `?? track.masteringBypass` → khi map chưa sync/thiếu entry (timing khi double-click + play lần đầu) → track MIDI-only bị tính bypass=TRUE → SF/sub-node route vào DRY bus (bypass mastering) dù ♪ tắt. Ngoài ra `handleEditSectionInTab` clone section tracks GIỮ NGUYÊN audioBypass/masteringBypass của track gốc → sync effect (14757) ghi map audio sai cho track section.
- **FIX (app.jsx):**
(1) BỎ fallback `?? masteringBypass` khỏi mọi hàm quyết định route (effMidiBypass/effAudioBypass/createMasteringRoute/routeBypassFor/getOrCreateSubTrackNode) — nút A/♪ + `audioBypass`/`midiBypass` là nguồn duy nhất; `masteringBypass` không còn quyết định route (field legacy kế thừa sai).
(2) `handleEditSectionInTab` (16595) — clone section tracks ép reset bypass theo context: `masteringBypass:false, audioBypass:true (section raw default), midiBypass:false` — hết kế thừa flag track gốc.
(3) Sync effect (14757): `trackMasteringBypassMap[t.id] = !!t.masteringBypass` (trước gán nhầm `!!t.audioBypass`).
(4) `updateSfRouting` (18813): `effMidiBypass(t.id)``effMidiBypass(t)` — truyền string → map lookup sai → sfRouteGain bị ép 1 (♪ vô hiệu qua đường này).
(5) Log chẩn đoán: `[Bypass] sfEntry created track <id> midiBypass=...` (lúc tạo node) + `[Bypass] sf route sync track <id> ...` (updateSfRouting ép route) — test còn lỗi thì dán log.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070330), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** `npm run build` → hard refresh → play MAIN → double-click section vào SECTION-TAB → MIDI qua mastering (nghe EQ/limiter); play trong SECTION-TAB → MIDI vẫn qua mastering (♪ tắt); bật ♪ → bypass đúng ý. Nếu còn bypass → dán console `[Bypass]` logs.
### [2026-08-07 03:35] Task: MIDI section vẫn bypass sau 0330 — thêm log chẩn đoán [SFRoute]/[Bypass] reapply
- **Báo cáo user (log 0330):** play MAIN → double-click section → `[SonicSF] setOutputDestination to: track node (sfEntry)` + noteons chạy → bấm Play tab (isPlaying=true) → stopAllPlayback → SF về masterBus.input. Log THIẾU các dòng `[Bypass]`/`[Play] offset` của bản 0330 → chưa xác định được route thực tế (sfRouteGain/routeGain giá trị bao nhiêu lúc nghe bypass).
- **Log mới thêm (app.jsx):**
(1) `[SFRoute] activeTab=... midiAudible=...` — updateSfRouting: track nào audible + đích tính.
(2) `[SFRoute] dest=sfEntry node <id> sfRouteGain=... sfDryGain=...` — đích SF + giá trị route hiện tại TRƯỚC khi ép.
(3) `[SFRoute] dest=gainNode node <id> (no sfEntry) route.routeGain=... dryGain=...` — đích fallback gainNode.
(4) `[Bypass] reapply track <id> contentType=midi/audio bypass=... → routeGain=.../dryGain=...` — startTrackPlayback re-apply route.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070335), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** hard refresh → play MAIN → double-click section vào SECTION-TAB → nghe bypass → **dán TOÀN BỘ console (không filter)** — cần các dòng `[SFRoute]`, `[Bypass]`, `[Play] offset`, `setOutputDestination` để chốt đường bypass chính xác.
### [2026-08-07 03:40] Task: MIDI section bypass — ID TRÙNG main track → node/map collision (CHỐT NGUYÊN NHÂN)
- **Log 0335 (đã chốt):** play MAIN → `[SFRoute] activeTab=main midiAudible=` (rỗng → SF về masterBus.input — MIDI qua mastering ✓). Double-click → `[SFRoute] activeTab=session_... midiAudible=1(midi1)``[SFRoute] dest=gainNode node 1 (no sfEntry) — route.routeGain=0 route.dryGain=1` → SF route vào NODE '1' → **route dry → MIDI section BỊ BYPASS**. (Lưu ý: log soundfontPlayer "track node (sfEntry)" là log SAI — luôn in "sfEntry" cho mọi node khác null; đích thực là gainNode.)
- **Nguyên nhân gốc:** section clone giữ id sub-track TRÙNG main track id (data: main 1/2 = sub 1/2). (1) `updateSfRouting` lookup node theo id → trúng node MAIN (route theo ♪ MAIN = bật = dry) → SF (MIDI section) kéo vào dry dù ♪ section tắt. (2) Bypass map keyed theo id bị GHI ĐÈ CHÉO (clone audioBypass=true ghi đè map main; ♪ main ảnh hưởng route section).
- **FIX (app.jsx):**
(1) MỌI hàm quyết định route (`effMidiBypass`/`effAudioBypass`/`createMasteringRoute`/`routeBypassFor`/sub-node): **ƯU TIÊN field track object (`track.midiBypass`/`track.audioBypass`)** — object phân biệt đúng context; map chỉ fallback (realtime nút bấm, track không field).
(2) `updateSfRouting`: activeTab là `session_*` → lookup node ƯU TIÊN SUB-NODE (key `<parent>_sub_<id>` — route theo ♪ section + thẳng masterBus.input); không có sub-node → null (SF về masterBus.input — qua mastering, KHÔNG bypass). KHÔNG bao giờ route vào node MAIN khi ở section tab.
(3) Sync effect (14754): đảo thứ tự — session/clone TRƯỚC, MAIN SAU (main thắng khi id trùng — map fallback đúng context; clone dùng field).
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070340), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** hard refresh → play MAIN → double-click section vào SECTION-TAB → MIDI qua mastering (nghe EQ/limiter); log kỳ vọng: `[SFRoute] dest=gainNode node 1 ...` → KHÔNG còn (sub-node hoặc masterBus.input); `route.routeGain=1`. Play section tab → MIDI qua mastering (♪ tắt); bật ♪ section → bypass đúng ý.
### [2026-08-07 03:45] Task: MIDI bypass khi mở MIDI item SECTION-TAB → PIANO ROLL TAB
- **Báo cáo user:** sau fix 0340 (section tab OK) — mở MIDI item từ SECTION-TAB vào PIANO ROLL TAB → MIDI bị bypass.
- **Nguyên nhân:** cùng cơ chế collision id — PIANO ROLL của track section có `parent_tab_id = session_*`, `trackId` = id sub-track TRÙNG main track id. `updateSfRouting` nhánh PIANO_ROLL lookup `activeTrackNodesRef.current[trackId]` → trúng NODE MAIN (route theo ♪ main — dry) → SF (notes piano roll) kéo vào dry dù ♪ section tắt. Xảy ra ngay khi ĐỔI TAB (effect 14814 → updateSfRouting) — không cần play.
- **FIX (app.jsx updateSfRouting nhánh PIANO_ROLL):** khi `_activeSub.parent_tab_id` startsWith `session_` → lookup node ƯU TIÊN SUB-NODE (key `endsWith('_sub_' + trackId)` — route theo ♪ section + thẳng masterBus.input); không có sub-node → null (SF về masterBus.input — qua mastering, KHÔNG bypass). Không bao giờ route vào node MAIN cho piano roll của section.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/templates/index.html` (?v=202608070345), `wiki.md`. Rebuild precompiled.
- **Ghi chú/Test:** hard refresh → play MAIN → double-click section (SECTION-TAB) → double-click MIDI item → PIANO ROLL tab → MIDI qua mastering (nghe EQ/limiter); log `[SFRoute]` không còn dest node MAIN (route 0/1) cho piano roll section.