1 /*
2 * Carla Standalone
3 * Copyright (C) 2011-2020 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
18 #include "CarlaHostImpl.hpp"
19
20 #ifdef HAVE_LIBLO
21
22 #define NSM_API_VERSION_MAJOR 1
23 #define NSM_API_VERSION_MINOR 2
24
25 // #define NSM_CLIENT_FEATURES ":switch:"
26 #define NSM_CLIENT_FEATURES ":switch:optional-gui:"
27
28 #include "CarlaOscUtils.hpp"
29 #include "CarlaString.hpp"
30
31 #include "water/files/File.h"
32
33 // -------------------------------------------------------------------------------------------------------------------
34
35 class CarlaNSM
36 {
37 public:
CarlaNSM(CarlaHostStandalone & shandle)38 CarlaNSM(CarlaHostStandalone& shandle) noexcept
39 : gStandalone(shandle),
40 fReplyAddress(nullptr),
41 fServer(nullptr),
42 fServerThread(nullptr),
43 fServerURL(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 ~CarlaNSM()
54 {
55 CARLA_SAFE_ASSERT(fReadyActionOpen);
56 CARLA_SAFE_ASSERT(fReadyActionSave);
57
58 if (fServerThread != nullptr)
59 {
60 lo_server_thread_stop(fServerThread);
61 lo_server_thread_free(fServerThread);
62 fServerThread = nullptr;
63 fServer = nullptr;
64 }
65
66 if (fServerURL != nullptr)
67 {
68 std::free(fServerURL);
69 fServerURL = nullptr;
70 }
71
72 if (fReplyAddress != nullptr)
73 {
74 lo_address_free(fReplyAddress);
75 fReplyAddress = nullptr;
76 }
77 }
78
announce(const uint64_t pid,const char * const executableName)79 bool announce(const uint64_t pid, const char* const executableName)
80 {
81 CARLA_SAFE_ASSERT_RETURN(pid != 0, false);
82 CARLA_SAFE_ASSERT_RETURN(executableName != nullptr && executableName[0] != '\0', false);
83
84 const char* const NSM_URL(std::getenv("NSM_URL"));
85
86 if (NSM_URL == nullptr)
87 return false;
88
89 const lo_address nsmAddress(lo_address_new_from_url(NSM_URL));
90 CARLA_SAFE_ASSERT_RETURN(nsmAddress != nullptr, false);
91
92 const int proto = lo_address_get_protocol(nsmAddress);
93
94 if (fServerThread == nullptr)
95 {
96 // create new OSC server
97 fServerThread = lo_server_thread_new_with_proto(nullptr, proto, _osc_error_handler);
98 CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr, false);
99
100 // register message handlers
101 lo_server_thread_add_method(fServerThread, "/error", "sis", _error_handler, this);
102 lo_server_thread_add_method(fServerThread, "/reply", "ssss", _reply_handler, this);
103 lo_server_thread_add_method(fServerThread, "/nsm/client/open", "sss", _open_handler, this);
104 lo_server_thread_add_method(fServerThread, "/nsm/client/save", "", _save_handler, this);
105 lo_server_thread_add_method(fServerThread, "/nsm/client/session_is_loaded", "", _loaded_handler, this);
106 lo_server_thread_add_method(fServerThread, "/nsm/client/show_optional_gui", "", _show_gui_handler, this);
107 lo_server_thread_add_method(fServerThread, "/nsm/client/hide_optional_gui", "", _hide_gui_handler, this);
108 lo_server_thread_add_method(fServerThread, nullptr, nullptr, _broadcast_handler, this);
109
110 fServer = lo_server_thread_get_server(fServerThread);
111 fServerURL = lo_server_thread_get_url(fServerThread);
112 }
113
114 const char* appName = std::getenv("CARLA_NSM_NAME");
115
116 if (appName == nullptr)
117 appName = "Carla";
118
119 lo_send_from(nsmAddress, fServer, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
120 appName, NSM_CLIENT_FEATURES, executableName, NSM_API_VERSION_MAJOR, NSM_API_VERSION_MINOR, pid);
121
122 lo_address_free(nsmAddress);
123
124 if (gStandalone.engineCallback != nullptr)
125 {
126 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
127 CB::ENGINE_CALLBACK_NSM,
128 0,
129 CB::NSM_CALLBACK_INIT,
130 0, 0, 0.0f, nullptr);
131 }
132
133 return true;
134 }
135
ready(const NsmCallbackOpcode action)136 void ready(const NsmCallbackOpcode action)
137 {
138 CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr,);
139
140 switch (action)
141 {
142 case CB::NSM_CALLBACK_INIT:
143 CARLA_SAFE_ASSERT_BREAK(! fStarted);
144 fStarted = true;
145 lo_server_thread_start(fServerThread);
146 break;
147
148 case CB::NSM_CALLBACK_ERROR:
149 break;
150
151 case CB::NSM_CALLBACK_ANNOUNCE:
152 break;
153
154 case CB::NSM_CALLBACK_OPEN:
155 fReadyActionOpen = true;
156 break;
157
158 case CB::NSM_CALLBACK_SAVE:
159 fReadyActionSave = true;
160 break;
161
162 case CB::NSM_CALLBACK_SESSION_IS_LOADED:
163 break;
164
165 case CB::NSM_CALLBACK_SHOW_OPTIONAL_GUI:
166 CARLA_SAFE_ASSERT_BREAK(fReplyAddress != nullptr);
167 CARLA_SAFE_ASSERT_BREAK(fServer != nullptr);
168 {
169 // NOTE: lo_send_from is a macro that creates local variables
170 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "");
171 }
172 break;
173
174 case CB::NSM_CALLBACK_HIDE_OPTIONAL_GUI:
175 CARLA_SAFE_ASSERT_BREAK(fReplyAddress != nullptr);
176 CARLA_SAFE_ASSERT_BREAK(fServer != nullptr);
177 {
178 // NOTE: lo_send_from is a macro that creates local variables
179 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "");
180 }
181 break;
182
183 case CB::NSM_CALLBACK_SET_CLIENT_NAME_ID:
184 break;
185 }
186 }
187
getInstance(CarlaHostStandalone & shandle)188 static CarlaNSM& getInstance(CarlaHostStandalone& shandle)
189 {
190 static CarlaNSM sInstance(shandle);
191 return sInstance;
192 }
193
194 protected:
handleError(const char * const method,const int code,const char * const message)195 int handleError(const char* const method, const int code, const char* const message)
196 {
197 carla_stdout("CarlaNSM::handleError(\"%s\", %i, \"%s\")", method, code, message);
198
199 if (gStandalone.engineCallback != nullptr)
200 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
201 CB::ENGINE_CALLBACK_NSM,
202 0,
203 CB::NSM_CALLBACK_ERROR,
204 code,
205 0, 0.0f,
206 message);
207
208 return 0;
209
210 // may be unused
211 (void)method;
212 }
213
handleReply(const char * const method,const char * const message,const char * const smName,const char * const features,const lo_message msg)214 int handleReply(const char* const method, const char* const message, const char* const smName, const char* const features,
215 const lo_message msg)
216 {
217 CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr, 1);
218 carla_stdout("CarlaNSM::handleReply(\"%s\", \"%s\", \"%s\", \"%s\")", method, message, smName, features);
219
220 if (std::strcmp(method, "/nsm/server/announce") == 0)
221 {
222 const lo_address msgAddress(lo_message_get_source(msg));
223 CARLA_SAFE_ASSERT_RETURN(msgAddress != nullptr, 0);
224
225 char* const msgURL(lo_address_get_url(msgAddress));
226 CARLA_SAFE_ASSERT_RETURN(msgURL != nullptr, 0);
227
228 if (fReplyAddress != nullptr)
229 lo_address_free(fReplyAddress);
230
231 fReplyAddress = lo_address_new_from_url(msgURL);
232 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 0);
233
234 fHasBroadcast = std::strstr(features, ":broadcast:") != nullptr;
235 fHasOptionalGui = std::strstr(features, ":optional-gui:") != nullptr;
236 fHasServerControl = std::strstr(features, ":server-control:") != nullptr;
237
238 // UI starts hidden
239 if (fHasOptionalGui)
240 {
241 // NOTE: lo_send_from is a macro that creates local variables
242 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "");
243 }
244
245 carla_stdout("Carla started via '%s', message: %s", smName, message);
246
247 if (gStandalone.engineCallback != nullptr)
248 {
249 int flags = 0;
250
251 if (fHasBroadcast)
252 flags |= 1 << 0;
253 if (fHasOptionalGui)
254 flags |= 1 << 1;
255 if (fHasServerControl)
256 flags |= 1 << 2;
257
258 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
259 CB::ENGINE_CALLBACK_NSM,
260 0,
261 CB::NSM_CALLBACK_ANNOUNCE,
262 flags,
263 0, 0.0f,
264 smName);
265 }
266
267 std::free(msgURL);
268 }
269 else
270 {
271 carla_stdout("Got unknown NSM reply method '%s'", method);
272 }
273
274 return 0;
275 }
276
handleOpen(const char * const projectPath,const char * const displayName,const char * const clientNameId)277 int handleOpen(const char* const projectPath, const char* const displayName, const char* const clientNameId)
278 {
279 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
280 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
281 carla_stdout("CarlaNSM::handleOpen(\"%s\", \"%s\", \"%s\")", projectPath, displayName, clientNameId);
282
283 const CarlaHostHandle handle = (CarlaHostHandle)&gStandalone;
284
285 carla_set_engine_option(handle, CB::ENGINE_OPTION_CLIENT_NAME_PREFIX, 0, clientNameId);
286
287 if (gStandalone.engineCallback != nullptr)
288 {
289 fReadyActionOpen = false;
290 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
291 CB::ENGINE_CALLBACK_NSM,
292 0,
293 CB::NSM_CALLBACK_SET_CLIENT_NAME_ID,
294 0, 0, 0.0f,
295 clientNameId);
296 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
297 CB::ENGINE_CALLBACK_NSM,
298 0,
299 CB::NSM_CALLBACK_OPEN,
300 0, 0, 0.0f,
301 projectPath);
302
303 for (; ! fReadyActionOpen;)
304 carla_msleep(10);
305 }
306 else
307 {
308 using namespace water;
309
310 if (carla_is_engine_running(handle))
311 carla_engine_close(handle);
312
313 // TODO send error if engine failed to initialize
314 carla_engine_init(handle, "JACK", clientNameId);
315
316 fProjectPath = projectPath;
317 fProjectPath += ".carxp";
318
319 const String jfilename = String(CharPointer_UTF8(fProjectPath));
320
321 if (File(jfilename).existsAsFile())
322 carla_load_project(handle, fProjectPath);
323 }
324
325 fClientNameId = clientNameId;
326
327 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/open", "OK");
328
329 // Broadcast ourselves
330 if (fHasBroadcast)
331 {
332 const char* appName = std::getenv("CARLA_NSM_NAME");
333
334 if (appName == nullptr)
335 appName = "Carla";
336
337 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/nsm/server/broadcast", "sssss",
338 "/non/hello", fServerURL, appName, CARLA_VERSION_STRING, fClientNameId.buffer());
339 }
340
341 return 0;
342 }
343
handleSave()344 int handleSave()
345 {
346 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
347 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
348 carla_stdout("CarlaNSM::handleSave()");
349
350 if (gStandalone.engineCallback != nullptr)
351 {
352 fReadyActionSave = false;
353 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
354 CB::ENGINE_CALLBACK_NSM,
355 0,
356 CB::NSM_CALLBACK_SAVE,
357 0, 0, 0.0f, nullptr);
358
359 for (; ! fReadyActionSave;)
360 carla_msleep(10);
361 }
362 else
363 {
364 CARLA_SAFE_ASSERT_RETURN(fProjectPath.isNotEmpty(), 0);
365
366 const CarlaHostHandle handle = (CarlaHostHandle)&gStandalone;
367
368 carla_save_project(handle, fProjectPath);
369 }
370
371 lo_send_from(fReplyAddress, fServer, LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/save", "OK");
372
373 return 0;
374 }
375
handleSessionIsLoaded()376 int handleSessionIsLoaded()
377 {
378 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
379 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
380 carla_stdout("CarlaNSM::handleSessionIsLoaded()");
381
382 if (gStandalone.engineCallback != nullptr)
383 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
384 CB::ENGINE_CALLBACK_NSM,
385 0,
386 CB::NSM_CALLBACK_SESSION_IS_LOADED,
387 0, 0, 0.0f, nullptr);
388
389 return 0;
390 }
391
handleShowOptionalGui()392 int handleShowOptionalGui()
393 {
394 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
395 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
396 carla_stdout("CarlaNSM::handleShowOptionalGui()");
397
398 if (gStandalone.engineCallback != nullptr)
399 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
400 CB::ENGINE_CALLBACK_NSM,
401 0,
402 CB::NSM_CALLBACK_SHOW_OPTIONAL_GUI,
403 0, 0, 0.0f, nullptr);
404
405 return 0;
406 }
407
handleHideOptionalGui()408 int handleHideOptionalGui()
409 {
410 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
411 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
412 carla_stdout("CarlaNSM::handleHideOptionalGui()");
413
414 if (gStandalone.engineCallback != nullptr)
415 gStandalone.engineCallback(gStandalone.engineCallbackPtr,
416 CB::ENGINE_CALLBACK_NSM,
417 0,
418 CB::NSM_CALLBACK_HIDE_OPTIONAL_GUI,
419 0, 0, 0.0f, nullptr);
420
421 return 0;
422 }
423
handleBroadcast(const char * const path,const char * const types,lo_arg ** const argv,const int argc,const lo_message msg)424 int handleBroadcast(const char* const path, const char* const types, lo_arg** const argv, const int argc,
425 const lo_message msg)
426 {
427 CARLA_SAFE_ASSERT_RETURN(fReplyAddress != nullptr, 1);
428 CARLA_SAFE_ASSERT_RETURN(fServer != nullptr, 1);
429 CARLA_SAFE_ASSERT_RETURN(argc >= 0, 0);
430 carla_stdout("CarlaNSM::handleBroadcast(%s, %s, %p, %i)", path, types, argv, argc);
431
432 #if 0
433 if (std::strcmp(path, "/non/hello") == 0)
434 {
435 CARLA_SAFE_ASSERT_RETURN(argc == 4, 0);
436 CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 0);
437
438 const char* const url = &argv[0]->s;
439 //const char* const name = &argv[1]->s;
440 //const char* const version = &argv[2]->s;
441 //const char* const clientId = &argv[3]->s;
442
443 const lo_address targetAddress(lo_address_new_from_url(url));
444 CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
445
446 lo_send_from(targetAddress, fServer, LO_TT_IMMEDIATE, "/signal/hello", "ss",
447 fClientNameId.buffer(), fServerURL);
448
449 lo_address_free(targetAddress);
450
451 return 0;
452 }
453
454 if (std::strcmp(path, "/signal/hello") == 0)
455 {
456 //const char* const name = &argv[0]->s;
457 const char* const url = &argv[1]->s;
458
459 const lo_address targetAddress(lo_address_new_from_url(url));
460 CARLA_SAFE_ASSERT_RETURN(targetAddress != nullptr, 0);
461
462 lo_send_from(targetAddress, fServer, LO_TT_IMMEDIATE, "/signal/hello", "ss",
463 fClientNameId.buffer(), fServerURL);
464
465 lo_address_free(targetAddress);
466
467 return 0;
468 }
469
470 if (std::strcmp(path, "/signal/list") == 0)
471 {
472 carla_stdout("CarlaNSM::handleBroadcast - got list");
473 CARLA_SAFE_ASSERT_RETURN(carla_is_engine_running(), 0);
474
475 const char* prefix = nullptr;
476
477 if (argc > 0)
478 prefix = &argv[0]->s;
479
480 const lo_address msgAddress(lo_message_get_source(msg));
481 CARLA_SAFE_ASSERT_RETURN(msgAddress != nullptr, 0);
482
483 for (uint32_t i = 0, pluginCount = carla_get_current_plugin_count(); i < pluginCount; ++i)
484 {
485 const CarlaPluginInfo* const pluginInfo(carla_get_plugin_info(i));
486 CARLA_SAFE_ASSERT_CONTINUE(pluginInfo != nullptr);
487
488 /*const*/ CarlaString pluginNameId(fClientNameId + "/" + CarlaString(pluginInfo->name).replace('/','_') + "/");
489
490 for (uint32_t j=0, paramCount = carla_get_parameter_count(i); j < paramCount; ++j)
491 {
492 const CarlaParameterInfo* const paramInfo(carla_get_parameter_info(i, j));
493 CARLA_SAFE_ASSERT_CONTINUE(paramInfo != nullptr);
494
495 const ParameterData* const paramData(carla_get_parameter_data(i, j));
496 CARLA_SAFE_ASSERT_CONTINUE(paramData != nullptr);
497
498 const ParameterRanges* const paramRanges(carla_get_parameter_ranges(i, j));
499 CARLA_SAFE_ASSERT_CONTINUE(paramRanges != nullptr);
500
501 if (paramData->type != CB::PARAMETER_INPUT /*&& paramData->type != CB::PARAMETER_OUTPUT*/)
502 continue;
503 if ((paramData->hints & CB::PARAMETER_IS_ENABLED) == 0)
504 continue;
505 if ((paramData->hints & CB::PARAMETER_IS_AUTOMABLE) == 0)
506 continue;
507 if (paramData->hints & CB::PARAMETER_IS_READ_ONLY)
508 continue;
509
510 const char* const dir = paramData->type == CB::PARAMETER_INPUT ? "in" : "out";
511 const CarlaString paramNameId = pluginNameId + CarlaString(paramInfo->name).replace('/','_');
512
513 const float defNorm = paramRanges->getNormalizedValue(paramRanges->def);
514
515 if (prefix == nullptr || std::strncmp(paramNameId, prefix, std::strlen(prefix)) == 0)
516 {
517 lo_send_from(msgAddress, fServer, LO_TT_IMMEDIATE, "/reply", "sssfff",
518 path, paramNameId.buffer(), dir, 0.0f, 1.0f, defNorm);
519 }
520 }
521 }
522
523 lo_send_from(msgAddress, fServer, LO_TT_IMMEDIATE, "/reply", "s", path);
524
525 //return 0;
526 }
527
528 for (int i=0; i<argc; ++i)
529 if (types[i] == 's')
530 carla_stdout("%i: %s", i+1, &argv[i]->s);
531 #endif
532
533 return 0;
534
535 // unused
536 (void)msg;
537 }
538
539 private:
540 CarlaHostStandalone& gStandalone;
541
542 lo_address fReplyAddress;
543 lo_server fServer;
544 lo_server_thread fServerThread;
545 char* fServerURL;
546
547 CarlaString fClientNameId;
548 CarlaString fProjectPath;
549
550 bool fHasBroadcast;
551 bool fHasOptionalGui;
552 bool fHasServerControl;
553 bool fStarted;
554
555 volatile bool fReadyActionOpen;
556 volatile bool fReadyActionSave;
557
558 #define handlePtr ((CarlaNSM*)data)
559
_osc_error_handler(int num,const char * msg,const char * path)560 static void _osc_error_handler(int num, const char* msg, const char* path)
561 {
562 carla_stderr2("CarlaNSM::_osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
563 }
564
_error_handler(const char *,const char * types,lo_arg ** argv,int argc,lo_message,void * data)565 static int _error_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
566 {
567 CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
568 CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sis") == 0, 1);
569
570 const char* const method = &argv[0]->s;
571 const int code = argv[1]->i;
572 const char* const message = &argv[2]->s;
573
574 return handlePtr->handleError(method, code, message);
575 }
576
_reply_handler(const char *,const char * types,lo_arg ** argv,int argc,lo_message msg,void * data)577 static int _reply_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
578 {
579 CARLA_SAFE_ASSERT_RETURN(argc == 4, 1);
580 CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ssss") == 0, 1);
581
582 const char* const method = &argv[0]->s;
583 const char* const message = &argv[1]->s;
584 const char* const smName = &argv[2]->s;
585 const char* const features = &argv[3]->s;
586
587 return handlePtr->handleReply(method, message, smName, features, msg);
588 }
589
_open_handler(const char *,const char * types,lo_arg ** argv,int argc,lo_message,void * data)590 static int _open_handler(const char*, const char* types, lo_arg** argv, int argc, lo_message, void* data)
591 {
592 CARLA_SAFE_ASSERT_RETURN(argc == 3, 1);
593 CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sss") == 0, 1);
594
595 const char* const projectPath = &argv[0]->s;
596 const char* const displayName = &argv[1]->s;
597 const char* const clientNameId = &argv[2]->s;
598
599 return handlePtr->handleOpen(projectPath, displayName, clientNameId);
600 }
601
_save_handler(const char *,const char *,lo_arg **,int argc,lo_message,void * data)602 static int _save_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
603 {
604 CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
605
606 return handlePtr->handleSave();
607 }
608
_loaded_handler(const char *,const char *,lo_arg **,int argc,lo_message,void * data)609 static int _loaded_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
610 {
611 CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
612
613 return handlePtr->handleSessionIsLoaded();
614 }
615
_show_gui_handler(const char *,const char *,lo_arg **,int argc,lo_message,void * data)616 static int _show_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
617 {
618 CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
619
620 return handlePtr->handleShowOptionalGui();
621 }
622
_hide_gui_handler(const char *,const char *,lo_arg **,int argc,lo_message,void * data)623 static int _hide_gui_handler(const char*, const char*, lo_arg**, int argc, lo_message, void* data)
624 {
625 CARLA_SAFE_ASSERT_RETURN(argc == 0, 1);
626
627 return handlePtr->handleHideOptionalGui();
628 }
629
_broadcast_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * data)630 static int _broadcast_handler(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
631 {
632 return handlePtr->handleBroadcast(path, types, argv, argc, msg);
633 }
634
635 #undef handlePtr
636
637 CARLA_PREVENT_HEAP_ALLOCATION
638 CARLA_DECLARE_NON_COPY_CLASS(CarlaNSM)
639 };
640
641 #endif // HAVE_LIBLO
642
643 // -------------------------------------------------------------------------------------------------------------------
644
carla_nsm_init(CarlaHostHandle handle,uint64_t pid,const char * executableName)645 bool carla_nsm_init(CarlaHostHandle handle, uint64_t pid, const char* executableName)
646 {
647 CARLA_SAFE_ASSERT_RETURN(handle->isStandalone, false);
648
649 #ifdef HAVE_LIBLO
650 return CarlaNSM::getInstance(*(CarlaHostStandalone*)handle).announce(pid, executableName);
651 #else
652 return false;
653
654 // unused
655 (void)pid; (void)executableName;
656 #endif
657 }
658
carla_nsm_ready(CarlaHostHandle handle,NsmCallbackOpcode action)659 void carla_nsm_ready(CarlaHostHandle handle, NsmCallbackOpcode action)
660 {
661 CARLA_SAFE_ASSERT_RETURN(handle->isStandalone,);
662
663 #ifdef HAVE_LIBLO
664 CarlaNSM::getInstance(*(CarlaHostStandalone*)handle).ready(action);
665 #else
666 // unused
667 return; (void)action;
668 #endif
669 }
670
671 // -------------------------------------------------------------------------------------------------------------------
672