Bridge.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. /*
  2. * Bridge.cpp
  3. * ----------
  4. * Purpose: VST plugin bridge (plugin side)
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. // TODO: Translate pointer-sized members in remaining structs: VstVariableIo, VstOfflineTask, VstAudioFile, VstWindow (all these are currently not supported by OpenMPT, so not urgent at all)
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "../common/mptBaseMacros.h"
  12. #include "../common/mptBaseTypes.h"
  13. #include "../common/mptBaseUtils.h"
  14. #include <Windows.h>
  15. #include <ShellAPI.h>
  16. #include <ShlObj.h>
  17. #include <CommDlg.h>
  18. #include <tchar.h>
  19. #include <algorithm>
  20. #include <string>
  21. #if defined(MPT_BUILD_MSVC)
  22. #pragma comment(lib, "comdlg32.lib")
  23. #pragma comment(lib, "ole32.lib")
  24. #pragma comment(lib, "shell32.lib")
  25. #endif
  26. #if MPT_BUILD_DEBUG
  27. #include <intrin.h>
  28. #define MPT_ASSERT(x) \
  29. MPT_MAYBE_CONSTANT_IF(!(x)) \
  30. { \
  31. if(IsDebuggerPresent()) \
  32. __debugbreak(); \
  33. ::MessageBoxA(nullptr, "Debug Assertion Failed:\n\n" #x, "OpenMPT Plugin Bridge", MB_ICONERROR); \
  34. }
  35. #else
  36. #define MPT_ASSERT(x)
  37. #endif
  38. #include "../misc/WriteMemoryDump.h"
  39. #include "Bridge.h"
  40. // Crash handler for writing memory dumps
  41. static LONG WINAPI CrashHandler(_EXCEPTION_POINTERS *pExceptionInfo)
  42. {
  43. WCHAR tempPath[MAX_PATH + 2];
  44. DWORD result = GetTempPathW(MAX_PATH + 1, tempPath);
  45. if(result > 0 && result <= MAX_PATH + 1)
  46. {
  47. std::wstring filename = tempPath;
  48. filename += L"OpenMPT Crash Files\\";
  49. CreateDirectoryW(filename.c_str(), nullptr);
  50. tempPath[0] = 0;
  51. const int ch = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, nullptr, L"'PluginBridge 'yyyy'-'MM'-'dd ", tempPath, mpt::saturate_cast<int>(std::size(tempPath)));
  52. if(ch)
  53. GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, 0, nullptr, L"HH'.'mm'.'ss'.dmp'", tempPath + ch - 1, mpt::saturate_cast<int>(std::size(tempPath)) - ch + 1);
  54. filename += tempPath;
  55. OPENMPT_NAMESPACE::WriteMemoryDump(pExceptionInfo, filename.c_str(), OPENMPT_NAMESPACE::PluginBridge::m_fullMemDump);
  56. }
  57. // Let Windows handle the exception...
  58. return EXCEPTION_CONTINUE_SEARCH;
  59. }
  60. int _tmain(int argc, TCHAR *argv[])
  61. {
  62. if(argc != 2)
  63. {
  64. MessageBox(nullptr, _T("This executable is part of OpenMPT. You do not need to run it by yourself."), _T("OpenMPT Plugin Bridge"), 0);
  65. return -1;
  66. }
  67. ::SetUnhandledExceptionFilter(CrashHandler);
  68. // We don't need COM, but some plugins do and don't initialize it themselves.
  69. // Note 1: Which plugins? This was added in r6459 on 2016-05-31 but with no remark whether it fixed a specific plugin,
  70. // but the fix doesn't seem to make a lot of sense since back then no plugin code was ever running on the main thread.
  71. // Could it have been for file dialogs, which were added a while before?
  72. // Note 2: M1 editor crashes if it runs on this thread and it was initialized with COINIT_MULTITHREADED
  73. const bool comInitialized = SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
  74. OPENMPT_NAMESPACE::PluginBridge::MainLoop(argv);
  75. if(comInitialized)
  76. CoUninitialize();
  77. return 0;
  78. }
  79. int WINAPI WinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ LPSTR /*lpCmdLine*/, _In_ int /*nCmdShow*/)
  80. {
  81. int argc = 0;
  82. auto argv = CommandLineToArgvW(GetCommandLineW(), &argc);
  83. return _tmain(argc, argv);
  84. }
  85. OPENMPT_NAMESPACE_BEGIN
  86. using namespace Vst;
  87. std::vector<BridgeCommon *> BridgeCommon::m_plugins;
  88. HWND BridgeCommon::m_communicationWindow = nullptr;
  89. int BridgeCommon::m_instanceCount = 0;
  90. thread_local bool BridgeCommon::m_isAudioThread = false;
  91. // This is kind of a back-up pointer in case we couldn't sneak our pointer into the AEffect struct yet.
  92. // It always points to the last initialized PluginBridge object.
  93. PluginBridge *PluginBridge::m_latestInstance = nullptr;
  94. ATOM PluginBridge::m_editorClassAtom = 0;
  95. bool PluginBridge::m_fullMemDump = false;
  96. void PluginBridge::MainLoop(TCHAR *argv[])
  97. {
  98. WNDCLASSEX editorWndClass;
  99. editorWndClass.cbSize = sizeof(WNDCLASSEX);
  100. editorWndClass.style = CS_HREDRAW | CS_VREDRAW;
  101. editorWndClass.lpfnWndProc = WindowProc;
  102. editorWndClass.cbClsExtra = 0;
  103. editorWndClass.cbWndExtra = 0;
  104. editorWndClass.hInstance = GetModuleHandle(nullptr);
  105. editorWndClass.hIcon = nullptr;
  106. editorWndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
  107. editorWndClass.hbrBackground = nullptr;
  108. editorWndClass.lpszMenuName = nullptr;
  109. editorWndClass.lpszClassName = _T("OpenMPTPluginBridgeEditor");
  110. editorWndClass.hIconSm = nullptr;
  111. m_editorClassAtom = RegisterClassEx(&editorWndClass);
  112. CreateCommunicationWindow(WindowProc);
  113. SetTimer(m_communicationWindow, TIMER_IDLE, 20, IdleTimerProc);
  114. uint32 parentProcessId = _ttoi(argv[1]);
  115. new PluginBridge(argv[0], OpenProcess(SYNCHRONIZE, FALSE, parentProcessId));
  116. MSG msg;
  117. while(::GetMessage(&msg, nullptr, 0, 0))
  118. {
  119. // Let host pre-process key messages like it does for non-bridged plugins
  120. if(msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
  121. {
  122. HWND owner = nullptr;
  123. for(HWND hwnd = msg.hwnd; hwnd != nullptr; hwnd = GetParent(hwnd))
  124. {
  125. // Does it come from a child window? (e.g. Kirnu editor)
  126. if(GetClassWord(hwnd, GCW_ATOM) == m_editorClassAtom)
  127. {
  128. owner = GetParent(GetParent(hwnd));
  129. break;
  130. }
  131. // Does the message come from a top-level window? This is required e.g. for the slider pop-up windows and patch browser in Synth1.
  132. if(!(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD))
  133. {
  134. owner = GetWindow(hwnd, GW_OWNER);
  135. break;
  136. }
  137. }
  138. // Send to top-level VST editor window in host
  139. if(owner && SendMessage(owner, msg.message + WM_BRIDGE_KEYFIRST - WM_KEYFIRST, msg.wParam, msg.lParam))
  140. continue;
  141. }
  142. TranslateMessage(&msg);
  143. DispatchMessage(&msg);
  144. }
  145. DestroyWindow(m_communicationWindow);
  146. }
  147. PluginBridge::PluginBridge(const wchar_t *memName, HANDLE otherProcess)
  148. {
  149. PluginBridge::m_latestInstance = this;
  150. m_thisPluginID = static_cast<int32>(m_plugins.size());
  151. m_plugins.push_back(this);
  152. if(!m_queueMem.Open(memName)
  153. || !CreateSignals(memName))
  154. {
  155. MessageBox(nullptr, _T("Could not connect to OpenMPT."), _T("OpenMPT Plugin Bridge"), 0);
  156. delete this;
  157. return;
  158. }
  159. m_sharedMem = m_queueMem.Data<SharedMemLayout>();
  160. // Store parent process handle so that we can terminate the bridge process when OpenMPT closes (e.g. through a crash).
  161. m_otherProcess.DuplicateFrom(otherProcess);
  162. m_sigThreadExit.Create(true);
  163. DWORD dummy = 0; // For Win9x
  164. m_audioThread = CreateThread(NULL, 0, &PluginBridge::AudioThread, this, 0, &dummy);
  165. m_sharedMem->bridgeCommWindow = m_communicationWindow;
  166. m_sharedMem->bridgePluginID = m_thisPluginID;
  167. m_sigBridgeReady.Trigger();
  168. }
  169. PluginBridge::~PluginBridge()
  170. {
  171. SignalObjectAndWait(m_sigThreadExit, m_audioThread, INFINITE, FALSE);
  172. CloseHandle(m_audioThread);
  173. BridgeMessage dispatchMsg;
  174. dispatchMsg.Dispatch(effClose, 0, 0, 0, 0.0f, 0);
  175. DispatchToPlugin(dispatchMsg.dispatch);
  176. m_plugins[m_thisPluginID] = nullptr;
  177. if(m_instanceCount == 1)
  178. PostQuitMessage(0);
  179. }
  180. void PluginBridge::RequestDelete()
  181. {
  182. PostMessage(m_communicationWindow, WM_BRIDGE_DELETE_PLUGIN, m_thisPluginID, 0);
  183. }
  184. // Send an arbitrary message to the host.
  185. // Returns true if the message was processed by the host.
  186. bool PluginBridge::SendToHost(BridgeMessage &sendMsg)
  187. {
  188. auto &messages = m_sharedMem->ipcMessages;
  189. const auto msgID = CopyToSharedMemory(sendMsg, messages);
  190. if(msgID < 0)
  191. return false;
  192. BridgeMessage &sharedMsg = messages[msgID];
  193. if(!m_isAudioThread)
  194. {
  195. if(SendMessage(m_sharedMem->hostCommWindow, WM_BRIDGE_MESSAGE_TO_HOST, m_otherPluginID, msgID) == WM_BRIDGE_SUCCESS)
  196. {
  197. sharedMsg.CopyTo(sendMsg);
  198. return true;
  199. }
  200. return false;
  201. }
  202. // Audio thread: Use signals instead of window messages
  203. m_sharedMem->audioThreadToHostMsgID = msgID;
  204. m_sigToHostAudio.Send();
  205. // Wait until we get the result from the host.
  206. DWORD result;
  207. const HANDLE objects[] = {m_sigToHostAudio.confirm, m_sigToBridgeAudio.send, m_otherProcess};
  208. do
  209. {
  210. result = WaitForMultipleObjects(mpt::saturate_cast<DWORD>(std::size(objects)), objects, FALSE, INFINITE);
  211. if(result == WAIT_OBJECT_0)
  212. {
  213. // Message got answered
  214. sharedMsg.CopyTo(sendMsg);
  215. break;
  216. } else if(result == WAIT_OBJECT_0 + 1)
  217. {
  218. ParseNextMessage(m_sharedMem->audioThreadToBridgeMsgID);
  219. m_sigToBridgeAudio.Confirm();
  220. }
  221. } while(result != WAIT_OBJECT_0 + 2 && result != WAIT_FAILED);
  222. return (result == WAIT_OBJECT_0);
  223. }
  224. // Copy AEffect to shared memory.
  225. void PluginBridge::UpdateEffectStruct()
  226. {
  227. if(m_nativeEffect == nullptr)
  228. return;
  229. else if(m_otherPtrSize == 4)
  230. m_sharedMem->effect32.FromNative(*m_nativeEffect);
  231. else if(m_otherPtrSize == 8)
  232. m_sharedMem->effect64.FromNative(*m_nativeEffect);
  233. else
  234. MPT_ASSERT(false);
  235. }
  236. // Create the memory-mapped file containing the processing message and audio buffers
  237. void PluginBridge::CreateProcessingFile(std::vector<char> &dispatchData)
  238. {
  239. static uint32 plugId = 0;
  240. wchar_t mapName[64];
  241. swprintf(mapName, std::size(mapName), L"Local\\openmpt-%u-%u", GetCurrentProcessId(), plugId++);
  242. PushToVector(dispatchData, mapName[0], sizeof(mapName));
  243. if(!m_processMem.Create(mapName, sizeof(ProcessMsg) + m_mixBufSize * (m_nativeEffect->numInputs + m_nativeEffect->numOutputs) * sizeof(double)))
  244. {
  245. SendErrorMessage(L"Could not initialize plugin bridge audio memory.");
  246. return;
  247. }
  248. }
  249. // Receive a message from the host and translate it.
  250. void PluginBridge::ParseNextMessage(int msgID)
  251. {
  252. auto &msg = m_sharedMem->ipcMessages[msgID];
  253. switch(msg.header.type)
  254. {
  255. case MsgHeader::newInstance:
  256. NewInstance(msg.newInstance);
  257. break;
  258. case MsgHeader::init:
  259. InitBridge(msg.init);
  260. break;
  261. case MsgHeader::dispatch:
  262. DispatchToPlugin(msg.dispatch);
  263. break;
  264. case MsgHeader::setParameter:
  265. SetParameter(msg.parameter);
  266. break;
  267. case MsgHeader::getParameter:
  268. GetParameter(msg.parameter);
  269. break;
  270. case MsgHeader::automate:
  271. AutomateParameters();
  272. break;
  273. }
  274. }
  275. // Create a new bridge instance within this one (creates a new thread).
  276. void PluginBridge::NewInstance(NewInstanceMsg &msg)
  277. {
  278. msg.memName[mpt::array_size<decltype(msg.memName)>::size - 1] = 0;
  279. new PluginBridge(msg.memName, m_otherProcess);
  280. }
  281. // Load the plugin.
  282. void PluginBridge::InitBridge(InitMsg &msg)
  283. {
  284. m_otherPtrSize = msg.hostPtrSize;
  285. m_mixBufSize = msg.mixBufSize;
  286. m_otherPluginID = msg.pluginID;
  287. m_fullMemDump = msg.fullMemDump != 0;
  288. msg.result = 0;
  289. msg.str[mpt::array_size<decltype(msg.str)>::size - 1] = 0;
  290. #ifdef _CONSOLE
  291. SetConsoleTitleW(msg->str);
  292. #endif
  293. m_nativeEffect = nullptr;
  294. __try
  295. {
  296. m_library = LoadLibraryW(msg.str);
  297. } __except(EXCEPTION_EXECUTE_HANDLER)
  298. {
  299. m_library = nullptr;
  300. }
  301. if(m_library == nullptr)
  302. {
  303. FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msg.str, mpt::saturate_cast<DWORD>(std::size(msg.str)), nullptr);
  304. RequestDelete();
  305. return;
  306. }
  307. auto mainProc = (Vst::MainProc)GetProcAddress(m_library, "VSTPluginMain");
  308. if(mainProc == nullptr)
  309. {
  310. mainProc = (Vst::MainProc)GetProcAddress(m_library, "main");
  311. }
  312. if(mainProc != nullptr)
  313. {
  314. __try
  315. {
  316. m_nativeEffect = mainProc(MasterCallback);
  317. } __except(EXCEPTION_EXECUTE_HANDLER)
  318. {
  319. m_nativeEffect = nullptr;
  320. }
  321. }
  322. if(m_nativeEffect == nullptr || m_nativeEffect->dispatcher == nullptr || m_nativeEffect->magic != kEffectMagic)
  323. {
  324. FreeLibrary(m_library);
  325. m_library = nullptr;
  326. wcscpy(msg.str, L"File is not a valid plugin");
  327. RequestDelete();
  328. return;
  329. }
  330. m_nativeEffect->reservedForHost1 = this;
  331. msg.result = 1;
  332. UpdateEffectStruct();
  333. // Init process buffer
  334. DispatchToHost(audioMasterVendorSpecific, kVendorOpenMPT, kUpdateProcessingBuffer, nullptr, 0.0f);
  335. }
  336. void PluginBridge::SendErrorMessage(const wchar_t *str)
  337. {
  338. BridgeMessage msg;
  339. msg.Error(str);
  340. SendToHost(msg);
  341. }
  342. // Wrapper for VST dispatch call with structured exception handling.
  343. static intptr_t DispatchSEH(AEffect *effect, VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt, bool &exception)
  344. {
  345. __try
  346. {
  347. if(effect->dispatcher != nullptr)
  348. {
  349. return effect->dispatcher(effect, opCode, index, value, ptr, opt);
  350. }
  351. } __except(EXCEPTION_EXECUTE_HANDLER)
  352. {
  353. exception = true;
  354. }
  355. return 0;
  356. }
  357. // Host-to-plugin opcode dispatcher
  358. void PluginBridge::DispatchToPlugin(DispatchMsg &msg)
  359. {
  360. if(m_nativeEffect == nullptr)
  361. {
  362. return;
  363. }
  364. // Various dispatch data - depending on the opcode, one of those might be used.
  365. std::vector<char> extraData;
  366. size_t extraDataSize = 0;
  367. MappedMemory auxMem;
  368. // Content of ptr is usually stored right after the message header, ptr field indicates size.
  369. void *ptr = (msg.ptr != 0) ? (&msg + 1) : nullptr;
  370. if(msg.size > sizeof(BridgeMessage))
  371. {
  372. if(!auxMem.Open(static_cast<const wchar_t *>(ptr)))
  373. {
  374. return;
  375. }
  376. ptr = auxMem.Data();
  377. }
  378. void *origPtr = ptr;
  379. switch(msg.opcode)
  380. {
  381. case effGetProgramName:
  382. case effGetParamLabel:
  383. case effGetParamDisplay:
  384. case effGetParamName:
  385. case effString2Parameter:
  386. case effGetProgramNameIndexed:
  387. case effGetEffectName:
  388. case effGetErrorText:
  389. case effGetVendorString:
  390. case effGetProductString:
  391. case effShellGetNextPlugin:
  392. // Name in [ptr]
  393. extraDataSize = 256;
  394. break;
  395. case effMainsChanged:
  396. // [value]: 0 means "turn off", 1 means "turn on"
  397. ::SetThreadPriority(m_audioThread, msg.value ? THREAD_PRIORITY_ABOVE_NORMAL : THREAD_PRIORITY_NORMAL);
  398. m_sharedMem->tailSize = static_cast<int32>(Dispatch(effGetTailSize, 0, 0, nullptr, 0.0f));
  399. break;
  400. case effEditGetRect:
  401. // ERect** in [ptr]
  402. extraDataSize = sizeof(void *);
  403. break;
  404. case effEditOpen:
  405. // HWND in [ptr] - Note: Window handles are interoperable between 32-bit and 64-bit applications in Windows (http://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx)
  406. {
  407. TCHAR str[_MAX_PATH];
  408. GetModuleFileName(m_library, str, mpt::saturate_cast<DWORD>(std::size(str)));
  409. const auto parentWindow = reinterpret_cast<HWND>(msg.ptr);
  410. ptr = m_window = CreateWindow(
  411. MAKEINTATOM(m_editorClassAtom),
  412. str,
  413. WS_CHILD | WS_VISIBLE,
  414. CW_USEDEFAULT, CW_USEDEFAULT,
  415. 1, 1,
  416. parentWindow,
  417. nullptr,
  418. GetModuleHandle(nullptr),
  419. nullptr);
  420. SetWindowLongPtr(m_window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
  421. }
  422. break;
  423. case effGetChunk:
  424. // void** in [ptr] for chunk data address
  425. extraDataSize = sizeof(void *);
  426. break;
  427. case effProcessEvents:
  428. // VstEvents* in [ptr]
  429. TranslateBridgeToVstEvents(m_eventCache, ptr);
  430. ptr = m_eventCache.data();
  431. break;
  432. case effOfflineNotify:
  433. // VstAudioFile* in [ptr]
  434. extraData.resize(sizeof(VstAudioFile *) * static_cast<size_t>(msg.value));
  435. ptr = extraData.data();
  436. for(int64 i = 0; i < msg.value; i++)
  437. {
  438. // TODO create pointers
  439. }
  440. break;
  441. case effOfflinePrepare:
  442. case effOfflineRun:
  443. // VstOfflineTask* in [ptr]
  444. extraData.resize(sizeof(VstOfflineTask *) * static_cast<size_t>(msg.value));
  445. ptr = extraData.data();
  446. for(int64 i = 0; i < msg.value; i++)
  447. {
  448. // TODO create pointers
  449. }
  450. break;
  451. case effSetSpeakerArrangement:
  452. case effGetSpeakerArrangement:
  453. // VstSpeakerArrangement* in [value] and [ptr]
  454. msg.value = reinterpret_cast<int64>(ptr) + sizeof(VstSpeakerArrangement);
  455. break;
  456. case effVendorSpecific:
  457. // Let's implement some custom opcodes!
  458. if(msg.index == kVendorOpenMPT)
  459. {
  460. msg.result = 1;
  461. switch(msg.value)
  462. {
  463. case kUpdateEffectStruct:
  464. UpdateEffectStruct();
  465. break;
  466. case kUpdateEventMemName:
  467. if(ptr)
  468. m_eventMem.Open(static_cast<const wchar_t *>(ptr));
  469. break;
  470. case kCacheProgramNames:
  471. if(ptr)
  472. {
  473. int32 progMin = static_cast<const int32 *>(ptr)[0];
  474. int32 progMax = static_cast<const int32 *>(ptr)[1];
  475. char *name = static_cast<char *>(ptr);
  476. for(int32 i = progMin; i < progMax; i++)
  477. {
  478. strcpy(name, "");
  479. if(m_nativeEffect->numPrograms <= 0 || Dispatch(effGetProgramNameIndexed, i, -1, name, 0) != 1)
  480. {
  481. // Fallback: Try to get current program name.
  482. strcpy(name, "");
  483. int32 curProg = static_cast<int32>(Dispatch(effGetProgram, 0, 0, nullptr, 0.0f));
  484. if(i != curProg)
  485. {
  486. Dispatch(effSetProgram, 0, i, nullptr, 0.0f);
  487. }
  488. Dispatch(effGetProgramName, 0, 0, name, 0);
  489. if(i != curProg)
  490. {
  491. Dispatch(effSetProgram, 0, curProg, nullptr, 0.0f);
  492. }
  493. }
  494. name[kCachedProgramNameLength - 1] = '\0';
  495. name += kCachedProgramNameLength;
  496. }
  497. }
  498. break;
  499. case kCacheParameterInfo:
  500. if(ptr)
  501. {
  502. int32 paramMin = static_cast<const int32 *>(ptr)[0];
  503. int32 paramMax = static_cast<const int32 *>(ptr)[1];
  504. ParameterInfo *param = static_cast<ParameterInfo *>(ptr);
  505. for(int32 i = paramMin; i < paramMax; i++, param++)
  506. {
  507. strcpy(param->name, "");
  508. strcpy(param->label, "");
  509. strcpy(param->display, "");
  510. Dispatch(effGetParamName, i, 0, param->name, 0.0f);
  511. Dispatch(effGetParamLabel, i, 0, param->label, 0.0f);
  512. Dispatch(effGetParamDisplay, i, 0, param->display, 0.0f);
  513. param->name[mpt::array_size<decltype(param->label)>::size - 1] = '\0';
  514. param->label[mpt::array_size<decltype(param->label)>::size - 1] = '\0';
  515. param->display[mpt::array_size<decltype(param->display)>::size - 1] = '\0';
  516. if(Dispatch(effGetParameterProperties, i, 0, &param->props, 0.0f) != 1)
  517. {
  518. memset(&param->props, 0, sizeof(param->props));
  519. strncpy(param->props.label, param->name, std::size(param->props.label));
  520. }
  521. }
  522. }
  523. break;
  524. case kBeginGetProgram:
  525. if(ptr)
  526. {
  527. int32 numParams = static_cast<int32>((msg.size - sizeof(DispatchMsg)) / sizeof(float));
  528. float *params = static_cast<float *>(ptr);
  529. for(int32 i = 0; i < numParams; i++)
  530. {
  531. params[i] = m_nativeEffect->getParameter(m_nativeEffect, i);
  532. }
  533. }
  534. break;
  535. default:
  536. msg.result = 0;
  537. }
  538. return;
  539. }
  540. break;
  541. }
  542. if(extraDataSize != 0)
  543. {
  544. extraData.resize(extraDataSize, 0);
  545. ptr = extraData.data();
  546. }
  547. //std::cout << "about to dispatch " << msg.opcode << " to effect...";
  548. //std::flush(std::cout);
  549. bool exception = false;
  550. msg.result = static_cast<int32>(DispatchSEH(m_nativeEffect, static_cast<VstOpcodeToPlugin>(msg.opcode), msg.index, static_cast<intptr_t>(msg.value), ptr, msg.opt, exception));
  551. if(exception && msg.opcode != effClose)
  552. {
  553. msg.type = MsgHeader::exceptionMsg;
  554. return;
  555. }
  556. //std::cout << "done" << std::endl;
  557. // Post-fix some opcodes
  558. switch(msg.opcode)
  559. {
  560. case effClose:
  561. m_nativeEffect = nullptr;
  562. FreeLibrary(m_library);
  563. m_library = nullptr;
  564. RequestDelete();
  565. return;
  566. case effGetProgramName:
  567. case effGetParamLabel:
  568. case effGetParamDisplay:
  569. case effGetParamName:
  570. case effString2Parameter:
  571. case effGetProgramNameIndexed:
  572. case effGetEffectName:
  573. case effGetErrorText:
  574. case effGetVendorString:
  575. case effGetProductString:
  576. case effShellGetNextPlugin:
  577. // Name in [ptr]
  578. {
  579. extraData.back() = 0;
  580. char *dst = static_cast<char *>(origPtr);
  581. size_t length = static_cast<size_t>(msg.ptr - 1);
  582. strncpy(dst, extraData.data(), length);
  583. dst[length] = 0;
  584. break;
  585. }
  586. case effEditGetRect:
  587. // ERect** in [ptr]
  588. {
  589. ERect *rectPtr = *reinterpret_cast<ERect **>(extraData.data());
  590. if(rectPtr != nullptr && origPtr != nullptr)
  591. {
  592. MPT_ASSERT(static_cast<size_t>(msg.ptr) >= sizeof(ERect));
  593. std::memcpy(origPtr, rectPtr, std::min(sizeof(ERect), static_cast<size_t>(msg.ptr)));
  594. m_windowWidth = rectPtr->right - rectPtr->left;
  595. m_windowHeight = rectPtr->bottom - rectPtr->top;
  596. // For plugins that don't know their size until after effEditOpen is done.
  597. if(m_window)
  598. {
  599. SetWindowPos(m_window, nullptr, 0, 0, m_windowWidth, m_windowHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  600. }
  601. }
  602. break;
  603. }
  604. case effEditClose:
  605. DestroyWindow(m_window);
  606. m_window = nullptr;
  607. break;
  608. case effGetChunk:
  609. // void** in [ptr] for chunk data address
  610. if(m_getChunkMem.Create(static_cast<const wchar_t *>(origPtr), msg.result))
  611. {
  612. std::memcpy(m_getChunkMem.Data(), *reinterpret_cast<void **>(extraData.data()), msg.result);
  613. }
  614. break;
  615. }
  616. UpdateEffectStruct(); // Regularly update the struct
  617. }
  618. intptr_t PluginBridge::Dispatch(VstOpcodeToPlugin opcode, int32 index, intptr_t value, void *ptr, float opt)
  619. {
  620. __try
  621. {
  622. return m_nativeEffect->dispatcher(m_nativeEffect, opcode, index, value, ptr, opt);
  623. } __except(EXCEPTION_EXECUTE_HANDLER)
  624. {
  625. SendErrorMessage(L"Exception in dispatch()!");
  626. }
  627. return 0;
  628. }
  629. // Set a plugin parameter.
  630. void PluginBridge::SetParameter(ParameterMsg &msg)
  631. {
  632. __try
  633. {
  634. m_nativeEffect->setParameter(m_nativeEffect, msg.index, msg.value);
  635. } __except(EXCEPTION_EXECUTE_HANDLER)
  636. {
  637. msg.type = MsgHeader::exceptionMsg;
  638. }
  639. }
  640. // Get a plugin parameter.
  641. void PluginBridge::GetParameter(ParameterMsg &msg)
  642. {
  643. __try
  644. {
  645. msg.value = m_nativeEffect->getParameter(m_nativeEffect, msg.index);
  646. } __except(EXCEPTION_EXECUTE_HANDLER)
  647. {
  648. msg.type = MsgHeader::exceptionMsg;
  649. }
  650. }
  651. // Execute received parameter automation messages
  652. void PluginBridge::AutomateParameters()
  653. {
  654. __try
  655. {
  656. const AutomationQueue::Parameter *param = m_sharedMem->automationQueue.params;
  657. const AutomationQueue::Parameter *paramEnd = param + std::min(m_sharedMem->automationQueue.pendingEvents.exchange(0), static_cast<int32>(std::size(m_sharedMem->automationQueue.params)));
  658. while(param != paramEnd)
  659. {
  660. m_nativeEffect->setParameter(m_nativeEffect, param->index, param->value);
  661. param++;
  662. }
  663. } __except(EXCEPTION_EXECUTE_HANDLER)
  664. {
  665. SendErrorMessage(L"Exception in setParameter()!");
  666. }
  667. }
  668. // Audio rendering thread
  669. DWORD WINAPI PluginBridge::AudioThread(LPVOID param)
  670. {
  671. static_cast<PluginBridge*>(param)->AudioThread();
  672. return 0;
  673. }
  674. void PluginBridge::AudioThread()
  675. {
  676. m_isAudioThread = true;
  677. const HANDLE objects[] = {m_sigProcessAudio.send, m_sigToBridgeAudio.send, m_sigThreadExit, m_otherProcess};
  678. DWORD result = 0;
  679. do
  680. {
  681. result = WaitForMultipleObjects(mpt::saturate_cast<DWORD>(std::size(objects)), objects, FALSE, INFINITE);
  682. if(result == WAIT_OBJECT_0)
  683. {
  684. ProcessMsg *msg = m_processMem.Data<ProcessMsg>();
  685. AutomateParameters();
  686. m_sharedMem->tailSize = static_cast<int32>(Dispatch(effGetTailSize, 0, 0, nullptr, 0.0f));
  687. m_isProcessing = true;
  688. // Prepare VstEvents.
  689. if(auto *events = m_eventMem.Data<int32>(); events != nullptr && *events != 0)
  690. {
  691. TranslateBridgeToVstEvents(m_eventCache, events);
  692. *events = 0;
  693. Dispatch(effProcessEvents, 0, 0, m_eventCache.data(), 0.0f);
  694. }
  695. switch(msg->processType)
  696. {
  697. case ProcessMsg::process:
  698. Process();
  699. break;
  700. case ProcessMsg::processReplacing:
  701. ProcessReplacing();
  702. break;
  703. case ProcessMsg::processDoubleReplacing:
  704. ProcessDoubleReplacing();
  705. break;
  706. }
  707. m_isProcessing = false;
  708. m_sigProcessAudio.Confirm();
  709. } else if(result == WAIT_OBJECT_0 + 1)
  710. {
  711. ParseNextMessage(m_sharedMem->audioThreadToBridgeMsgID);
  712. m_sigToBridgeAudio.Confirm();
  713. } else if(result == WAIT_OBJECT_0 + 2)
  714. {
  715. // Main thread asked for termination
  716. break;
  717. } else if(result == WAIT_OBJECT_0 + 3)
  718. {
  719. // Host process died
  720. RequestDelete();
  721. break;
  722. }
  723. } while(result != WAIT_FAILED);
  724. }
  725. // Process audio.
  726. void PluginBridge::Process()
  727. {
  728. if(m_nativeEffect->process)
  729. {
  730. float **inPointers, **outPointers;
  731. int32 sampleFrames = BuildProcessPointers(inPointers, outPointers);
  732. __try
  733. {
  734. m_nativeEffect->process(m_nativeEffect, inPointers, outPointers, sampleFrames);
  735. } __except(EXCEPTION_EXECUTE_HANDLER)
  736. {
  737. SendErrorMessage(L"Exception in process()!");
  738. }
  739. }
  740. }
  741. // Process audio.
  742. void PluginBridge::ProcessReplacing()
  743. {
  744. if(m_nativeEffect->processReplacing)
  745. {
  746. float **inPointers, **outPointers;
  747. int32 sampleFrames = BuildProcessPointers(inPointers, outPointers);
  748. __try
  749. {
  750. m_nativeEffect->processReplacing(m_nativeEffect, inPointers, outPointers, sampleFrames);
  751. } __except(EXCEPTION_EXECUTE_HANDLER)
  752. {
  753. SendErrorMessage(L"Exception in processReplacing()!");
  754. }
  755. }
  756. }
  757. // Process audio.
  758. void PluginBridge::ProcessDoubleReplacing()
  759. {
  760. if(m_nativeEffect->processDoubleReplacing)
  761. {
  762. double **inPointers, **outPointers;
  763. int32 sampleFrames = BuildProcessPointers(inPointers, outPointers);
  764. __try
  765. {
  766. m_nativeEffect->processDoubleReplacing(m_nativeEffect, inPointers, outPointers, sampleFrames);
  767. } __except(EXCEPTION_EXECUTE_HANDLER)
  768. {
  769. SendErrorMessage(L"Exception in processDoubleReplacing()!");
  770. }
  771. }
  772. }
  773. // Helper function to build the pointer arrays required by the VST process functions.
  774. template <typename buf_t>
  775. int32 PluginBridge::BuildProcessPointers(buf_t **(&inPointers), buf_t **(&outPointers))
  776. {
  777. MPT_ASSERT(m_processMem.Good());
  778. ProcessMsg &msg = *m_processMem.Data<ProcessMsg>();
  779. const size_t numPtrs = msg.numInputs + msg.numOutputs;
  780. m_sampleBuffers.resize(numPtrs, 0);
  781. if(numPtrs)
  782. {
  783. buf_t *offset = reinterpret_cast<buf_t *>(&msg + 1);
  784. for(size_t i = 0; i < numPtrs; i++)
  785. {
  786. m_sampleBuffers[i] = offset;
  787. offset += msg.sampleFrames;
  788. }
  789. inPointers = reinterpret_cast<buf_t **>(m_sampleBuffers.data());
  790. outPointers = inPointers + msg.numInputs;
  791. }
  792. return msg.sampleFrames;
  793. }
  794. // Send a message to the host.
  795. intptr_t PluginBridge::DispatchToHost(VstOpcodeToHost opcode, int32 index, intptr_t value, void *ptr, float opt)
  796. {
  797. std::vector<char> dispatchData(sizeof(DispatchMsg), 0);
  798. int64 ptrOut = 0;
  799. char *ptrC = static_cast<char *>(ptr);
  800. switch(opcode)
  801. {
  802. case audioMasterAutomate:
  803. case audioMasterVersion:
  804. case audioMasterCurrentId:
  805. case audioMasterIdle:
  806. case audioMasterPinConnected:
  807. break;
  808. case audioMasterWantMidi:
  809. return 1;
  810. case audioMasterGetTime:
  811. // VstTimeInfo* in [return value]
  812. if(m_isProcessing)
  813. {
  814. // During processing, read the cached time info. It won't change during the call
  815. // and we can save some valuable inter-process calls that way.
  816. return ToIntPtr<VstTimeInfo>(&m_sharedMem->timeInfo);
  817. }
  818. break;
  819. case audioMasterProcessEvents:
  820. // VstEvents* in [ptr]
  821. if(ptr == nullptr)
  822. return 0;
  823. TranslateVstEventsToBridge(dispatchData, *static_cast<VstEvents *>(ptr), m_otherPtrSize);
  824. ptrOut = dispatchData.size() - sizeof(DispatchMsg);
  825. // If we are currently processing, try to return the events as part of the process call
  826. if(m_isAudioThread && m_isProcessing && m_eventMem.Good())
  827. {
  828. auto *memBytes = m_eventMem.Data<char>();
  829. auto *eventBytes = m_eventMem.Data<char>() + sizeof(int32);
  830. int32 &memNumEvents = *m_eventMem.Data<int32>();
  831. const auto memEventsSize = BridgeVstEventsSize(memBytes);
  832. if(m_eventMem.Size() >= static_cast<size_t>(ptrOut) + memEventsSize)
  833. {
  834. // Enough shared memory for possibly pre-existing and new events; add new events at the end
  835. memNumEvents += static_cast<VstEvents *>(ptr)->numEvents;
  836. std::memcpy(eventBytes + memEventsSize, dispatchData.data() + sizeof(DispatchMsg) + sizeof(int32), static_cast<size_t>(ptrOut) - sizeof(int32));
  837. return 1;
  838. } else if(memNumEvents)
  839. {
  840. // Not enough memory; merge what we have and what we want to add so that it arrives in the correct order
  841. dispatchData.insert(dispatchData.begin() + sizeof(DispatchMsg) + sizeof(int32), eventBytes, eventBytes + memEventsSize);
  842. *reinterpret_cast<int32 *>(dispatchData.data() + sizeof(DispatchMsg)) += memNumEvents;
  843. memNumEvents = 0;
  844. ptrOut += memEventsSize;
  845. }
  846. }
  847. break;
  848. case audioMasterSetTime:
  849. case audioMasterTempoAt:
  850. case audioMasterGetNumAutomatableParameters:
  851. case audioMasterGetParameterQuantization:
  852. break;
  853. case audioMasterVendorSpecific:
  854. if(index != kVendorOpenMPT || value != kUpdateProcessingBuffer)
  855. {
  856. if(ptr != 0)
  857. {
  858. // Cannot translate this.
  859. return 0;
  860. }
  861. break;
  862. }
  863. [[fallthrough]];
  864. case audioMasterIOChanged:
  865. // We need to be sure that the new values are known to the master.
  866. if(m_nativeEffect != nullptr)
  867. {
  868. UpdateEffectStruct();
  869. CreateProcessingFile(dispatchData);
  870. ptrOut = dispatchData.size() - sizeof(DispatchMsg);
  871. }
  872. break;
  873. case audioMasterNeedIdle:
  874. m_needIdle = true;
  875. return 1;
  876. case audioMasterSizeWindow:
  877. if(m_window)
  878. {
  879. SetWindowPos(m_window, nullptr, 0, 0, index, static_cast<int>(value), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  880. }
  881. break;
  882. case audioMasterGetSampleRate:
  883. case audioMasterGetBlockSize:
  884. case audioMasterGetInputLatency:
  885. case audioMasterGetOutputLatency:
  886. break;
  887. case audioMasterGetPreviousPlug:
  888. case audioMasterGetNextPlug:
  889. // Don't even bother, this would explode :)
  890. return 0;
  891. case audioMasterWillReplaceOrAccumulate:
  892. case audioMasterGetCurrentProcessLevel:
  893. case audioMasterGetAutomationState:
  894. break;
  895. case audioMasterOfflineStart:
  896. case audioMasterOfflineRead:
  897. case audioMasterOfflineWrite:
  898. case audioMasterOfflineGetCurrentPass:
  899. case audioMasterOfflineGetCurrentMetaPass:
  900. // Currently not supported in OpenMPT
  901. return 0;
  902. case audioMasterSetOutputSampleRate:
  903. break;
  904. case audioMasterGetOutputSpeakerArrangement:
  905. case audioMasterGetInputSpeakerArrangement:
  906. // VstSpeakerArrangement* in [return value]
  907. ptrOut = sizeof(VstSpeakerArrangement);
  908. break;
  909. case audioMasterGetVendorString:
  910. case audioMasterGetProductString:
  911. // Name in [ptr]
  912. ptrOut = 256;
  913. break;
  914. case audioMasterGetVendorVersion:
  915. case audioMasterSetIcon:
  916. break;
  917. case audioMasterCanDo:
  918. // Name in [ptr]
  919. ptrOut = strlen(ptrC) + 1;
  920. dispatchData.insert(dispatchData.end(), ptrC, ptrC + ptrOut);
  921. break;
  922. case audioMasterGetLanguage:
  923. case audioMasterOpenWindow:
  924. case audioMasterCloseWindow:
  925. break;
  926. case audioMasterGetDirectory:
  927. // Name in [return value]
  928. ptrOut = 256;
  929. break;
  930. case audioMasterUpdateDisplay:
  931. case audioMasterBeginEdit:
  932. case audioMasterEndEdit:
  933. break;
  934. case audioMasterOpenFileSelector:
  935. // VstFileSelect* in [ptr]
  936. if(ptr != nullptr)
  937. {
  938. auto &fileSel = *static_cast<VstFileSelect *>(ptr);
  939. fileSel.returnMultiplePaths = nullptr;
  940. fileSel.numReturnPaths = 0;
  941. TranslateVstFileSelectToBridge(dispatchData, fileSel, m_otherPtrSize);
  942. ptrOut = dispatchData.size() - sizeof(DispatchMsg) + 65536; // enough space for return paths
  943. }
  944. break;
  945. case audioMasterCloseFileSelector:
  946. // VstFileSelect* in [ptr]
  947. if(auto *fileSel = static_cast<VstFileSelect *>(ptr); fileSel != nullptr && fileSel->reserved == 1)
  948. {
  949. fileSel->returnPath = nullptr;
  950. fileSel->returnMultiplePaths = nullptr;
  951. }
  952. m_fileSelectCache.clear();
  953. m_fileSelectCache.shrink_to_fit();
  954. return 1;
  955. case audioMasterEditFile:
  956. break;
  957. case audioMasterGetChunkFile:
  958. // Name in [ptr]
  959. ptrOut = 256;
  960. dispatchData.insert(dispatchData.end(), ptrC, ptrC + ptrOut);
  961. break;
  962. default:
  963. #ifdef MPT_BUILD_DEBUG
  964. if(ptr != nullptr)
  965. __debugbreak();
  966. #endif
  967. break;
  968. }
  969. if(ptrOut != 0)
  970. {
  971. // In case we only reserve space and don't copy stuff over...
  972. dispatchData.resize(sizeof(DispatchMsg) + static_cast<size_t>(ptrOut), 0);
  973. }
  974. uint32 extraSize = static_cast<uint32>(dispatchData.size() - sizeof(DispatchMsg));
  975. // Create message header
  976. BridgeMessage *msg = reinterpret_cast<BridgeMessage *>(dispatchData.data());
  977. msg->Dispatch(opcode, index, value, ptrOut, opt, extraSize);
  978. const bool useAuxMem = dispatchData.size() > sizeof(BridgeMessage);
  979. MappedMemory auxMem;
  980. if(useAuxMem)
  981. {
  982. // Extra data doesn't fit in message - use secondary memory
  983. wchar_t auxMemName[64];
  984. static_assert(sizeof(DispatchMsg) + sizeof(auxMemName) <= sizeof(BridgeMessage), "Check message sizes, this will crash!");
  985. swprintf(auxMemName, std::size(auxMemName), L"Local\\openmpt-%u-auxmem-%u", GetCurrentProcessId(), GetCurrentThreadId());
  986. if(auxMem.Create(auxMemName, extraSize))
  987. {
  988. // Move message data to shared memory and then move shared memory name to message data
  989. std::memcpy(auxMem.Data(), &dispatchData[sizeof(DispatchMsg)], extraSize);
  990. std::memcpy(&dispatchData[sizeof(DispatchMsg)], auxMemName, sizeof(auxMemName));
  991. } else
  992. {
  993. return 0;
  994. }
  995. }
  996. //std::cout << "about to dispatch " << opcode << " to host...";
  997. //std::flush(std::cout);
  998. if(!SendToHost(*msg))
  999. {
  1000. return 0;
  1001. }
  1002. //std::cout << "done." << std::endl;
  1003. const DispatchMsg *resultMsg = &msg->dispatch;
  1004. const char *extraData = useAuxMem ? auxMem.Data<const char>() : reinterpret_cast<const char *>(resultMsg + 1);
  1005. // Post-fix some opcodes
  1006. switch(opcode)
  1007. {
  1008. case audioMasterGetTime:
  1009. // VstTimeInfo* in [return value]
  1010. return ToIntPtr<VstTimeInfo>(&m_sharedMem->timeInfo);
  1011. case audioMasterGetOutputSpeakerArrangement:
  1012. case audioMasterGetInputSpeakerArrangement:
  1013. // VstSpeakerArrangement* in [return value]
  1014. std::memcpy(&m_host2PlugMem.speakerArrangement, extraData, sizeof(VstSpeakerArrangement));
  1015. return ToIntPtr<VstSpeakerArrangement>(&m_host2PlugMem.speakerArrangement);
  1016. case audioMasterGetVendorString:
  1017. case audioMasterGetProductString:
  1018. // Name in [ptr]
  1019. strcpy(ptrC, extraData);
  1020. break;
  1021. case audioMasterGetDirectory:
  1022. // Name in [return value]
  1023. strncpy(m_host2PlugMem.name, extraData, std::size(m_host2PlugMem.name) - 1);
  1024. m_host2PlugMem.name[std::size(m_host2PlugMem.name) - 1] = 0;
  1025. return ToIntPtr<char>(m_host2PlugMem.name);
  1026. case audioMasterOpenFileSelector:
  1027. if(resultMsg->result != 0 && ptr != nullptr)
  1028. {
  1029. TranslateBridgeToVstFileSelect(m_fileSelectCache, extraData, static_cast<size_t>(ptrOut));
  1030. auto &fileSel = *static_cast<VstFileSelect *>(ptr);
  1031. const auto &fileSelResult = *reinterpret_cast<const VstFileSelect *>(m_fileSelectCache.data());
  1032. if((fileSel.command == kVstFileLoad || fileSel.command == kVstFileSave))
  1033. {
  1034. if(FourCC("VOPM") == m_nativeEffect->uniqueID)
  1035. {
  1036. fileSel.sizeReturnPath = _MAX_PATH;
  1037. }
  1038. } else if(fileSel.command == kVstDirectorySelect)
  1039. {
  1040. if(FourCC("VSTr") == m_nativeEffect->uniqueID && fileSel.returnPath != nullptr && fileSel.sizeReturnPath == 0)
  1041. {
  1042. // Old versions of reViSiT (which still relied on the host's file selector) seem to be dodgy.
  1043. // They report a path size of 0, but when using an own buffer, they will crash.
  1044. // So we'll just assume that reViSiT can handle long enough (_MAX_PATH) paths here.
  1045. fileSel.sizeReturnPath = static_cast<int32>(strlen(fileSelResult.returnPath) + 1);
  1046. }
  1047. }
  1048. fileSel.numReturnPaths = fileSelResult.numReturnPaths;
  1049. fileSel.reserved = 1;
  1050. if(fileSel.command == kVstMultipleFilesLoad)
  1051. {
  1052. fileSel.returnMultiplePaths = fileSelResult.returnMultiplePaths;
  1053. } else if(fileSel.returnPath != nullptr && fileSel.sizeReturnPath != 0)
  1054. {
  1055. // Plugin provides memory
  1056. const auto len = strnlen(fileSelResult.returnPath, fileSel.sizeReturnPath - 1);
  1057. strncpy(fileSel.returnPath, fileSelResult.returnPath, len);
  1058. fileSel.returnPath[len] = '\0';
  1059. fileSel.reserved = 0;
  1060. } else
  1061. {
  1062. fileSel.returnPath = fileSelResult.returnPath;
  1063. fileSel.sizeReturnPath = fileSelResult.sizeReturnPath;
  1064. }
  1065. }
  1066. break;
  1067. case audioMasterGetChunkFile:
  1068. // Name in [ptr]
  1069. strcpy(ptrC, extraData);
  1070. break;
  1071. }
  1072. return static_cast<intptr_t>(resultMsg->result);
  1073. }
  1074. // Helper function for sending messages to the host.
  1075. intptr_t VSTCALLBACK PluginBridge::MasterCallback(AEffect *effect, VstOpcodeToHost opcode, int32 index, intptr_t value, void *ptr, float opt)
  1076. {
  1077. PluginBridge *instance = (effect != nullptr && effect->reservedForHost1 != nullptr) ? static_cast<PluginBridge *>(effect->reservedForHost1) : PluginBridge::m_latestInstance;
  1078. return instance->DispatchToHost(opcode, index, value, ptr, opt);
  1079. }
  1080. LRESULT CALLBACK PluginBridge::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1081. {
  1082. PluginBridge *that = nullptr;
  1083. if(hwnd == m_communicationWindow && wParam < m_plugins.size())
  1084. that = static_cast<PluginBridge *>(m_plugins[wParam]);
  1085. else // Editor windows
  1086. that = reinterpret_cast<PluginBridge *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  1087. if(that == nullptr)
  1088. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1089. switch(uMsg)
  1090. {
  1091. case WM_ERASEBKGND:
  1092. // Pretend that we erased the background
  1093. return 1;
  1094. case WM_SIZE:
  1095. {
  1096. // For plugins that change their size but do not notify the host, e.g. Roland D-50
  1097. RECT rect{0, 0, 0, 0};
  1098. GetClientRect(hwnd, &rect);
  1099. const int width = rect.right - rect.left, height = rect.bottom - rect.top;
  1100. if(width > 0 && height > 0 && (width != that->m_windowWidth || height != that->m_windowHeight))
  1101. {
  1102. that->m_windowWidth = width;
  1103. that->m_windowHeight = height;
  1104. that->DispatchToHost(audioMasterSizeWindow, width, height, nullptr, 0.0f);
  1105. }
  1106. break;
  1107. }
  1108. case WM_BRIDGE_MESSAGE_TO_BRIDGE:
  1109. that->ParseNextMessage(static_cast<int>(lParam));
  1110. return WM_BRIDGE_SUCCESS;
  1111. case WM_BRIDGE_DELETE_PLUGIN:
  1112. delete that;
  1113. return 0;
  1114. }
  1115. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1116. }
  1117. void PluginBridge::IdleTimerProc(HWND, UINT, UINT_PTR idTimer, DWORD)
  1118. {
  1119. if(idTimer != TIMER_IDLE)
  1120. return;
  1121. for(auto *plugin : m_plugins)
  1122. {
  1123. auto *that = static_cast<PluginBridge *>(plugin);
  1124. if(that == nullptr)
  1125. continue;
  1126. if(that->m_needIdle)
  1127. {
  1128. that->Dispatch(effIdle, 0, 0, nullptr, 0.0f);
  1129. that->m_needIdle = false;
  1130. }
  1131. if(that->m_window)
  1132. {
  1133. that->Dispatch(effEditIdle, 0, 0, nullptr, 0.0f);
  1134. }
  1135. }
  1136. }
  1137. OPENMPT_NAMESPACE_END