Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

658 lines
23KB

  1. // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "CarlaHostImpl.hpp"
  4. #if defined(HAVE_LIBLO) && !defined(CARLA_OS_WASM)
  5. #define CARLA_ENABLE_STANDALONE_NSM
  6. #define NSM_API_VERSION_MAJOR 1
  7. #define NSM_API_VERSION_MINOR 2
  8. // #define NSM_CLIENT_FEATURES ":switch:"
  9. #define NSM_CLIENT_FEATURES ":switch:optional-gui:"
  10. #include "CarlaOscUtils.hpp"
  11. #include "CarlaString.hpp"
  12. #include "water/files/File.h"
  13. // -------------------------------------------------------------------------------------------------------------------
  14. class CarlaNSM
  15. {
  16. public:
  17. CarlaNSM(CarlaHostStandalone& shandle) noexcept
  18. : gStandalone(shandle),
  19. fReplyAddress(nullptr),
  20. fServer(nullptr),
  21. fServerThread(nullptr),
  22. fServerURL(nullptr),
  23. fClientNameId(),
  24. fProjectPath(),
  25. fHasBroadcast(false),
  26. fHasOptionalGui(false),
  27. fHasServerControl(false),
  28. fStarted(),
  29. fReadyActionOpen(true),
  30. fReadyActionSave(true) {}
  31. ~CarlaNSM()
  32. {
  33. CARLA_SAFE_ASSERT(fReadyActionOpen);
  34. CARLA_SAFE_ASSERT(fReadyActionSave);
  35. if (fServerThread != nullptr)
  36. {
  37. lo_server_thread_stop(fServerThread);
  38. lo_server_thread_free(fServerThread);
  39. fServerThread = nullptr;
  40. fServer = nullptr;
  41. }
  42. if (fServerURL != nullptr)
  43. {
  44. std::free(fServerURL);
  45. fServerURL = nullptr;
  46. }
  47. if (fReplyAddress != nullptr)
  48. {
  49. lo_address_free(fReplyAddress);
  50. fReplyAddress = nullptr;
  51. }
  52. }
  53. bool announce(const uint64_t pid, const char* const executableName)
  54. {
  55. CARLA_SAFE_ASSERT_RETURN(pid != 0, false);
  56. CARLA_SAFE_ASSERT_RETURN(executableName != nullptr && executableName[0] != '\0', false);
  57. const char* const NSM_URL(std::getenv("NSM_URL"));
  58. if (NSM_URL == nullptr)
  59. return false;
  60. const lo_address nsmAddress(lo_address_new_from_url(NSM_URL));
  61. CARLA_SAFE_ASSERT_RETURN(nsmAddress != nullptr, false);
  62. const int proto = lo_address_get_protocol(nsmAddress);
  63. if (fServerThread == nullptr)
  64. {
  65. // create new OSC server
  66. fServerThread = lo_server_thread_new_with_proto(nullptr, proto, _osc_error_handler);
  67. CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr, false);
  68. // register message handlers
  69. lo_server_thread_add_method(fServerThread, "/error", "sis", _error_handler, this);
  70. lo_server_thread_add_method(fServerThread, "/reply", "ssss", _reply_handler, this);
  71. lo_server_thread_add_method(fServerThread, "/nsm/client/open", "sss", _open_handler, this);
  72. lo_server_thread_add_method(fServerThread, "/nsm/client/save", "", _save_handler, this);
  73. lo_server_thread_add_method(fServerThread, "/nsm/client/session_is_loaded", "", _loaded_handler, this);
  74. lo_server_thread_add_method(fServerThread, "/nsm/client/show_optional_gui", "", _show_gui_handler, this);
  75. lo_server_thread_add_method(fServerThread, "/nsm/client/hide_optional_gui", "", _hide_gui_handler, this);
  76. lo_server_thread_add_method(fServerThread, nullptr, nullptr, _broadcast_handler, this);
  77. fServer = lo_server_thread_get_server(fServerThread);
  78. fServerURL = lo_server_thread_get_url(fServerThread);
  79. }
  80. const char* appName = std::getenv("CARLA_NSM_NAME");
  81. if (appName == nullptr)
  82. appName = "Carla";
  83. lo_send_from(nsmAddress, fServer, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
  84. appName, NSM_CLIENT_FEATURES, executableName, NSM_API_VERSION_MAJOR, NSM_API_VERSION_MINOR, pid);
  85. lo_address_free(nsmAddress);
  86. if (gStandalone.engineCallback != nullptr)
  87. {
  88. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  89. CB::ENGINE_CALLBACK_NSM,
  90. 0,
  91. CB::NSM_CALLBACK_INIT,
  92. 0, 0, 0.0f, nullptr);
  93. }
  94. return true;
  95. }
  96. void ready(const NsmCallbackOpcode action)
  97. {
  98. CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr,);
  99. switch (action)
  100. {
  101. case CB::NSM_CALLBACK_INIT:
  102. CARLA_SAFE_ASSERT_BREAK(! fStarted);
  103. fStarted = true;
  104. lo_server_thread_start(fServerThread);
  105. break;
  106. case CB::NSM_CALLBACK_ERROR:
  107. break;
  108. case CB::NSM_CALLBACK_ANNOUNCE:
  109. break;
  110. case CB::NSM_CALLBACK_OPEN:
  111. fReadyActionOpen = true;
  112. break;
  113. case CB::NSM_CALLBACK_SAVE:
  114. fReadyActionSave = true;
  115. break;
  116. case CB::NSM_CALLBACK_SESSION_IS_LOADED:
  117. break;
  118. case CB::NSM_CALLBACK_SHOW_OPTIONAL_GUI:
  119. CARLA_SAFE_ASSERT_BREAK(fReplyAddress != nullptr);
  120. CARLA_SAFE_ASSERT_BREAK(fServer != nullptr);
  121. {
  122. // NOTE: lo_send_from is a macro that creates local variables
  123. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "");
  124. }
  125. break;
  126. case CB::NSM_CALLBACK_HIDE_OPTIONAL_GUI:
  127. CARLA_SAFE_ASSERT_BREAK(fReplyAddress != nullptr);
  128. CARLA_SAFE_ASSERT_BREAK(fServer != nullptr);
  129. {
  130. // NOTE: lo_send_from is a macro that creates local variables
  131. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "");
  132. }
  133. break;
  134. case CB::NSM_CALLBACK_SET_CLIENT_NAME_ID:
  135. break;
  136. }
  137. }
  138. static CarlaNSM& getInstance(CarlaHostStandalone& shandle)
  139. {
  140. static CarlaNSM sInstance(shandle);
  141. return sInstance;
  142. }
  143. protected:
  144. int handleError(const char* const method, const int code, const char* const message)
  145. {
  146. carla_stdout("CarlaNSM::handleError(\"%s\", %i, \"%s\")", method, code, message);
  147. if (gStandalone.engineCallback != nullptr)
  148. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  149. CB::ENGINE_CALLBACK_NSM,
  150. 0,
  151. CB::NSM_CALLBACK_ERROR,
  152. code,
  153. 0, 0.0f,
  154. message);
  155. return 0;
  156. // may be unused
  157. (void)method;
  158. }
  159. int handleReply(const char* const method, const char* const message, const char* const smName, const char* const features,
  160. const lo_message msg)
  161. {
  162. CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr, 1);
  163. carla_stdout("CarlaNSM::handleReply(\"%s\", \"%s\", \"%s\", \"%s\")", method, message, smName, features);
  164. if (std::strcmp(method, "/nsm/server/announce") == 0)
  165. {
  166. const lo_address msgAddress(lo_message_get_source(msg));
  167. CARLA_SAFE_ASSERT_RETURN(msgAddress != nullptr, 0);
  168. char* const msgURL(lo_address_get_url(msgAddress));
  169. CARLA_SAFE_ASSERT_RETURN(msgURL != nullptr, 0);
  170. if (fReplyAddress != nullptr)
  171. lo_address_free(fReplyAddress);
  172. fReplyAddress = lo_address_new_from_url(msgURL);
  173. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 0);
  174. fHasBroadcast = std::strstr(features, ":broadcast:") != nullptr;
  175. fHasOptionalGui = std::strstr(features, ":optional-gui:") != nullptr;
  176. fHasServerControl = std::strstr(features, ":server-control:") != nullptr;
  177. // UI starts hidden
  178. if (fHasOptionalGui)
  179. {
  180. // NOTE: lo_send_from is a macro that creates local variables
  181. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "");
  182. }
  183. carla_stdout("Carla started via '%s', message: %s", smName, message);
  184. if (gStandalone.engineCallback != nullptr)
  185. {
  186. int flags = 0;
  187. if (fHasBroadcast)
  188. flags |= 1 << 0;
  189. if (fHasOptionalGui)
  190. flags |= 1 << 1;
  191. if (fHasServerControl)
  192. flags |= 1 << 2;
  193. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  194. CB::ENGINE_CALLBACK_NSM,
  195. 0,
  196. CB::NSM_CALLBACK_ANNOUNCE,
  197. flags,
  198. 0, 0.0f,
  199. smName);
  200. }
  201. std::free(msgURL);
  202. }
  203. else
  204. {
  205. carla_stdout("Got unknown NSM reply method '%s'", method);
  206. }
  207. return 0;
  208. }
  209. int handleOpen(const char* const projectPath, const char* const displayName, const char* const clientNameId)
  210. {
  211. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  212. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  213. carla_stdout("CarlaNSM::handleOpen(\"%s\", \"%s\", \"%s\")", projectPath, displayName, clientNameId);
  214. const CarlaHostHandle handle = (CarlaHostHandle)&gStandalone;
  215. carla_set_engine_option(handle, CB::ENGINE_OPTION_CLIENT_NAME_PREFIX, 0, clientNameId);
  216. if (gStandalone.engineCallback != nullptr)
  217. {
  218. fReadyActionOpen = false;
  219. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  220. CB::ENGINE_CALLBACK_NSM,
  221. 0,
  222. CB::NSM_CALLBACK_SET_CLIENT_NAME_ID,
  223. 0, 0, 0.0f,
  224. clientNameId);
  225. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  226. CB::ENGINE_CALLBACK_NSM,
  227. 0,
  228. CB::NSM_CALLBACK_OPEN,
  229. 0, 0, 0.0f,
  230. projectPath);
  231. for (; ! fReadyActionOpen;)
  232. carla_msleep(10);
  233. }
  234. else
  235. {
  236. using namespace water;
  237. if (carla_is_engine_running(handle))
  238. carla_engine_close(handle);
  239. // TODO send error if engine failed to initialize
  240. carla_engine_init(handle, "JACK", clientNameId);
  241. fProjectPath = projectPath;
  242. fProjectPath += ".carxp";
  243. if (File(fProjectPath).existsAsFile())
  244. carla_load_project(handle, fProjectPath);
  245. }
  246. fClientNameId = clientNameId;
  247. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/open", "OK");
  248. // Broadcast ourselves
  249. if (fHasBroadcast)
  250. {
  251. const char* appName = std::getenv("CARLA_NSM_NAME");
  252. if (appName == nullptr)
  253. appName = "Carla";
  254. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/server/broadcast", "sssss",
  255. "/non/hello", fServerURL, appName, CARLA_VERSION_STRING, fClientNameId.buffer());
  256. }
  257. return 0;
  258. }
  259. int handleSave()
  260. {
  261. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  262. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  263. carla_stdout("CarlaNSM::handleSave()");
  264. if (gStandalone.engineCallback != nullptr)
  265. {
  266. fReadyActionSave = false;
  267. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  268. CB::ENGINE_CALLBACK_NSM,
  269. 0,
  270. CB::NSM_CALLBACK_SAVE,
  271. 0, 0, 0.0f, nullptr);
  272. for (; ! fReadyActionSave;)
  273. carla_msleep(10);
  274. }
  275. else
  276. {
  277. CARLA_SAFE_ASSERT_RETURN(fProjectPath.isNotEmpty(), 0);
  278. const CarlaHostHandle handle = (CarlaHostHandle)&gStandalone;
  279. carla_save_project(handle, fProjectPath);
  280. }
  281. lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/save", "OK");
  282. return 0;
  283. }
  284. int handleSessionIsLoaded()
  285. {
  286. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  287. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  288. carla_stdout("CarlaNSM::handleSessionIsLoaded()");
  289. if (gStandalone.engineCallback != nullptr)
  290. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  291. CB::ENGINE_CALLBACK_NSM,
  292. 0,
  293. CB::NSM_CALLBACK_SESSION_IS_LOADED,
  294. 0, 0, 0.0f, nullptr);
  295. return 0;
  296. }
  297. int handleShowOptionalGui()
  298. {
  299. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  300. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  301. carla_stdout("CarlaNSM::handleShowOptionalGui()");
  302. if (gStandalone.engineCallback != nullptr)
  303. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  304. CB::ENGINE_CALLBACK_NSM,
  305. 0,
  306. CB::NSM_CALLBACK_SHOW_OPTIONAL_GUI,
  307. 0, 0, 0.0f, nullptr);
  308. return 0;
  309. }
  310. int handleHideOptionalGui()
  311. {
  312. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  313. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  314. carla_stdout("CarlaNSM::handleHideOptionalGui()");
  315. if (gStandalone.engineCallback != nullptr)
  316. gStandalone.engineCallback(gStandalone.engineCallbackPtr,
  317. CB::ENGINE_CALLBACK_NSM,
  318. 0,
  319. CB::NSM_CALLBACK_HIDE_OPTIONAL_GUI,
  320. 0, 0, 0.0f, nullptr);
  321. return 0;
  322. }
  323. int handleBroadcast(const char* const path, const char* const types, lo_arg** const argv, const int argc,
  324. const lo_message msg)
  325. {
  326. CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
  327. CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
  328. CARLA_SAFE_ASSERT_RETURN(argc >= 0, 0);
  329. carla_stdout("CarlaNSM::handleBroadcast(%s, %s, %p, %i)", path, types, argv, argc);
  330. #if 0
  331. if (std::strcmp(path, "/non/hello") == 0)
  332. {
  333. CARLA_SAFE_ASSERT_RETURN(argc == 4, 0);
  334. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 0);
  335. const char* const url = &argv[0]->s;
  336. //const char* const name = &argv[1]->s;
  337. //const char* const version = &argv[2]->s;
  338. //const char* const clientId = &argv[3]->s;
  339. const lo_address targetAddress(lo_address_new_from_url(url));
  340. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  341. lo_send_from(targetAddress, fServer, LO_TT_IMMEDIATE, "/signal/hello", "ss",
  342. fClientNameId.buffer(), fServerURL);
  343. lo_address_free(targetAddress);
  344. return 0;
  345. }
  346. if (std::strcmp(path, "/signal/hello") == 0)
  347. {
  348. //const char* const name = &argv[0]->s;
  349. const char* const url = &argv[1]->s;
  350. const lo_address targetAddress(lo_address_new_from_url(url));
  351. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  352. lo_send_from(targetAddress, fServer, LO_TT_IMMEDIATE, "/signal/hello", "ss",
  353. fClientNameId.buffer(), fServerURL);
  354. lo_address_free(targetAddress);
  355. return 0;
  356. }
  357. if (std::strcmp(path, "/signal/list") == 0)
  358. {
  359. carla_stdout("CarlaNSM::handleBroadcast - got list");
  360. CARLA_SAFE_ASSERT_RETURN(carla_is_engine_running(), 0);
  361. const char* prefix = nullptr;
  362. if (argc > 0)
  363. prefix = &argv[0]->s;
  364. const lo_address msgAddress(lo_message_get_source(msg));
  365. CARLA_SAFE_ASSERT_RETURN(msgAddress != nullptr, 0);
  366. for (uint32_t i = 0, pluginCount = carla_get_current_plugin_count(); i < pluginCount; ++i)
  367. {
  368. const CarlaPluginInfo* const pluginInfo(carla_get_plugin_info(i));
  369. CARLA_SAFE_ASSERT_CONTINUE(pluginInfo != nullptr);
  370. /*const*/ CarlaString pluginNameId(fClientNameId + "/" + CarlaString(pluginInfo->name).replace('/','_') + "/");
  371. for (uint32_t j=0, paramCount = carla_get_parameter_count(i); j < paramCount; ++j)
  372. {
  373. const CarlaParameterInfo* const paramInfo(carla_get_parameter_info(i, j));
  374. CARLA_SAFE_ASSERT_CONTINUE(paramInfo != nullptr);
  375. const ParameterData* const paramData(carla_get_parameter_data(i, j));
  376. CARLA_SAFE_ASSERT_CONTINUE(paramData != nullptr);
  377. const ParameterRanges* const paramRanges(carla_get_parameter_ranges(i, j));
  378. CARLA_SAFE_ASSERT_CONTINUE(paramRanges != nullptr);
  379. if (paramData->type != CB::PARAMETER_INPUT /*&& paramData->type != CB::PARAMETER_OUTPUT*/)
  380. continue;
  381. if ((paramData->hints & CB::PARAMETER_IS_ENABLED) == 0)
  382. continue;
  383. if ((paramData->hints & CB::PARAMETER_IS_AUTOMATABLE) == 0)
  384. continue;
  385. if (paramData->hints & CB::PARAMETER_IS_READ_ONLY)
  386. continue;
  387. const char* const dir = paramData->type == CB::PARAMETER_INPUT ? "in" : "out";
  388. const CarlaString paramNameId = pluginNameId + CarlaString(paramInfo->name).replace('/','_');
  389. const float defNorm = paramRanges->getNormalizedValue(paramRanges->def);
  390. if (prefix == nullptr || std::strncmp(paramNameId, prefix, std::strlen(prefix)) == 0)
  391. {
  392. lo_send_from(msgAddress, fServer, LO_TT_IMMEDIATE, "/reply", "sssfff",
  393. path, paramNameId.buffer(), dir, 0.0f, 1.0f, defNorm);
  394. }
  395. }
  396. }
  397. lo_send_from(msgAddress, fServer, LO_TT_IMMEDIATE, "/reply", "s", path);
  398. //return 0;
  399. }
  400. for (int i=0; i<argc; ++i)
  401. if (types[i] == 's')
  402. carla_stdout("%i: %s", i+1, &argv[i]->s);
  403. #endif
  404. return 0;
  405. // unused
  406. (void)msg;
  407. }
  408. private:
  409. CarlaHostStandalone& gStandalone;
  410. lo_address fReplyAddress;
  411. lo_server fServer;
  412. lo_server_thread fServerThread;
  413. char* fServerURL;
  414. CarlaString fClientNameId;
  415. CarlaString fProjectPath;
  416. bool fHasBroadcast;
  417. bool fHasOptionalGui;
  418. bool fHasServerControl;
  419. bool fStarted;
  420. volatile bool fReadyActionOpen;
  421. volatile bool fReadyActionSave;
  422. #define handlePtr ((CarlaNSM*)data)
  423. static void _osc_error_handler(int num, const char* msg, const char* path)
  424. {
  425. carla_stderr2("CarlaNSM::_osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
  426. }
  427. static int _error_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
  428. {
  429. CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
  430. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sis") == 0, 1);
  431. const char* const method = &argv[0]->s;
  432. const int code = argv[1]->i;
  433. const char* const message = &argv[2]->s;
  434. return handlePtr->handleError(method, code, message);
  435. }
  436. static int _reply_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
  437. {
  438. CARLA_SAFE_ASSERT_RETURN(argc == 4, 1);
  439. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 1);
  440. const char* const method = &argv[0]->s;
  441. const char* const message = &argv[1]->s;
  442. const char* const smName = &argv[2]->s;
  443. const char* const features = &argv[3]->s;
  444. return handlePtr->handleReply(method, message, smName, features, msg);
  445. }
  446. static int _open_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
  447. {
  448. CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
  449. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sss") == 0, 1);
  450. const char* const projectPath = &argv[0]->s;
  451. const char* const displayName = &argv[1]->s;
  452. const char* const clientNameId = &argv[2]->s;
  453. return handlePtr->handleOpen(projectPath, displayName, clientNameId);
  454. }
  455. static int _save_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  456. {
  457. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  458. return handlePtr->handleSave();
  459. }
  460. static int _loaded_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  461. {
  462. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  463. return handlePtr->handleSessionIsLoaded();
  464. }
  465. static int _show_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  466. {
  467. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  468. return handlePtr->handleShowOptionalGui();
  469. }
  470. static int _hide_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  471. {
  472. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  473. return handlePtr->handleHideOptionalGui();
  474. }
  475. static int _broadcast_handler(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
  476. {
  477. return handlePtr->handleBroadcast(path, types, argv, argc, msg);
  478. }
  479. #undef handlePtr
  480. CARLA_PREVENT_HEAP_ALLOCATION
  481. CARLA_DECLARE_NON_COPYABLE(CarlaNSM)
  482. };
  483. #endif // CARLA_ENABLE_STANDALONE_NSM
  484. // -------------------------------------------------------------------------------------------------------------------
  485. bool carla_nsm_init(CarlaHostHandle handle, uint64_t pid, const char* executableName)
  486. {
  487. CARLA_SAFE_ASSERT_RETURN(handle->isStandalone, false);
  488. #ifdef CARLA_ENABLE_STANDALONE_NSM
  489. return CarlaNSM::getInstance(*(CarlaHostStandalone*)handle).announce(pid, executableName);
  490. #else
  491. return false;
  492. // unused
  493. (void)pid; (void)executableName;
  494. #endif
  495. }
  496. void carla_nsm_ready(CarlaHostHandle handle, NsmCallbackOpcode action)
  497. {
  498. CARLA_SAFE_ASSERT_RETURN(handle->isStandalone,);
  499. #ifdef CARLA_ENABLE_STANDALONE_NSM
  500. CarlaNSM::getInstance(*(CarlaHostStandalone*)handle).ready(action);
  501. #else
  502. // unused
  503. return; (void)action;
  504. #endif
  505. }
  506. // -------------------------------------------------------------------------------------------------------------------