Files
SonicForgeStudio/native_bridge/debug/fix_revert_w2.py
T

195 lines
13 KiB
Python

import subprocess
def load(p):
return open(p, encoding='utf-8', newline='').read()
def save(p, s):
open(p, 'w', encoding='utf-8', newline='').write(s)
def rep(s, needle, repl, tag):
n = s.count(needle)
if n != 1:
raise SystemExit("FAIL %s: needle count=%d" % (tag, n))
return s.replace(needle, repl)
cr = '\r\n'
# ---- main.cpp ----
mp = load('native_bridge/src/main.cpp')
mp = rep(mp,
"int main(int argc, char* argv[]) {" + cr + " std::cout << \"[NativeBridge] Starting DAW Host Bridge Engine...\" << std::endl;" + cr + "#ifdef _WIN32" + cr + " CoInitializeEx(nullptr, COINIT_MULTITHREADED);" + cr + cr + " // Disable Power Throttling (Efficiency Mode) for this background process",
"int main(int argc, char* argv[]) {" + cr + " std::cout << \"[NativeBridge] Starting DAW Host Bridge Engine...\" << std::endl;" + cr + "#ifdef _WIN32" + cr + " // Disable Power Throttling (Efficiency Mode) for this background process",
"coinit")
mp = rep(mp,
" SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &powerState, sizeof(powerState));" + cr + cr + " // Elevate main audio processing thread to time-critical priority" + cr + " SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);",
" SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &powerState, sizeof(powerState));",
"timecritical")
mp = rep(mp,
" instruments.setEditorOpenPredicate([](const std::string& /*lp*/) {" + cr + " return false;" + cr + " });",
" instruments.setEditorOpenPredicate([](const std::string& lp) {" + cr + " std::lock_guard<std::mutex> lk(g_editorMutex);" + cr + " auto it = g_editorPathCount.find(lp);" + cr + " return it != g_editorPathCount.end() && it->second > 0;" + cr + " });",
"predicate")
blob = subprocess.check_output(['git', 'show', '0cec3d3:native_bridge/src/main.cpp']).decode('utf-8')
if '\r\n' not in blob and '\n' in blob:
blob = blob.replace('\n', '\r\n')
def fn_start(s):
i = s.find('static void post_close_gui(uint32_t ch, HWND hwnd) {' + cr + ' ChannelWorker* w = nullptr;')
if i < 0:
i = s.find('static void post_close_gui(uint32_t ch, HWND hwnd) {\n ChannelWorker* w = nullptr;')
if i < 0:
raise SystemExit("fn_start not found")
return i
cur_start = fn_start(mp)
cur_end = mp.find('int main(int argc, char* argv[]) {', cur_start)
old_start = fn_start(blob)
old_end = blob.find('int main(int argc, char* argv[]) {', old_start)
mp = rep(mp, mp[cur_start:cur_end], blob[old_start:old_end], "post_close_gui")
needle5 = (
" workers[guiCh]->post([&instruments, guiCh, arg1, arg2 = pluginId]() {" + cr +
" if (!instruments.get(guiCh)) {" + cr +
" std::cerr << \"[NativeBridge] GUI attach FAILED hwnd=\" << (void*)arg1" + cr +
" << \" plugin=\" << arg2 << \" ch=\" << guiCh << \" (no instrument loaded)\" << std::endl;" + cr +
" return;" + cr +
" }" + cr +
" if (auto* inst0 = instruments.get(guiCh)) {" + cr +
" if (inst0->hasAttachedView()) {" + cr +
" return;" + cr +
" }" + cr +
" }" + cr +
" void* hwnd = (void*)arg1;" + cr +
"#ifdef _WIN32" + cr +
" HWND nativeHwnd = nullptr;" + cr +
" {" + cr +
" std::lock_guard<std::mutex> lock(g_guiMutex);" + cr +
" auto it = g_guiWindows.find(guiCh);" + cr +
" if (it != g_guiWindows.end()) nativeHwnd = (HWND)it->second;" + cr +
" }" + cr +
" if (hwnd == 0) {" + cr +
" if (nativeHwnd && IsWindow(nativeHwnd)) {" + cr +
" hwnd = (void*)nativeHwnd;" + cr +
" SetWindowTextA(nativeHwnd, arg2.c_str());" + cr +
" ShowWindow(nativeHwnd, SW_SHOW);" + cr +
" SetForegroundWindow(nativeHwnd);" + cr +
" // Reuse: cap nhat USERDATA (channel+1) - inst CU da bi thay" + cr +
" // the boi assign() -> WM_DESTROY sau nay lookup inst MOI." + cr +
" SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));" + cr +
" } else {" + cr +
" nativeHwnd = (HWND)create_native_vst_window(arg2.c_str());" + cr +
" if (!nativeHwnd) {" + cr +
" std::cerr << \"[NativeBridge] GUI create window FAILED plugin=\" << arg2 << std::endl;" + cr +
" return;" + cr +
" }" + cr +
" {" + cr +
" std::lock_guard<std::mutex> lock(g_guiMutex);" + cr +
" g_guiWindows[guiCh] = nativeHwnd; // keep window alive" + cr +
" g_hwndToCh[nativeHwnd] = guiCh; // WM_DESTROY cleanup" + cr +
" }" + cr +
" SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));" + cr +
" hwnd = (void*)nativeHwnd;" + cr +
" }" + cr +
" }" + cr +
"#endif" + cr +
" if (auto* inst0 = instruments.get(guiCh)) {" + cr +
" if (inst0->hasAttachedView()) {" + cr +
" return;" + cr +
" }" + cr +
" }" + cr +
"#ifdef _WIN32" + cr +
" // Option B: chi 1 editor VST mo tai 1 thoi diem toan"
)
repl5 = (
" void* hwnd = (void*)arg1;" + cr +
"#ifdef _WIN32" + cr +
" // Window PHAI thuoc MAIN thread (audio loop pump nay dispatch" + cr +
" // messages cua no moi vong lap). Tao/cap nhat window ngay tai day." + cr +
" HWND nativeHwnd = nullptr;" + cr +
" {" + cr +
" std::lock_guard<std::mutex> lock(g_guiMutex);" + cr +
" auto it = g_guiWindows.find(guiCh);" + cr +
" if (it != g_guiWindows.end()) nativeHwnd = (HWND)it->second;" + cr +
" }" + cr +
" if (hwnd == 0) {" + cr +
" if (nativeHwnd && IsWindow(nativeHwnd)) {" + cr +
" hwnd = (void*)nativeHwnd;" + cr +
" SetWindowTextA(nativeHwnd, pluginId.c_str());" + cr +
" ShowWindow(nativeHwnd, SW_SHOW);" + cr +
" SetForegroundWindow(nativeHwnd);" + cr +
" // Reuse: cap nhat USERDATA (channel+1) - inst CU da bi thay" + cr +
" // the boi assign() -> WM_DESTROY sau nay lookup inst MOI." + cr +
" SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));" + cr +
" } else {" + cr +
" nativeHwnd = (HWND)create_native_vst_window(pluginId.c_str());" + cr +
" if (!nativeHwnd) {" + cr +
" std::cerr << \"[NativeBridge] GUI create window FAILED plugin=\" << pluginId << std::endl;" + cr +
" return;" + cr +
" }" + cr +
" {" + cr +
" std::lock_guard<std::mutex> lock(g_guiMutex);" + cr +
" g_guiWindows[guiCh] = nativeHwnd; // keep window alive" + cr +
" g_hwndToCh[nativeHwnd] = guiCh; // WM_DESTROY cleanup" + cr +
" }" + cr +
" SetWindowLongPtrA(nativeHwnd, GWLP_USERDATA, (LONG_PTR)(guiCh + 1));" + cr +
" hwnd = (void*)nativeHwnd;" + cr +
" }" + cr +
" }" + cr +
"#endif" + cr +
" workers[guiCh]->post([&instruments, guiCh, hwnd, arg2 = pluginId]() {" + cr +
" if (!instruments.get(guiCh)) {" + cr +
" std::cerr << \"[NativeBridge] GUI attach FAILED hwnd=\" << hwnd" + cr +
" << \" plugin=\" << arg2 << \" ch=\" << guiCh << \" (no instrument loaded)\" << std::endl;" + cr +
" return;" + cr +
" }" + cr +
" if (auto* inst0 = instruments.get(guiCh)) {" + cr +
" if (inst0->hasAttachedView()) {" + cr +
" return;" + cr +
" }" + cr +
" }" + cr +
"#ifdef _WIN32" + cr +
" // Option B: chi 1 editor VST mo tai 1 thoi diem toan"
)
mp = rep(mp, needle5, repl5, "handleOpenGui-window")
mp = rep(mp,
" try {" + cr + " instruments.setBypassed(true);" + cr + " sleep_ms(10);" + cr + " ok = inst->reloadForGUI();" + cr + " instruments.setBypassed(false);" + cr + " // IME recursion fix: strip the editor's IMC before",
" try {" + cr + " ok = inst->reloadForGUI();" + cr + " // IME recursion fix: strip the editor's IMC before",
"bypass-open1")
mp = rep(mp,
" } catch (...) {" + cr + " instruments.setBypassed(false);" + cr + " std::cerr << \"[NativeBridge] GUI attach EXCEPTION ch=\" << guiCh",
" } catch (...) {" + cr + " std::cerr << \"[NativeBridge] GUI attach EXCEPTION ch=\" << guiCh",
"bypass-open2")
mp = rep(mp,
' << " (channel active with editor open)" << std::endl;',
' << " (channel muted while editor open)" << std::endl;',
"logmsg")
mp = rep(mp,
" if (ch != UINT32_MAX && g_engine) {" + cr + " auto* inst = g_engine->get(ch);" + cr + " if (inst) {" + cr + " inst->resizeView(w, h);" + cr + " }" + cr + " }" + cr + " return 0;",
" if (ch != UINT32_MAX && g_workers) {" + cr + " auto wit = g_workers->find(ch);" + cr + " if (wit != g_workers->end()) {" + cr + " // onSize() must run on the channel worker (the view was attached" + cr + " // in its COM STA apartment), not on the main pump thread." + cr + " wit->second->post([ch, w, h]() {" + cr + " if (!g_engine) return;" + cr + " auto* i = g_engine->get(ch);" + cr + " if (i) i->resizeView(w, h);" + cr + " });" + cr + " }" + cr + " }" + cr + " return 0;",
"wmsize")
save('native_bridge/src/main.cpp', mp)
# ---- Vst3Instrument.cpp ----
vp = load('native_bridge/src/Vst3Instrument.cpp')
vp = rep(vp,
"bool Vst3Instrument::reloadForGUI() {" + cr + "#ifndef HAVE_VST3SDK" + cr + " return false;" + cr + "#else" + cr + " auto* s = static_cast<Vst3HostState*>(state_);" + cr + " if (!s || !s->controller) return false;" + cr + " return true;" + cr + "#endif" + cr + "}",
"bool Vst3Instrument::reloadForGUI() {" + cr + "#ifndef HAVE_VST3SDK" + cr + " return false;" + cr + "#else" + cr + " auto* s = static_cast<Vst3HostState*>(state_);" + cr + " if (!s || !s->controller) return false;" + cr + " if (s->view && guiAttached_) return true;" + cr + " if (hasAttachedOnce_ && !guiAttached_) {" + cr + " // Reopen GUI sau khi dong: mot so plugin (Nexus...) hang o" + cr + " // view->attached() LAN 2 tren cung component instance. Tao lai inst" + cr + " // moi tren CUNG worker thread (COM STA con song) roi attach lai." + cr + " // PHAN NAY PHAI chay tren worker thread — apartment cua channel song" + cr + " // o day; chay tren thread tam thi apartment moi chet ngay sau do" + cr + " // (reopen lan sau -> treo nhu bridge_like)." + cr + " if (!reload()) return false;" + cr + " s = static_cast<Vst3HostState*>(state_);" + cr + " if (!s || !s->controller) return false;" + cr + " }" + cr + " return true;" + cr + "#endif" + cr + "}",
"reloadForGUI")
vp = rep(vp,
"void Vst3Instrument::closeGUI() {" + cr + "#ifndef HAVE_VST3SDK" + cr + " return;" + cr + "#else" + cr + " auto* s = static_cast<Vst3HostState*>(state_);" + cr + " if (s && s->view) {" + cr + " if (guiAttached_) {" + cr + " try {" + cr + " s->view->removed();" + cr + " } catch (...) {" + cr + " std::cerr << \"[Vst3Instrument] Exception inside view->removed()\" << std::endl;" + cr + " }" + cr + " }" + cr + " s->view = nullptr;" + cr + " }" + cr + " guiAttached_ = false;" + cr + "#endif" + cr + "}",
"void Vst3Instrument::closeGUI() {" + cr + "#ifndef HAVE_VST3SDK" + cr + " return;" + cr + "#else" + cr + " auto* s = static_cast<Vst3HostState*>(state_);" + cr + " // Do NOT call s->view->removed(): Nexus's removed() enters an internal" + cr + " // modal wait for a message only this thread's message pump can dispatch" + cr + " // — but this thread is inside removed(), so it deadlocks forever" + cr + " // (observed: closeGUI job never returns; wdisp flood from the editor)." + cr + " // Nulling the view and letting the next terminate() (reload / destructor)" + cr + " // tear the editor windows down on this same thread is the deterministic" + cr + " // path out. Callers (post_close_gui / load job) additionally destroy the" + cr + " // editor's child windows right here on this thread so the plugin stops" + cr + " // pumping; the leaked editor object is inert once its windows are gone." + cr + " if (s) s->view = nullptr;" + cr + " guiAttached_ = false;" + cr + "#endif" + cr + "}",
"closeGUI")
save('native_bridge/src/Vst3Instrument.cpp', vp)
print("ALL EDITS OK")