FIX: Windows build crash 'app\static does not exist' (datas absolute + APP_DIR freeze-aware) + VU meter ARM/MIDI keyboard

This commit is contained in:
2026-08-08 11:51:15 +00:00
parent f7b0172fdc
commit 7dda81b1d3
6 changed files with 48 additions and 15 deletions
+4 -1
View File
@@ -58,7 +58,10 @@ app.add_middleware(
# Mount storage directory (must come before general /static mount)
app.mount("/static/audio", StaticFiles(directory=settings.STORAGE_DIR), name="audio")
# Mount app static files (js, css)
STATIC_DIR = os.path.join(os.path.dirname(__file__), "static")
# Dùng settings.APP_DIR (freeze-aware) thay vì os.path.dirname(__file__):
# khi PyInstaller onefile, __file__ trỏ vào thư mục giải nén tạm _MEI...
# nhưng static/templates nằm trong sys._MEIPASS/app (config.py đã xử lý).
STATIC_DIR = os.path.join(settings.APP_DIR, "static")
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
# Include routers
+11 -1
View File
@@ -25744,8 +25744,18 @@ STRICT CONSTRAINTS:
try {
// Khi STOP (không play, không recording): v VU RNG không đc analyser/
// activity hết animation dính + master không full sau khi dng play.
// NGOI L: nếu có MIDI activity live (bt ARM track + bm phím MIDI
// keyboard KHÔNG play/record) thì KHÔNG early-return track VU phi
// nhy theo midiVuActivityRef + decay (user bug: ARM + phím MIDI VU
// đng yên vì block này v rng và return trưc khi đc activity).
const isRecActive = activeAudioRecordersRef.current && Object.keys(activeAudioRecordersRef.current).length > 0;
if (!isPlaying && !isRecActive) {
let liveMidiVu = false;
try {
for (const _k in midiVuActivityRef.current) {
if (midiVuActivityRef.current[_k] > 0.001) { liveMidiVu = true; break; }
}
} catch (e) { }
if (!isPlaying && !isRecActive && !liveMidiVu) {
setMasterVU(0);
setMasterMeterPeak(0);
Object.keys(trackVuRefs.current).forEach(k => {
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -24,7 +24,7 @@
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
<script src="/static/js/app.precompiled.js?v=202608070950" defer></script>
<script src="/static/js/app.precompiled.js?v=202608081200" defer></script>
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
<style>
:root {
+13 -5
View File
@@ -2,24 +2,32 @@
# Chay: pyinstaller engine.spec --clean --noconfirm (tren Windows)
# -*- mode: python ; coding: utf-8 -*-
import os
from PyInstaller.utils.hooks import collect_dynamic_libs, collect_submodules
# Native DLL cho pedalboard va soundfile
binaries = collect_dynamic_libs('pedalboard')
binaries += collect_dynamic_libs('soundfile')
# Root tuyet doi cua thu muc chua spec — datas PHẢI absolute: PyInstaller
# resolve duong dan relative theo CWD luc chay lenh (KHONG theo spec file),
# chay tu noi khac -> khong tim thay -> bo qua am tham -> app/static thieu
# trong bundle -> RuntimeError 'app\static does not exist' luc chay (da gap).
_SPEC_ROOT = os.path.abspath(SPECPATH)
# Assets doc (read-only) + thu muc storage (khoi tao rong; khi frozen,
# config.py chuyen storage sang %APPDATA%\SonicForgeDAW\storage)
datas = [
('app/templates', 'app/templates'), # index.html, favicon.svg
('app/static', 'app/static'), # js/css/processors
('app/storage', 'app/storage'),
('md', 'md'), # /ai-prompt-generator
(os.path.join(_SPEC_ROOT, 'app', 'templates'), 'app/templates'), # index.html, favicon.svg
(os.path.join(_SPEC_ROOT, 'app', 'static'), 'app/static'), # js/css/processors
(os.path.join(_SPEC_ROOT, 'app', 'models'), 'app/models'), # project_schema.json (projects.py)
(os.path.join(_SPEC_ROOT, 'app', 'storage'), 'app/storage'),
(os.path.join(_SPEC_ROOT, 'md'), 'md'), # /ai-prompt-generator
]
a = Analysis(
['desktop_engine.py'],
pathex=['.'],
pathex=[_SPEC_ROOT],
binaries=binaries,
datas=datas,
hiddenimports=collect_submodules('celery.fixups') + [
+8
View File
@@ -1,3 +1,11 @@
### [2026-08-08] FIX: Windows build crash — 'app\static does not exist' (PyInstaller datas relative) + FIX: ARM track + MIDI keyboard → VU meter đứng yên
- **Tóm tắt thay đổi:** 2 bug trên bản Windows standalone:
1. **Build crash 6 hộp thoại error**: `RuntimeError: Directory '...\_MEIxxxx\app\static' does not exist` khi chạy daw_engine.exe. Root cause: `app/main.py` dùng `os.path.dirname(__file__)` để mount /static — khi frozen `__file__` trỏ vào thư mục giải nén tạm `_MEI...` KHÔNG phải `sys._MEIPASS`; đồng thời `engine.spec` datas dùng path RELATIVE (resolve theo CWD lúc chạy `pyinstaller`, chạy từ nơi khác → bỏ qua âm thầm → static/templates/models thiếu trong bundle). Fix: `main.py` dùng `settings.APP_DIR` (freeze-aware, config.py đã có); `engine.spec` đổi toàn bộ datas + pathex sang ABSOLUTE từ `SPECPATH` + thêm `app/models` (project_schema.json — projects.py dùng, trước đây thiếu khi frozen).
2. **ARM track + bấm phím MIDI keyboard → VU meter không animation**: vòng tick VU (`masterVUAnimRef` useEffect) có block early-return `if (!isPlaying && !isRecActive)` vẽ VU RỖNG và return — nên bật ARM + bấm phím MIDI (không play/record) thì `midiVuActivityRef` có giá trị nhưng không bao giờ được đọc → VU đứng yên. Fix: thêm điều kiện `liveMidiVu` (scan midiVuActivityRef > 0.001) — có MIDI activity live thì KHÔNG early-return, track VU nhảy theo activity + decay như bình thường.
- **Các file ảnh hưởng:** `app/main.py` (STATIC_DIR → settings.APP_DIR), `engine.spec` (datas/pathex absolute + app/models), `app/static/js/app.jsx` (VU tick liveMidiVu guard), `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608081200)
- **Ghi chú/Test (nếu có):** BUILD OK 1107797 bytes, node --check OK, pytest 86 passed + 5 skipped (test_sf_convert fail pre-existing — path `/app/...` docker-only). Backend import OK — STATIC_DIR resolve đúng cả dev lẫn frozen.
---
### [2026-08-04] Task: Mở PIANO ROLL TAB lúc main đang play KHÔNG được tắt âm — handleEditMidiInTab stopAllPlayback có điều kiện
- **Tóm tắt thay đổi:** User báo "đang play main session, dblclick mở Piano roll tab → âm bị tắt". Thủ phạm: `handleEditMidiInTab` (15983) gọi `stopAllPlayback()` VÔ ĐIỀU KIỆN ngay khi mở tab — dừng mọi nguồn main đang phát. Fix: `if (!isPlaying) stopAllPlayback()` — chỉ clean-stop khi KHÔNG play main (tránh stuck route khi đổi tab giữa sub-tab); main đang play → mở tab → âm main tiếp tục. Nhánh play sub-tab tự stopAllPlayback trước khi play nên không xung đột route.
- **Các file ảnh hưởng:** `app/static/js/app.jsx` (handleEditMidiInTab), `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608042300)