fix(rt): restart fxRt khi chain VST doi trong luc realtime dang chay
- masteringSettings effect goi fxRtStart() khong dieu kien: early-return khi active + cung chainKey, stop+start lai khi chain doi (insert/remove/ bypass/reorder VST trong MASTER FX CHAIN) — truoc day nhanh chainKey chet vi branch chi chay khi !fxRt.active - test list_scan_all: path plugin phai ton tai tren dia (loc entry chet truoc cache); dung _scan_json helper voi file that trong tmp_path - bump cache-bust app.precompiled.js -> 202608212300
This commit is contained in:
@@ -18793,7 +18793,7 @@ const App = () => {
|
||||
// Đồng bộ realtime VST master với PWR/Bypass: WebAudio graph đã đổi theo
|
||||
// masterConnected nhưng fxRt không tự dừng → tắt PWR mà âm không đổi.
|
||||
try {
|
||||
if (fxRtChain().length) { if (!fxRt.active) fxRtStart(); }
|
||||
if (fxRtChain().length) { fxRtStart(); }
|
||||
else if (fxRt.active) { fxRtStop(); }
|
||||
} catch (e) { console.warn('[FX RT] resync fail:', e); }
|
||||
// Re-sync live track routes: mastering ON → mọi track qua chain (♪ bị
|
||||
|
||||
@@ -1239,7 +1239,7 @@ const[fxRackTarget,setFxRackTarget]=useState(null);window.__openFxRack=(trackId,
|
||||
window.__renderProjectPreview=async()=>{const schema=serializeProjectToSchema(currentProjectId||'temp_project',projectName||'Dự án tạm chưa lưu',bpm,tracks,subTabs,sessionTabs,masteringSettings,masterVolume);try{const res=await window.SonicAPI.renderProject(schema,'preview_'+Date.now()+'.wav');return res;}catch(e){window.showToast&&window.showToast('Render preview lỗi: '+(e.message||e),'error');throw e;}};const[masteringSettings,setMasteringSettings]=useState({masterConnected:true,// ⚠️ FIX: bật ON mặc định — MIDI item/preview PHẢI được xử lí qua mastering FX ngay khi chạy app (không cần bật/tắt power)
|
||||
activeModule:null,imagerActive:true,maximizerActive:true,eqLowGain:1.5,eqMid1Gain:-1.0,eqMid2Gain:2.0,eqHighGain:1.8,w1:0,w2:115,w3:135,w4:150,imagerScale:'v2',maxGain:5.4,maxUpward:2.0,maxSoftClip:15,maxTransient:25,ceiling:-0.1,isBypassed:false,chain:[],compActive:false,compThreshold:-16,compRatio:3,compMakeup:0,limActive:false,limThreshold:-1.0,excActive:false,excDrive:40,rebalActive:false,rebalMid:0,rebalSide:0,vstFxChain:[],vstBypass:false});useEffect(()=>{window.currentMasteringSettings=masteringSettings;if(audioCtx&&masterBus){toggleMasteringOnMaster(masteringSettings.masterConnected,masteringSettings.isBypassed);applyMasteringSettings(masteringSettings);// Đồng bộ realtime VST master với PWR/Bypass: WebAudio graph đã đổi theo
|
||||
// masterConnected nhưng fxRt không tự dừng → tắt PWR mà âm không đổi.
|
||||
try{if(fxRtChain().length){if(!fxRt.active)fxRtStart();}else if(fxRt.active){fxRtStop();}}catch(e){console.warn('[FX RT] resync fail:',e);}// Re-sync live track routes: mastering ON → mọi track qua chain (♪ bị
|
||||
try{if(fxRtChain().length){fxRtStart();}else if(fxRt.active){fxRtStop();}}catch(e){console.warn('[FX RT] resync fail:',e);}// Re-sync live track routes: mastering ON → mọi track qua chain (♪ bị
|
||||
// override bởi effMidiBypass/effAudioBypass) — nút PWR bật/tắt phải áp
|
||||
// ngay lên node đang phát (không chờ tracks effect).
|
||||
try{const _list=activeTracksRef.current&&activeTracksRef.current.length?activeTracksRef.current:tracks;_list.forEach(_t=>{const _n=activeTrackNodesRef.current[_t.id];if(_n){if(_n.sfRouteGain&&_n.sfDryGain){const _b=effMidiBypass(_t);_n.sfRouteGain.gain.value=_b?0:1;_n.sfDryGain.gain.value=_b?1:0;}if(_n.route&&_n.route.routeGain&&_n.route.dryGain){const _ab=routeBypassFor(_t);_n.route.routeGain.gain.value=_ab?0:1;_n.route.dryGain.gain.value=_ab?1:0;}}});// Sub-nodes (section tabs, key '<parent>_sub_<id>'): PWR master ON →
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
|
||||
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
|
||||
<script src="/static/js/services/chordTheory.js?v=202608211300"></script>
|
||||
<script src="/static/js/app.precompiled.js?v=202608181030" defer></script>
|
||||
<script src="/static/js/app.precompiled.js?v=202608212300" defer></script>
|
||||
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
|
||||
<style>
|
||||
:root {
|
||||
|
||||
@@ -63,15 +63,26 @@ class TestFxScanCache:
|
||||
"type": "VST3", "is_fx": True, "is_instrument": False},
|
||||
]})
|
||||
|
||||
def _scan_json(self, d):
|
||||
"""JSON scan với path plugin THẬT tồn tại trên đĩa — list_scan_all lọc
|
||||
entry plugin đã xóa khỏi đĩa (os.path.exists) trước khi cache; path ảo
|
||||
(C:\\VST3\\Ozone Pro.vst3) bị lọc hết → test không thể assert entry."""
|
||||
return json.dumps({"plugins": [
|
||||
{"path": os.path.join(d, "Ozone Pro.vst3"), "name": "Ozone Pro",
|
||||
"type": "VST3", "is_fx": True, "is_instrument": False},
|
||||
]})
|
||||
|
||||
def _pm(self, tmp_path):
|
||||
d = str(tmp_path)
|
||||
return PluginManager(vst_dir=d, sf_dir=d, extra_vst_dirs=[])
|
||||
|
||||
def test_scan_caches_with_bridge(self, tmp_path):
|
||||
pm = self._pm(tmp_path)
|
||||
# Plugin phải tồn tại trên đĩa — list_scan_all lọc entry chết trước cache.
|
||||
open(os.path.join(str(tmp_path), "Ozone Pro.vst3"), "w").close()
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")) as mrun:
|
||||
returncode=0, stdout=self._scan_json(str(tmp_path)), stderr="")) as mrun:
|
||||
r1 = pm.list_scan_all()
|
||||
assert len(r1) == 1 and r1[0]["name"] == "Ozone Pro"
|
||||
assert pm._fx_scan_all is not None and len(pm._fx_scan_all) == 1
|
||||
@@ -88,10 +99,11 @@ class TestFxScanCache:
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value=""):
|
||||
assert pm.list_scan_all() == []
|
||||
assert pm._fx_scan_all is None # KHÔNG cache rỗng
|
||||
# Có bridge → scan thật chạy
|
||||
# Có bridge → scan thật chạy (plugin tồn tại trên đĩa)
|
||||
open(os.path.join(str(tmp_path), "Ozone Pro.vst3"), "w").close()
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")):
|
||||
returncode=0, stdout=self._scan_json(str(tmp_path)), stderr="")):
|
||||
r = pm.list_scan_all()
|
||||
assert len(r) == 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user