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.

713 lines
24KB

  1. /*
  2. * Carla Standalone
  3. * Copyright (C) 2011-2015 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaDefines.h"
  18. #ifdef HAVE_LIBLO
  19. #define NSM_API_VERSION_MAJOR 1
  20. #define NSM_API_VERSION_MINOR 2
  21. #define NSM_CLIENT_FEATURES ":switch:"
  22. //#define NSM_CLIENT_FEATURES ":switch:optional-gui:"
  23. #include "CarlaHost.h"
  24. #include "CarlaOscUtils.hpp"
  25. #include "CarlaString.hpp"
  26. #include "juce_core.h"
  27. namespace CB = CarlaBackend;
  28. // -------------------------------------------------------------------------------------------------------------------
  29. struct CarlaBackendStandalone {
  30. CarlaEngine* engine;
  31. EngineCallbackFunc engineCallback;
  32. void* engineCallbackPtr;
  33. // ...
  34. };
  35. extern CarlaBackendStandalone gStandalone;
  36. // -------------------------------------------------------------------------------------------------------------------
  37. class CarlaNSM
  38. {
  39. public:
  40. CarlaNSM() noexcept
  41. : fOscAddress(nullptr),
  42. fOscServer(nullptr),
  43. fOscServerThread(nullptr),
  44. fClientNameId(),
  45. fProjectPath(),
  46. fHasBroadcast(false),
  47. fHasOptionalGui(false),
  48. fHasServerControl(false),
  49. fStarted(),
  50. fReadyActionOpen(true),
  51. fReadyActionSave(true) {}
  52. ~CarlaNSM()
  53. {
  54. CARLA_SAFE_ASSERT(fReadyActionOpen);
  55. CARLA_SAFE_ASSERT(fReadyActionSave);
  56. if (fOscServerThread != nullptr)
  57. {
  58. lo_server_thread_stop(fOscServerThread);
  59. lo_server_thread_free(fOscServerThread);
  60. fOscServerThread = nullptr;
  61. fOscServer = nullptr;
  62. }
  63. if (fOscAddress != nullptr)
  64. {
  65. lo_address_free(fOscAddress);
  66. fOscAddress = nullptr;
  67. }
  68. }
  69. bool announce(const int pid, const char* const executableName)
  70. {
  71. CARLA_SAFE_ASSERT_RETURN(pid != 0, false);
  72. CARLA_SAFE_ASSERT_RETURN(executableName != nullptr && executableName[0] != '\0', false);
  73. const char* const NSM_URL(std::getenv("NSM_URL"));
  74. if (NSM_URL == nullptr)
  75. return false;
  76. const lo_address addr = lo_address_new_from_url(NSM_URL);
  77. CARLA_SAFE_ASSERT_RETURN(addr != nullptr, false);
  78. const int proto = lo_address_get_protocol(addr);
  79. if (fOscServerThread == nullptr)
  80. {
  81. // create new OSC server
  82. fOscServerThread = lo_server_thread_new_with_proto(nullptr, proto, _osc_error_handler);
  83. CARLA_SAFE_ASSERT_RETURN(fOscServerThread != nullptr, false);
  84. // register message handlers
  85. lo_server_thread_add_method(fOscServerThread, "/error", "sis", _error_handler, this);
  86. lo_server_thread_add_method(fOscServerThread, "/reply", "ssss", _reply_handler, this);
  87. lo_server_thread_add_method(fOscServerThread, "/nsm/client/open", "sss", _open_handler, this);
  88. lo_server_thread_add_method(fOscServerThread, "/nsm/client/save", "", _save_handler, this);
  89. lo_server_thread_add_method(fOscServerThread, "/nsm/client/session_is_loaded", "", _loaded_handler, this);
  90. lo_server_thread_add_method(fOscServerThread, "/nsm/client/show_optional_gui", "", _show_gui_handler, this);
  91. lo_server_thread_add_method(fOscServerThread, "/nsm/client/hide_optional_gui", "", _hide_gui_handler, this);
  92. lo_server_thread_add_method(fOscServerThread, nullptr, nullptr, _broadcast_handler, this);
  93. fOscServer = lo_server_thread_get_server(fOscServerThread);
  94. }
  95. lo_send_from(addr, fOscServer, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
  96. "Carla", NSM_CLIENT_FEATURES, executableName, NSM_API_VERSION_MAJOR, NSM_API_VERSION_MINOR, pid);
  97. lo_address_free(addr);
  98. return true;
  99. }
  100. void ready(const int action)
  101. {
  102. CARLA_SAFE_ASSERT_RETURN(fOscServerThread != nullptr,);
  103. switch (action)
  104. {
  105. case -1: // init
  106. CARLA_SAFE_ASSERT_BREAK(! fStarted);
  107. fStarted = true;
  108. lo_server_thread_start(fOscServerThread);
  109. break;
  110. case 0: // error
  111. break;
  112. case 1: // reply
  113. break;
  114. case 2: // open
  115. fReadyActionOpen = true;
  116. break;
  117. case 3: // save
  118. fReadyActionSave = true;
  119. break;
  120. case 4: // session loaded
  121. break;
  122. case 5: // show gui
  123. CARLA_SAFE_ASSERT_BREAK(fOscAddress != nullptr);
  124. CARLA_SAFE_ASSERT_BREAK(fOscServer != nullptr);
  125. lo_send_from(fOscAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "");
  126. break;
  127. case 6: // hide gui
  128. CARLA_SAFE_ASSERT_BREAK(fOscAddress != nullptr);
  129. CARLA_SAFE_ASSERT_BREAK(fOscServer != nullptr);
  130. lo_send_from(fOscAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "");
  131. break;
  132. }
  133. }
  134. static CarlaNSM& getInstance()
  135. {
  136. static CarlaNSM sInstance;
  137. return sInstance;
  138. }
  139. protected:
  140. int handleError(const char* const method, const int code, const char* const message)
  141. {
  142. carla_stdout("CarlaNSM::handleError(\"%s\", %i, \"%s\")", method, code, message);
  143. if (gStandalone.engineCallback != nullptr)
  144. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 0, code, 0.0f, message);
  145. return 1;
  146. // may be unused
  147. (void)method;
  148. }
  149. int handleReply(const char* const method, const char* const message, const char* const smName, const char* const features,
  150. const lo_message msg)
  151. {
  152. CARLA_SAFE_ASSERT_RETURN(fOscServerThread != nullptr, 1);
  153. carla_stdout("CarlaNSM::handleReply(\"%s\", \"%s\", \"%s\", \"%s\")", method, message, smName, features);
  154. if (std::strcmp(method, "/nsm/server/announce") == 0)
  155. {
  156. char* const addressURL(lo_address_get_url(lo_message_get_source(msg)));
  157. CARLA_SAFE_ASSERT_RETURN(addressURL != nullptr, 0);
  158. if (fOscAddress != nullptr)
  159. lo_address_free(fOscAddress);
  160. fOscAddress = lo_address_new_from_url(addressURL);
  161. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 0);
  162. fHasBroadcast = std::strstr(features, ":broadcast:") != nullptr;
  163. fHasOptionalGui = std::strstr(features, ":optional-gui:") != nullptr;
  164. fHasServerControl = std::strstr(features, ":server_control:") != nullptr;
  165. // UI starts visible
  166. if (fHasOptionalGui)
  167. lo_send_from(fOscAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "");
  168. carla_stdout("Carla started via '%s', message: %s", smName, message);
  169. if (gStandalone.engineCallback != nullptr)
  170. {
  171. int flags = 0;
  172. if (fHasBroadcast)
  173. flags |= 1 << 0;
  174. if (fHasOptionalGui)
  175. flags |= 1 << 1;
  176. if (fHasServerControl)
  177. flags |= 1 << 2;
  178. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 1, flags, 0.0f, smName);
  179. }
  180. }
  181. else
  182. {
  183. carla_stdout("Got unknown NSM reply method '%s'", method);
  184. }
  185. return 0;
  186. }
  187. int handleOpen(const char* const projectPath, const char* const displayName, const char* const clientNameId)
  188. {
  189. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  190. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  191. carla_stdout("CarlaNSM::handleOpen(\"%s\", \"%s\", \"%s\")", projectPath, displayName, clientNameId);
  192. if (gStandalone.engineCallback != nullptr)
  193. {
  194. fReadyActionOpen = false;
  195. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 2, 0, 0.0f, projectPath);
  196. for (; ! fReadyActionOpen;)
  197. carla_msleep(10);
  198. }
  199. else
  200. {
  201. using namespace juce;
  202. if (carla_is_engine_running())
  203. carla_engine_close();
  204. carla_engine_init("JACK", clientNameId);
  205. fProjectPath = projectPath;
  206. fProjectPath += ".carxp";
  207. const String jfilename = String(CharPointer_UTF8(fProjectPath));
  208. if (File(jfilename).existsAsFile())
  209. carla_load_project(fProjectPath);
  210. }
  211. fClientNameId = clientNameId;
  212. lo_send_from(fOscAddress, fOscServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/open", "OK");
  213. // Broadcast ourselves
  214. if (fHasBroadcast)
  215. {
  216. char* const oscServerAddress(lo_server_get_url(fOscServer));
  217. if (lo_message msg = lo_message_new())
  218. {
  219. lo_message_add(msg, "sssss",
  220. "/non/hello",
  221. oscServerAddress,
  222. "Carla",
  223. CARLA_VERSION_STRING,
  224. fClientNameId.buffer());
  225. lo_send_message_from(fOscAddress, fOscServer, "/nsm/server/broadcast", msg);
  226. lo_message_free(msg);
  227. }
  228. std::free(oscServerAddress);
  229. }
  230. return 0;
  231. }
  232. int handleSave()
  233. {
  234. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  235. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  236. carla_stdout("CarlaNSM::handleSave()");
  237. if (gStandalone.engineCallback != nullptr)
  238. {
  239. fReadyActionSave = false;
  240. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 3, 0, 0.0f, nullptr);
  241. for (; ! fReadyActionSave;)
  242. carla_msleep(10);
  243. }
  244. else
  245. {
  246. CARLA_SAFE_ASSERT_RETURN(fProjectPath.isNotEmpty(), 0);
  247. carla_save_project(fProjectPath);
  248. }
  249. lo_send_from(fOscAddress, fOscServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/save", "OK");
  250. return 0;
  251. }
  252. int handleSessionIsLoaded()
  253. {
  254. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  255. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  256. carla_stdout("CarlaNSM::handleSessionIsLoaded()");
  257. if (gStandalone.engineCallback != nullptr)
  258. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 4, 0, 0.0f, nullptr);
  259. return 0;
  260. }
  261. int handleShowOptionalGui()
  262. {
  263. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  264. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  265. carla_stdout("CarlaNSM::handleShowOptionalGui()");
  266. if (gStandalone.engineCallback != nullptr)
  267. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 5, 0, 0.0f, nullptr);
  268. return 0;
  269. }
  270. int handleHideOptionalGui()
  271. {
  272. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  273. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  274. carla_stdout("CarlaNSM::handleHideOptionalGui()");
  275. if (gStandalone.engineCallback != nullptr)
  276. gStandalone.engineCallback(gStandalone.engineCallbackPtr, CB::ENGINE_CALLBACK_NSM, 0, 6, 0, 0.0f, nullptr);
  277. return 0;
  278. }
  279. int handleBroadcast(const char* const path, const char* const types, lo_arg** const argv, const int argc,
  280. const lo_message msg)
  281. {
  282. CARLA_SAFE_ASSERT_RETURN(fOscAddress != nullptr, 1);
  283. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 1);
  284. CARLA_SAFE_ASSERT_RETURN(argc >= 0, 0);
  285. carla_stdout("CarlaNSM::handleBroadcast(%s, %s, %p, %i)", path, types, argv, argc);
  286. if (std::strcmp(path, "/non/hello") == 0)
  287. {
  288. CARLA_SAFE_ASSERT_RETURN(argc == 4, 0);
  289. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 0);
  290. const char* const url = &argv[0]->s;
  291. //const char* const name = &argv[1]->s;
  292. //const char* const version = &argv[2]->s;
  293. //const char* const clientId = &argv[3]->s;
  294. const lo_address targetAddress(lo_address_new_from_url(url));
  295. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  296. char* const oscServerAddress(lo_server_get_url(fOscServer));
  297. CARLA_SAFE_ASSERT_RETURN(oscServerAddress != nullptr, 0);
  298. if (lo_message msg2 = lo_message_new())
  299. {
  300. lo_message_add(msg2, "ss",
  301. fClientNameId.buffer(),
  302. oscServerAddress);
  303. lo_send_message_from(targetAddress, fOscServer, "/signal/hello", msg2);
  304. lo_message_free(msg2);
  305. carla_stdout("CarlaNSM::handleBroadcast - sent hello");
  306. }
  307. lo_address_free(targetAddress);
  308. std::free(oscServerAddress);
  309. return 0;
  310. }
  311. if (std::strcmp(path, "/signal/hello") == 0)
  312. {
  313. carla_stdout("CarlaNSM::handleBroadcast - got hello");
  314. //const char* const name = &argv[0]->s;
  315. const char* const url = &argv[1]->s;
  316. const lo_address targetAddress(lo_address_new_from_url(url));
  317. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  318. char* const oscServerAddress(lo_server_get_url(fOscServer));
  319. CARLA_SAFE_ASSERT_RETURN(oscServerAddress != nullptr, 0);
  320. //lo_send_from(targetAddress, fOscServer, LO_TT_IMMEDIATE, "/signal/list", "");
  321. if (lo_message msg2 = lo_message_new())
  322. {
  323. lo_message_add(msg2, "ss",
  324. fClientNameId.buffer(),
  325. oscServerAddress);
  326. lo_send_message_from(targetAddress, fOscServer, "/signal/hello", msg2);
  327. lo_message_free(msg2);
  328. carla_stdout("CarlaNSM::handleBroadcast - sent hello");
  329. }
  330. lo_address_free(targetAddress);
  331. std::free(oscServerAddress);
  332. return 0;
  333. }
  334. if (std::strcmp(path, "/signal/list") == 0)
  335. {
  336. carla_stdout("CarlaNSM::handleBroadcast - got list");
  337. CARLA_SAFE_ASSERT_RETURN(carla_is_engine_running(), 0);
  338. //const char* prefix = nullptr;
  339. //if (argc > 0)
  340. //prefix = &argv[0]->s;
  341. const lo_address targetAddress(lo_message_get_source(msg));
  342. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  343. CarlaString stripName;
  344. for (uint32_t i = 0, pluginCount = carla_get_current_plugin_count(); i < pluginCount; ++i)
  345. {
  346. const CarlaPluginInfo* const pluginInfo(carla_get_plugin_info(i));
  347. CARLA_SAFE_ASSERT_CONTINUE(pluginInfo != nullptr);
  348. for (uint32_t j=0, paramCount = carla_get_parameter_count(i); j < paramCount; ++j)
  349. {
  350. const CarlaParameterInfo* const paramInfo(carla_get_parameter_info(i, j));
  351. CARLA_SAFE_ASSERT_CONTINUE(paramInfo != nullptr);
  352. const ParameterData* const paramData(carla_get_parameter_data(i, j));
  353. CARLA_SAFE_ASSERT_CONTINUE(paramData != nullptr);
  354. const ParameterRanges* const paramRanges(carla_get_parameter_ranges(i, j));
  355. CARLA_SAFE_ASSERT_CONTINUE(paramRanges != nullptr);
  356. if (paramData->type != CB::PARAMETER_INPUT && paramData->type != CB::PARAMETER_OUTPUT)
  357. continue;
  358. if ((paramData->hints & CB::PARAMETER_IS_ENABLED) == 0)
  359. continue;
  360. if ((paramData->hints & CB::PARAMETER_IS_AUTOMABLE) == 0)
  361. continue;
  362. if (paramData->hints & CB::PARAMETER_IS_READ_ONLY)
  363. continue;
  364. if (lo_message msg2 = lo_message_new())
  365. {
  366. stripName = fClientNameId + "/strip/Unnamed/" + pluginInfo->name + "/" + paramInfo->name;
  367. stripName.replace(' ','_');
  368. lo_message_add(msg2, "sssfff",
  369. path,
  370. stripName.buffer(),
  371. paramData->type == CB::PARAMETER_INPUT ? "in" : "out",
  372. paramRanges->min,
  373. paramRanges->max,
  374. paramRanges->def);
  375. lo_send_message_from(targetAddress, fOscServer, "/reply", msg2);
  376. lo_message_free(msg2);
  377. carla_stdout("CarlaNSM::handleBroadcast - sent list at %i : %i, path: %s", i+1, j+1, stripName.buffer());
  378. }
  379. #if 0
  380. if (prefix == nullptr /*|| strncmp(o->path(), prefix, std::strlen(prefix)) == 0*/)
  381. {
  382. lo_send_from(targetAddress, fOscServer, LO_TT_IMMEDIATE, "/reply", "sssfff",
  383. path,
  384. paramInfo->name,
  385. paramData->type == CB::PARAMETER_INPUT ? "in" : "out",
  386. paramRanges->min,
  387. paramRanges->max,
  388. paramRanges->def);
  389. }
  390. #endif
  391. }
  392. }
  393. if (lo_message msg2 = lo_message_new())
  394. {
  395. lo_message_add(msg2, "s", path);
  396. lo_send_message_from(targetAddress, fOscServer, "/reply", msg2);
  397. lo_message_free(msg2);
  398. carla_stdout("CarlaNSM::handleBroadcast - sent list final");
  399. }
  400. //lo_send_from(targetAddress, fOscServer, LO_TT_IMMEDIATE, "/reply", "s", path);
  401. //return 0;
  402. }
  403. #if 0
  404. if (std::strcmp(path, "/reply") == 0)
  405. {
  406. CARLA_SAFE_ASSERT_RETURN(argc > 0, 0);
  407. const char* const method = &argv[0]->s;
  408. if (std::strcmp(method, "/signal/list") == 0)
  409. {
  410. carla_stdout("CarlaNSM::handleBroadcast - got new list");
  411. if (argc == 1)
  412. return 0;
  413. CARLA_SAFE_ASSERT_RETURN(argc == 6, 0);
  414. const lo_address targetAddress(lo_message_get_source(msg));
  415. CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
  416. const char* const stripName = &argv[1]->s;
  417. const char* const orientation = &argv[2]->s;
  418. const float min = argv[3]->f;
  419. const float max = argv[4]->f;
  420. const float def = argv[5]->f;
  421. if (lo_message msg2 = lo_message_new())
  422. {
  423. lo_message_add(msg2, "sssfff",
  424. method,
  425. stripName,
  426. orientation,
  427. min,
  428. max,
  429. def);
  430. lo_send_message_from(targetAddress, fOscServer, "/reply", msg2);
  431. lo_message_free(msg2);
  432. }
  433. }
  434. else
  435. {
  436. CARLA_SAFE_ASSERT(false);
  437. }
  438. return 0;
  439. }
  440. #endif
  441. // check if all args are strings
  442. for (int i=0; i<argc; ++i)
  443. {
  444. if (types[i] != 's')
  445. return 0;
  446. }
  447. for (int i=0; i<argc; ++i)
  448. carla_stdout("%i: %s", i+1, &argv[i]->s);
  449. return 0;
  450. }
  451. private:
  452. lo_address fOscAddress;
  453. lo_server fOscServer;
  454. lo_server_thread fOscServerThread;
  455. CarlaString fClientNameId;
  456. CarlaString fProjectPath;
  457. bool fHasBroadcast;
  458. bool fHasOptionalGui;
  459. bool fHasServerControl;
  460. bool fStarted;
  461. volatile bool fReadyActionOpen;
  462. volatile bool fReadyActionSave;
  463. #define handlePtr ((CarlaNSM*)data)
  464. static void _osc_error_handler(int num, const char* msg, const char* path)
  465. {
  466. carla_stderr2("CarlaNSM::_osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
  467. }
  468. static int _error_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
  469. {
  470. CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
  471. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sis") == 0, 1);
  472. const char* const method = &argv[0]->s;
  473. const int code = argv[1]->i;
  474. const char* const message = &argv[2]->s;
  475. return handlePtr->handleError(method, code, message);
  476. }
  477. static int _reply_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
  478. {
  479. CARLA_SAFE_ASSERT_RETURN(argc == 4, 1);
  480. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 1);
  481. const char* const method = &argv[0]->s;
  482. const char* const message = &argv[1]->s;
  483. const char* const smName = &argv[2]->s;
  484. const char* const features = &argv[3]->s;
  485. return handlePtr->handleReply(method, message, smName, features, msg);
  486. }
  487. static int _open_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
  488. {
  489. CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
  490. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sss") == 0, 1);
  491. const char* const projectPath = &argv[0]->s;
  492. const char* const displayName = &argv[1]->s;
  493. const char* const clientNameId = &argv[2]->s;
  494. return handlePtr->handleOpen(projectPath, displayName, clientNameId);
  495. }
  496. static int _save_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  497. {
  498. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  499. return handlePtr->handleSave();
  500. }
  501. static int _loaded_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  502. {
  503. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  504. return handlePtr->handleSessionIsLoaded();
  505. }
  506. static int _show_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  507. {
  508. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  509. return handlePtr->handleShowOptionalGui();
  510. }
  511. static int _hide_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
  512. {
  513. CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
  514. return handlePtr->handleHideOptionalGui();
  515. }
  516. static int _broadcast_handler(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
  517. {
  518. return handlePtr->handleBroadcast(path, types, argv, argc, msg);
  519. }
  520. #undef handlePtr
  521. CARLA_PREVENT_HEAP_ALLOCATION
  522. CARLA_DECLARE_NON_COPY_CLASS(CarlaNSM)
  523. };
  524. #endif // HAVE_LIBLO
  525. // -------------------------------------------------------------------------------------------------------------------
  526. CARLA_EXPORT
  527. bool carla_nsm_init(int pid, const char* executableName);
  528. bool carla_nsm_init(int pid, const char* executableName)
  529. {
  530. #ifdef HAVE_LIBLO
  531. return CarlaNSM::getInstance().announce(pid, executableName);
  532. #else
  533. return false;
  534. // unused
  535. (void)pid; (void)executableName;
  536. #endif
  537. }
  538. CARLA_EXPORT
  539. void carla_nsm_ready(int action);
  540. void carla_nsm_ready(int action)
  541. {
  542. #ifdef HAVE_LIBLO
  543. CarlaNSM::getInstance().ready(action);
  544. #endif
  545. }
  546. // -------------------------------------------------------------------------------------------------------------------