fix(bridge): deploy ABI-fixed VST2 binary to install + open GUI for VST2 tracks

Qin_RV_x64.dll (Kong Audio) crashed with SEH 0xc0000005 in Bridger64.dll
using the stale install binary (pre-ABI-fix). Copy native_bridge build
Release binary into install/ so the packaged app runs the fixed host.

Also open the native GUI after loading a VST2 instrument (previously
VST3-only), so Qin_RV's editor (Qin_VST_Window via auxhost.exe) shows
automatically on track load.
This commit is contained in:
2026-08-19 22:36:28 +07:00
parent 819257a1b3
commit 5df96aef1e
4 changed files with 5 additions and 5 deletions
+2 -2
View File
@@ -6138,7 +6138,7 @@ const PluginManagerModal = ({ isOpen, onClose, pluginsData, onInsertInstrument }
if (ok) window.SonicAPI.bridgeStatus().then(s => setBridgeStatus(s)).catch(() => {});
// Requirement 2: VST3 load → mở native GUI ngay (C++ attach editor vào
// cửa sổ bridge tự tạo — control type=4, hwnd=0).
if (ok && type === 'VST3' && window.NativeBridgeService.openNativeGUI) {
if (ok && (type === 'VST3' || type === 'VST2') && window.NativeBridgeService.openNativeGUI) {
try { await openVstGuiRetry(name, 0, 20); } catch (e) {}
}
return ok;
@@ -16543,7 +16543,7 @@ const App = () => {
// transport STOP; setReloading trước job (G0.1b) + 1 UiThread (G1.2)
// chặn race 2 thread 1 DLL. Mute ngắn ~0.1-0.3s lần đầu, note đang
// ngân không mất. Reopen sau khi đóng vẫn mute 1-3s (reload) — level 2.
if (ok && btype === 'VST3' && window.NativeBridgeService.openNativeGUI) {
if (ok && (btype === 'VST3' || btype === 'VST2') && window.NativeBridgeService.openNativeGUI) {
try { await openVstGuiRetry(instrumentId, bch, 20); } catch (e) {}
}
}
+2 -2
View File
@@ -495,7 +495,7 @@ const data=await window.SonicAPI.listPlugins();setLocalData(data);try{const cat=
// invoke load_native_instrument (C2) → bridge C++ load vào channel 0.
const loadToBridge=async(name,path,type)=>{try{const r=await window.SonicAPI.bridgeLoad({name:name,path:path||null,instrumentType:type,channel:0});if(!r||!r.path){window.showToast&&window.showToast('Không resolve được asset: '+name,'error');return false;}const ok=await window.NativeBridgeService.loadInstrument(r.path,type,0);window.showToast&&window.showToast(ok?'Đã load vào Native Bridge: '+r.path:'Bridge không khả dụng (dev mode?)',ok?'success':'warning');if(ok)window.SonicAPI.bridgeStatus().then(s=>setBridgeStatus(s)).catch(()=>{});// Requirement 2: VST3 load → mở native GUI ngay (C++ attach editor vào
// cửa sổ bridge tự tạo — control type=4, hwnd=0).
if(ok&&type==='VST3'&&window.NativeBridgeService.openNativeGUI){try{await openVstGuiRetry(name,0,20);}catch(e){}}return ok;}catch(err){window.showToast&&window.showToast('Lỗi load bridge: '+(err.message||err),'error');return false;}};const[pmTab,setPmTab]=React.useState('soundfont');return React.createElement('div',{className:'fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm',onClick:onClose},React.createElement('div',{className:'bg-[#1e1e1e] border border-[#383838] rounded-xl shadow-2xl w-full max-w-3xl p-0 text-slate-200 overflow-hidden flex flex-col relative',style:{maxHeight:'80vh'},onClick:e=>e.stopPropagation()},// ── In-app folder picker (Plugin Directories) ─────────────────────
if(ok&&(type==='VST3'||type==='VST2')&&window.NativeBridgeService.openNativeGUI){try{await openVstGuiRetry(name,0,20);}catch(e){}}return ok;}catch(err){window.showToast&&window.showToast('Lỗi load bridge: '+(err.message||err),'error');return false;}};const[pmTab,setPmTab]=React.useState('soundfont');return React.createElement('div',{className:'fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm',onClick:onClose},React.createElement('div',{className:'bg-[#1e1e1e] border border-[#383838] rounded-xl shadow-2xl w-full max-w-3xl p-0 text-slate-200 overflow-hidden flex flex-col relative',style:{maxHeight:'80vh'},onClick:e=>e.stopPropagation()},// ── In-app folder picker (Plugin Directories) ─────────────────────
pmPicker&&React.createElement('div',{className:'absolute inset-0 z-10 bg-[#171717]/97 flex flex-col',style:{padding:16}},React.createElement('div',{className:'flex items-center justify-between mb-2'},React.createElement('div',{className:'text-xs font-bold text-violet-300 uppercase'},'Chọn thư mục plugin'),React.createElement('button',{onClick:()=>setPmPicker(null),className:'text-zinc-500 hover:text-zinc-200 transition'},React.createElement('i',{'data-lucide':'x',className:'w-4 h-4'}))),React.createElement('div',{className:'flex items-center gap-2 mb-2'},React.createElement('button',{onClick:()=>{if(pmPicker.parent)browsePluginDir(pmPicker.parent);},disabled:!pmPicker.parent,className:'px-2 py-1 bg-zinc-800 hover:bg-zinc-700 rounded text-[11px] text-zinc-300 disabled:opacity-30 shrink-0'},'Lên'),React.createElement('div',{className:'flex-1 text-[11px] text-zinc-400 font-mono truncate',title:pmPicker.path||''},pmPicker.path||(pmPicker.loading?'Đang tải...':'My Computer'))),pmPicker.loading?React.createElement('div',{className:'flex-1 flex items-center justify-center text-zinc-500 text-xs'},'Đang tải...'):pmPicker.dirs?pmPicker.dirs.length===0?React.createElement('div',{className:'flex-1 flex items-center justify-center text-zinc-600 text-xs italic'},'Thư mục trống'):React.createElement('div',{className:'flex-1 overflow-y-auto space-y-1'},pmPicker.dirs.map((d,i)=>React.createElement('div',{key:'pd_'+i,className:'flex items-center gap-2 px-2 py-1.5 rounded hover:bg-violet-900/30 cursor-pointer group',onClick:()=>browsePluginDir(d.path)},React.createElement('i',{'data-lucide':'folder',className:'w-3.5 h-3.5 text-amber-500/80 shrink-0'}),React.createElement('span',{className:'flex-1 text-[11px] text-zinc-300 truncate'},d.name),React.createElement('i',{'data-lucide':'chevron-right',className:'w-3 h-3 text-zinc-600 group-hover:text-violet-400 shrink-0'})))):pmPicker.roots?pmPicker.roots.length===0?React.createElement('div',{className:'flex-1 flex items-center justify-center text-zinc-600 text-xs'},'Không tìm thấy ổ đĩa'):React.createElement('div',{className:'flex-1 overflow-y-auto space-y-1'},pmPicker.roots.map((r,i)=>React.createElement('div',{key:'pr_'+i,className:'flex items-center gap-2 px-2 py-1.5 rounded hover:bg-violet-900/30 cursor-pointer',onClick:()=>browsePluginDir(r.path)},React.createElement('i',{'data-lucide':'hard-drive',className:'w-3.5 h-3.5 text-cyan-500/80 shrink-0'}),React.createElement('span',{className:'flex-1 text-[11px] text-zinc-300'},r.name||r.path)))):null,React.createElement('div',{className:'flex items-center justify-end gap-2 mt-2 pt-2 border-t border-[#383838]'},React.createElement('button',{onClick:()=>setPmPicker(null),className:'px-3 py-1.5 bg-zinc-800 hover:bg-zinc-700 text-white text-xs rounded'},'Hủy'),React.createElement('button',{onClick:confirmPluginDir,disabled:!pmPicker.path,className:'px-3 py-1.5 bg-violet-700 hover:bg-violet-600 text-white text-xs font-semibold rounded disabled:opacity-30'},'Chọn thư mục này'))),// Header
React.createElement('div',{className:'flex items-center justify-between px-5 py-3 bg-[#252525] border-b border-[#383838]'},React.createElement('h3',{className:'text-base font-bold text-cyan-400 flex items-center gap-2'},React.createElement('i',{'data-lucide':'zap',className:'w-4 h-4'}),'Plugin Manager (SoundFont / VSTi)'),React.createElement('div',{className:'flex items-center gap-2'},React.createElement('span',{className:`text-[9px] font-bold uppercase tracking-wider px-2 py-0.5 rounded border ${bridgeStatus&&bridgeStatus.connected?'text-emerald-400 border-emerald-700 bg-emerald-900/30':'text-zinc-500 border-zinc-700 bg-zinc-800'}`,title:'Native Bridge (C++ engine) — '+(bridgeStatus?JSON.stringify(bridgeStatus).slice(0,120):'chưa query')},bridgeStatus&&bridgeStatus.connected?'● Bridge ON':'● Bridge OFF'),React.createElement('button',{onClick:onClose,className:'text-zinc-500 hover:text-zinc-200 transition'},React.createElement('i',{'data-lucide':'x',className:'w-4 h-4'})))),// Left-right body
React.createElement('div',{className:'flex flex-1 overflow-hidden',style:{minHeight:'300px'}},// Left sidebar
@@ -972,7 +972,7 @@ if(ok&&window.__bridgeLastProgram){const _pfx=trackId+':';Object.keys(window.__b
// transport STOP; setReloading trước job (G0.1b) + 1 UiThread (G1.2)
// chặn race 2 thread 1 DLL. Mute ngắn ~0.1-0.3s lần đầu, note đang
// ngân không mất. Reopen sau khi đóng vẫn mute 1-3s (reload) — level 2.
if(ok&&btype==='VST3'&&window.NativeBridgeService.openNativeGUI){try{await openVstGuiRetry(instrumentId,bch,20);}catch(e){}}}})();};const setTrackInstrumentWithProgram=(trackId,instrumentId,programNumber,displayName,bankNumber)=>{const isSfInstrument=instrumentId&&typeof instrumentId==='string'&&instrumentId.startsWith('sf_');const sfBank=bankNumber!==undefined?bankNumber:isSfInstrument?0:undefined;const sfProg=programNumber!==undefined?programNumber:undefined;var mt=activeTracksRef.current||tracks;var curTrk=null;for(var ci=0;ci<mt.length;ci++){if(mt[ci].id===trackId){curTrk=mt[ci];break;}}// ── Unload Carla bridge khi chuyển từ VSTi sang instrument KHÔNG phải VST ──
if(ok&&(btype==='VST3'||btype==='VST2')&&window.NativeBridgeService.openNativeGUI){try{await openVstGuiRetry(instrumentId,bch,20);}catch(e){}}}})();};const setTrackInstrumentWithProgram=(trackId,instrumentId,programNumber,displayName,bankNumber)=>{const isSfInstrument=instrumentId&&typeof instrumentId==='string'&&instrumentId.startsWith('sf_');const sfBank=bankNumber!==undefined?bankNumber:isSfInstrument?0:undefined;const sfProg=programNumber!==undefined?programNumber:undefined;var mt=activeTracksRef.current||tracks;var curTrk=null;for(var ci=0;ci<mt.length;ci++){if(mt[ci].id===trackId){curTrk=mt[ci];break;}}// ── Unload Carla bridge khi chuyển từ VSTi sang instrument KHÔNG phải VST ──
// (soundfont/GM/default). Nếu không, Carla vẫn chạy với VSTi cũ → MIDI vẫn
// play qua Carla bridge (âm sai instrument + âm kẹt không dừng được).
try{const _hasInst=!!instrumentId;const _wasVst=curTrk&&curTrk.synth_engine&&String(curTrk.synth_engine.type||'').indexOf('vst')!==-1;const _nowVst=_hasInst&&!isSfInstrument;if(_wasVst&&!_nowVst&&window.SonicCarlaMidi&&window.SonicCarlaMidi.stopBridge){window.SonicCarlaMidi.stopBridge();try{if(window.SonicMidiRouter)window.SonicMidiRouter.panic();else if(window.SonicSF&&window.SonicSF.stopAll)window.SonicSF.stopAll();}catch(e){}stopAllNativeSfNotes();stopAllNativeVstNotes();console.log('[Instrument] Carla bridge unloaded — track',trackId,'switched from VSTi to non-VST');}}catch(e){console.warn('[Instrument] carla-stop on instrument switch error:',e);}var mch=curTrk?assignTrackMidiChannel(curTrk,mt):sfBank===128?9:0;updateActiveTracks(prev=>prev.map(t=>{if(t.id!==trackId)return t;const hasInstrument=!!instrumentId;const instrType=isSfInstrument?'soundfont':hasInstrument?'vst3':'default';const synthEngine=hasInstrument?{type:instrType,plugin_id:instrumentId,soundfont_bank:sfBank!==undefined?sfBank:0,soundfont_program:sfProg!==undefined?sfProg:0,soundfont_id:isSfInstrument?instrumentId.replace('sf_',''):''}:undefined;return{...t,midiChannel:mch,instrumentId,instrumentProgram:sfProg,instrumentName:displayName,soundfont_bank:sfBank,soundfont_program:sfProg,synth_engine:synthEngine,type:hasInstrument?'MIDI':t.type==='MIDI'?'audio':t.type};}));setInstrumentDropdownTrackId(null);setInstrumentDropdownBtnRect(null);setSynthCategory(null);// Trigger FluidSynth load + program change when soundfont instrument selected
+1 -1
View File
@@ -50,7 +50,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=202608190002" defer></script>
<script src="/static/js/app.precompiled.js?v=202608182235" defer></script>
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
<style>
:root {
Binary file not shown.