connect solution into app: VSTi live native (vst3 attach/vst2 bridge) with WASM autosample fallback, VST GUI window (Bug 1), native-first track instrument
This commit is contained in:
@@ -30,8 +30,8 @@ _NATIVE_DIR = (
|
||||
or os.path.join(settings.BASE_DIR, "native_host", "build", "Release")
|
||||
)
|
||||
|
||||
_ERR = None
|
||||
_LOCK = threading.Lock()
|
||||
_ERR = None # khoi tao buffer sau khi dinh nghia _errbuf()
|
||||
_LOCK = threading.RLock() # reentrant: _hidden_hwnd() goi trong ensure_*
|
||||
|
||||
|
||||
def native_dir() -> str:
|
||||
@@ -49,6 +49,39 @@ def _errbuf():
|
||||
def _errval(buf) -> str:
|
||||
return buf.value.decode(errors="replace") if buf and buf.value else ""
|
||||
|
||||
_ERR = _errbuf() # module-level err buffer (dung chung, 256 bytes)
|
||||
|
||||
|
||||
def _hidden_hwnd():
|
||||
"""Tao 1 hidden window dung lam parent cho VST3 editor headless (live).
|
||||
SF_VST3_Attach yeu cau parent_hwnd != NULL; window 0-size khong hien thi."""
|
||||
import ctypes as _ct
|
||||
from ctypes import wintypes as _wt
|
||||
if getattr(_hidden_hwnd, "_hwnd", 0):
|
||||
return _hidden_hwnd._hwnd
|
||||
with _LOCK:
|
||||
if getattr(_hidden_hwnd, "_hwnd", 0):
|
||||
return _hidden_hwnd._hwnd
|
||||
_u = _ct.windll.user32
|
||||
_k = _ct.windll.kernel32
|
||||
_u.DefWindowProcW.argtypes = [_wt.HWND, _wt.UINT, _ct.c_void_p, _ct.c_void_p]
|
||||
_u.DefWindowProcW.restype = _ct.c_long
|
||||
_WNDPROC = _ct.WINFUNCTYPE(_ct.c_long, _wt.HWND, _wt.UINT, _ct.c_void_p, _ct.c_void_p) # WPARAM/LPARAM 64-bit
|
||||
class _WC(_ct.Structure):
|
||||
_fields_ = [("style", _ct.c_uint), ("lpfnWndProc", _WNDPROC), ("cbClsExtra", _ct.c_int),
|
||||
("cbWndExtra", _ct.c_int), ("hInstance", _wt.HINSTANCE), ("hIcon", _wt.HICON),
|
||||
("hCursor", _wt.HANDLE), ("hbrBackground", _wt.HBRUSH), ("lpszMenuName", _wt.LPCWSTR),
|
||||
("lpszClassName", _wt.LPCWSTR)]
|
||||
_wc = _WC()
|
||||
_wc.lpfnWndProc = _WNDPROC(_u.DefWindowProcW)
|
||||
_wc.lpszClassName = "SonicForgeNativeHidden"
|
||||
_wc.hInstance = _k.GetModuleHandleW(None)
|
||||
if _u.RegisterClassW(_ct.byref(_wc)) or _k.GetLastError() == 1410: # 1410 = class ton tai
|
||||
_h = _u.CreateWindowExW(0, "SonicForgeNativeHidden", "sf", 0, 0, 0, 0, 0,
|
||||
None, None, _wc.hInstance, None)
|
||||
_hidden_hwnd._hwnd = _h or 0
|
||||
return _hidden_hwnd._hwnd
|
||||
|
||||
|
||||
def is_available() -> bool:
|
||||
return os.path.isfile(_dll("sf_host_bridge.dll"))
|
||||
@@ -133,11 +166,21 @@ class _Vst3Ctx:
|
||||
self.handle = 0
|
||||
|
||||
def create(self, plugin_path):
|
||||
# Attach can plugin_name = ten class VST3 (ClassInfo::name) + parent
|
||||
# hwnd. Ten class thuong = ten file/folder .vst3; hidden window cho
|
||||
# live headless. Neu ten class khong khop -> rc 0 -> caller fallback.
|
||||
base = os.path.basename(plugin_path.rstrip("\\/"))
|
||||
if base.lower().endswith(".vst3"):
|
||||
plugin_name = base[:-5]
|
||||
else:
|
||||
plugin_name = os.path.splitext(base)[0]
|
||||
w = ctypes.c_int32(0)
|
||||
h = ctypes.c_int32(0)
|
||||
self.handle = self.dll.SF_VST3_Load(plugin_path.encode("utf-8"), 0,
|
||||
ctypes.byref(w), ctypes.byref(h),
|
||||
_ERR, 256)
|
||||
self.handle = self.dll.SF_VST3_Attach(plugin_path.encode("utf-8"),
|
||||
plugin_name.encode("utf-8"),
|
||||
_hidden_hwnd(),
|
||||
ctypes.byref(w), ctypes.byref(h),
|
||||
_ERR, 256)
|
||||
return self.handle
|
||||
|
||||
def close(self):
|
||||
@@ -509,10 +552,10 @@ class NativeAudioService:
|
||||
raise RuntimeError(f"thiếu {_dll('vst3_host_bridge.dll')}")
|
||||
dll = ctypes.WinDLL(_dll("vst3_host_bridge.dll"))
|
||||
i32 = ctypes.c_int32
|
||||
dll.SF_VST3_Load.argtypes = [ctypes.c_char_p, ctypes.c_void_p,
|
||||
ctypes.POINTER(i32), ctypes.POINTER(i32),
|
||||
ctypes.c_char_p, i32]
|
||||
dll.SF_VST3_Load.restype = i32
|
||||
dll.SF_VST3_Attach.argtypes = [ctypes.c_char_p, ctypes.c_char_p,
|
||||
ctypes.c_void_p, ctypes.POINTER(i32),
|
||||
ctypes.POINTER(i32), ctypes.c_char_p, i32]
|
||||
dll.SF_VST3_Attach.restype = i32
|
||||
dll.SF_VST3_SendNoteOn.argtypes = [i32, i32, i32, i32]
|
||||
dll.SF_VST3_SendNoteOn.restype = i32
|
||||
dll.SF_VST3_SendNoteOff.argtypes = [i32, i32, i32]
|
||||
@@ -543,7 +586,7 @@ class NativeAudioService:
|
||||
ctx = _Vst3Ctx(dll)
|
||||
h = ctx.create(plugin_path)
|
||||
if h <= 0:
|
||||
raise RuntimeError(f"SF_VST3_Load fail: {_errval(_ERR)}")
|
||||
raise RuntimeError(f"SF_VST3_Attach fail: {_errval(_ERR)}")
|
||||
ctx.SetMasterGain(h, self._master_lin)
|
||||
if live:
|
||||
rc = ctx.AudioStart(h, self.sample_rate, self.block_size, _ERR, 256)
|
||||
|
||||
Reference in New Issue
Block a user