Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
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.

689 lines
24KB

  1. /*************************************************************************/
  2. /* Copyright (C) 2012 Jonathan Moore Liles */
  3. /* Copyright (C) 2020- Nils Hilbricht */
  4. /* */
  5. /* Permission to use, copy, modify, and/or distribute this software for */
  6. /* any purpose with or without fee is hereby granted, provided that the */
  7. /* above copyright notice and this permission notice appear in all */
  8. /* copies. */
  9. /* */
  10. /* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL */
  11. /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */
  12. /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE */
  13. /* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL */
  14. /* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR */
  15. /* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER */
  16. /* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR */
  17. /* PERFORMANCE OF THIS SOFTWARE. */
  18. /*************************************************************************/
  19. /*************************************************************************/
  20. /* A simple, callback based C API for NSM clients. */
  21. /* */
  22. /* Simplified Example: */
  23. /* */
  24. /* #include "nsm.h" */
  25. /* */
  26. /* static nsm_client_t *nsm = 0; */
  27. /* static int wait_nsm = 1; */
  28. /* */
  29. /* int */
  30. /* cb_nsm_open ( const char *name, */
  31. /* const char *display_name, */
  32. /* const char *client_id, */
  33. /* char **out_msg, */
  34. /* void *userdata ) */
  35. /* { */
  36. /* do_open_stuff(); */
  37. /* wait_nsm = 0; */
  38. /* return ERR_OK; */
  39. /* } */
  40. /* */
  41. /* int */
  42. /* cb_nsm_save ( char **out_msg, */
  43. /* void *userdata ) */
  44. /* { */
  45. /* do_save_stuff(); */
  46. /* return ERR_OK; */
  47. /* } */
  48. /* */
  49. /* void */
  50. /* cb_nsm_show ( void *userdata ) */
  51. /* { */
  52. /* do_show_ui(); */
  53. /* nsm_send_is_shown ( nsm ); */
  54. /* } */
  55. /* */
  56. /* void */
  57. /* cb_nsm_hide ( void *userdata ) */
  58. /* { */
  59. /* do_hide_ui(); */
  60. /* nsm_send_is_hidden ( nsm ); */
  61. /* } */
  62. /* */
  63. /* gboolean */
  64. /* poll_nsm() */
  65. /* { */
  66. /* if ( nsm ) */
  67. /* { */
  68. /* nsm_check_nowait( nsm ); */
  69. /* return true; */
  70. /* } */
  71. /* return false; */
  72. /* } */
  73. /* */
  74. /* int main( int argc, char **argv ) */
  75. /* { */
  76. /* const char *nsm_url = getenv( "NSM_URL" ); */
  77. /* */
  78. /* if ( nsm_url ) */
  79. /* { */
  80. /* nsm = nsm_new(); */
  81. /* */
  82. /* nsm_set_open_callback( nsm, cb_nsm_open, 0 ); */
  83. /* nsm_set_save_callback( nsm, cb_nsm_save, 0 ); */
  84. /* */
  85. /* if ( 0 == nsm_init( nsm, nsm_url ) ) */
  86. /* { */
  87. /* nsm_send_announce( nsm, "FOO", ":optional-gui:", argv[0] );*/
  88. /* */
  89. /* ********************************************************************** */
  90. /* This will block for at most 100 sec and */
  91. /* waiting for the NSM server open callback. */
  92. /* DISCLAIMER: YOU MAY NOT NEED TO DO THAT. */
  93. /* ********************************************************************** */
  94. /* */
  95. /* int timeout = 0; */
  96. /* while ( wait_nsm ) */
  97. /* { */
  98. /* nsm_check_wait( nsm, 500 ); */
  99. /* timeout += 1; */
  100. /* if ( timeout > 200 ) */
  101. /* exit ( 1 ); */
  102. /* } */
  103. /* */
  104. /* ********************************************************************** */
  105. /* This will check if the server support optional-gui */
  106. /* and connect the callbacks when support is found. */
  107. /* If you don't use the above blocking block */
  108. /* this could be done in cb_nsm_open() as well. */
  109. /* DISCLAIMER: YOU MAY NOT NEED TO DO THAT. */
  110. /* ********************************************************************** */
  111. /* */
  112. /* if ( strstr( nsm_get_session_manager_features ( nsm ), */
  113. /* ":optional-gui:" ) ) */
  114. /* { */
  115. /* nsm_set_show_callback( nsm, cb_nsm_show, 0 ); */
  116. /* nsm_set_hide_callback( nsm, cb_nsm_hide, 0 ); */
  117. /* } */
  118. /* */
  119. /* ********************************************************************** */
  120. /* */
  121. /* do_timeout_add( 200, poll_nsm, Null ); */
  122. /* } */
  123. /* else */
  124. /* { */
  125. /* nsm_free( nsm ); */
  126. /* nsm = 0; */
  127. /* } */
  128. /* } */
  129. /* } */
  130. /**************************************************************************/
  131. #ifndef _NSM_H
  132. #define _NSM_H
  133. #define NSM_API_VERSION_MAJOR 1
  134. #define NSM_API_VERSION_MINOR 0
  135. #include <lo/lo.h>
  136. #include <string.h>
  137. #include <sys/types.h>
  138. #include <unistd.h>
  139. #include <stdlib.h>
  140. #include <stdio.h>
  141. typedef void * nsm_client_t;
  142. typedef int (nsm_open_callback)( const char *name, const char *display_name, const char *client_id, char **out_msg, void *userdata );
  143. typedef int (nsm_save_callback)( char **out_msg, void *userdata );
  144. typedef void (nsm_show_gui_callback)( void *userdata );
  145. typedef void (nsm_hide_gui_callback)( void *userdata );
  146. typedef void (nsm_active_callback)( int b, void *userdata );
  147. typedef void (nsm_session_is_loaded_callback)( void *userdata );
  148. typedef int (nsm_broadcast_callback)( const char *, lo_message m, void *userdata );
  149. #define _NSM() ((struct _nsm_client_t*)nsm)
  150. #define NSM_EXPORT __attribute__((unused)) static
  151. /* private parts */
  152. struct _nsm_client_t
  153. {
  154. const char *nsm_url;
  155. lo_server _server;
  156. lo_server_thread _st;
  157. lo_address nsm_addr;
  158. int nsm_is_active;
  159. char *nsm_client_id;
  160. char *_session_manager_name;
  161. char *_session_manager_features;
  162. nsm_open_callback *open;
  163. void *open_userdata;
  164. nsm_save_callback *save;
  165. void *save_userdata;
  166. nsm_show_gui_callback *show;
  167. void *show_userdata;
  168. nsm_hide_gui_callback *hide;
  169. void *hide_userdata;
  170. nsm_active_callback *active;
  171. void *active_userdata;
  172. nsm_session_is_loaded_callback *session_is_loaded;
  173. void *session_is_loaded_userdata;
  174. nsm_broadcast_callback *broadcast;
  175. void *broadcast_userdata;
  176. };
  177. enum
  178. {
  179. ERR_OK = 0,
  180. ERR_GENERAL = -1,
  181. ERR_INCOMPATIBLE_API = -2,
  182. ERR_BLACKLISTED = -3,
  183. ERR_LAUNCH_FAILED = -4,
  184. ERR_NO_SUCH_FILE = -5,
  185. ERR_NO_SESSION_OPEN = -6,
  186. ERR_UNSAVED_CHANGES = -7,
  187. ERR_NOT_NOW = -8
  188. };
  189. NSM_EXPORT
  190. int
  191. nsm_is_active ( nsm_client_t *nsm )
  192. {
  193. return _NSM()->nsm_is_active;
  194. }
  195. NSM_EXPORT
  196. const char *
  197. nsm_get_session_manager_name ( nsm_client_t *nsm )
  198. {
  199. return _NSM()->_session_manager_name;
  200. }
  201. NSM_EXPORT
  202. const char *
  203. nsm_get_session_manager_features ( nsm_client_t *nsm )
  204. {
  205. return _NSM()->_session_manager_features;
  206. }
  207. NSM_EXPORT
  208. nsm_client_t *
  209. nsm_new ( void )
  210. {
  211. struct _nsm_client_t *nsm = (struct _nsm_client_t*)malloc( sizeof( struct _nsm_client_t ) );
  212. nsm->nsm_url = 0;
  213. nsm->nsm_is_active = 0;
  214. nsm->nsm_client_id = 0;
  215. nsm->_server = 0;
  216. nsm->_st = 0;
  217. nsm->nsm_addr = 0;
  218. nsm->_session_manager_name = 0;
  219. nsm->_session_manager_features = 0;
  220. nsm->open = 0;
  221. nsm->save = 0;
  222. nsm->show = 0;
  223. nsm->hide = 0;
  224. nsm->active = 0;
  225. nsm->session_is_loaded = 0;
  226. nsm->broadcast = 0;
  227. return (nsm_client_t *)nsm;
  228. }
  229. /*******************************************/
  230. /* CLIENT TO SERVER INFORMATIONAL MESSAGES */
  231. /*******************************************/
  232. NSM_EXPORT
  233. void
  234. nsm_send_is_dirty ( nsm_client_t *nsm )
  235. {
  236. if ( _NSM()->nsm_is_active )
  237. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "" );
  238. }
  239. NSM_EXPORT
  240. void
  241. nsm_send_is_clean ( nsm_client_t *nsm )
  242. {
  243. if ( _NSM()->nsm_is_active )
  244. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "" );
  245. }
  246. NSM_EXPORT
  247. void
  248. nsm_send_is_shown ( nsm_client_t *nsm )
  249. {
  250. if ( _NSM()->nsm_is_active )
  251. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "" );
  252. }
  253. NSM_EXPORT
  254. void
  255. nsm_send_is_hidden ( nsm_client_t *nsm )
  256. {
  257. if ( _NSM()->nsm_is_active )
  258. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" );
  259. }
  260. NSM_EXPORT
  261. void
  262. nsm_send_progress ( nsm_client_t *nsm, float p )
  263. {
  264. if ( _NSM()->nsm_is_active )
  265. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p );
  266. }
  267. NSM_EXPORT
  268. void
  269. nsm_send_message ( nsm_client_t *nsm, int priority, const char *msg )
  270. {
  271. if ( _NSM()->nsm_is_active )
  272. lo_send_from( _NSM()->nsm_addr, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg );
  273. }
  274. NSM_EXPORT void
  275. nsm_send_announce ( nsm_client_t *nsm, const char *app_name, const char *capabilities, const char *process_name )
  276. {
  277. lo_address to = lo_address_new_from_url( _NSM()->nsm_url );
  278. if ( ! to )
  279. {
  280. fprintf( stderr, "NSM: Bad address!" );
  281. return;
  282. }
  283. int pid = (int)getpid();
  284. lo_send_from( to, _NSM()->_server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
  285. app_name,
  286. capabilities,
  287. process_name,
  288. NSM_API_VERSION_MAJOR,
  289. NSM_API_VERSION_MINOR,
  290. pid );
  291. lo_address_free( to );
  292. }
  293. NSM_EXPORT void
  294. nsm_send_broadcast ( nsm_client_t *nsm, lo_message msg )
  295. {
  296. if ( _NSM()->nsm_is_active )
  297. lo_send_message_from( _NSM()->nsm_addr, _NSM()->_server, "/nsm/server/broadcast", msg );
  298. }
  299. NSM_EXPORT
  300. void
  301. nsm_check_wait ( nsm_client_t *nsm, int timeout )
  302. {
  303. if ( lo_server_wait( _NSM()->_server, timeout ) )
  304. while ( lo_server_recv_noblock( _NSM()->_server, 0 ) ) {}
  305. }
  306. NSM_EXPORT
  307. void
  308. nsm_check_nowait (nsm_client_t *nsm )
  309. {
  310. nsm_check_wait( nsm, 0 );
  311. }
  312. NSM_EXPORT
  313. void
  314. nsm_thread_start ( nsm_client_t *nsm )
  315. {
  316. lo_server_thread_start( _NSM()->_st );
  317. }
  318. NSM_EXPORT
  319. void
  320. nsm_thread_stop ( nsm_client_t *nsm )
  321. {
  322. lo_server_thread_stop( _NSM()->_st );
  323. }
  324. NSM_EXPORT void
  325. nsm_free ( nsm_client_t *nsm )
  326. {
  327. if ( _NSM()->_st )
  328. nsm_thread_stop( nsm );
  329. if ( _NSM()->_st )
  330. lo_server_thread_free( _NSM()->_st );
  331. else
  332. lo_server_free( _NSM()->_server );
  333. free(_NSM()->nsm_client_id);
  334. free(_NSM()->_session_manager_name);
  335. free(_NSM()->_session_manager_features);
  336. free( _NSM() );
  337. }
  338. /*****************/
  339. /* SET CALLBACKS */
  340. /*****************/
  341. NSM_EXPORT
  342. void
  343. nsm_set_open_callback( nsm_client_t *nsm, nsm_open_callback *open_callback, void *userdata )
  344. {
  345. _NSM()->open = open_callback;
  346. _NSM()->open_userdata = userdata;
  347. }
  348. NSM_EXPORT
  349. void
  350. nsm_set_save_callback( nsm_client_t *nsm, nsm_save_callback *save_callback, void *userdata )
  351. {
  352. _NSM()->save = save_callback;
  353. _NSM()->save_userdata = userdata;
  354. }
  355. NSM_EXPORT
  356. void
  357. nsm_set_show_callback( nsm_client_t *nsm, nsm_show_gui_callback *show_callback, void *userdata )
  358. {
  359. _NSM()->show = show_callback;
  360. _NSM()->show_userdata = userdata;
  361. }
  362. NSM_EXPORT
  363. void
  364. nsm_set_hide_callback( nsm_client_t *nsm, nsm_hide_gui_callback *hide_callback, void *userdata )
  365. {
  366. _NSM()->hide = hide_callback;
  367. _NSM()->hide_userdata = userdata;
  368. }
  369. NSM_EXPORT
  370. void
  371. nsm_set_active_callback( nsm_client_t *nsm, nsm_active_callback *active_callback, void *userdata )
  372. {
  373. _NSM()->active = active_callback;
  374. _NSM()->active_userdata = userdata;
  375. }
  376. NSM_EXPORT
  377. void
  378. nsm_set_session_is_loaded_callback( nsm_client_t *nsm, nsm_session_is_loaded_callback *session_is_loaded_callback, void *userdata )
  379. {
  380. _NSM()->session_is_loaded = session_is_loaded_callback;
  381. _NSM()->session_is_loaded_userdata = userdata;
  382. }
  383. NSM_EXPORT
  384. void
  385. nsm_set_broadcast_callback( nsm_client_t *nsm, nsm_broadcast_callback *broadcast_callback, void *userdata )
  386. {
  387. _NSM()->broadcast = broadcast_callback;
  388. _NSM()->broadcast_userdata = userdata;
  389. }
  390. /****************/
  391. /* OSC HANDLERS */
  392. /****************/
  393. #undef OSC_REPLY
  394. #undef OSC_REPLY_ERR
  395. #define OSC_REPLY( value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value )
  396. #define OSC_REPLY_ERR( errcode, value ) lo_send_from( ((struct _nsm_client_t*)user_data)->nsm_addr, ((struct _nsm_client_t*)user_data)->_server, LO_TT_IMMEDIATE, "/error", "sis", path, errcode, value )
  397. NSM_EXPORT int _nsm_osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  398. {
  399. (void) types;
  400. (void) argc;
  401. (void) msg;
  402. char *out_msg = NULL;
  403. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  404. nsm->nsm_client_id = strdup( &argv[2]->s );
  405. if ( ! nsm->open )
  406. return 0;
  407. int r = nsm->open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg, nsm->open_userdata );
  408. if ( r )
  409. OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
  410. else
  411. OSC_REPLY( "OK" );
  412. if ( out_msg )
  413. free( out_msg );
  414. return 0;
  415. }
  416. NSM_EXPORT int _nsm_osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  417. {
  418. (void) types;
  419. (void) argv;
  420. (void) argc;
  421. (void) msg;
  422. char *out_msg = NULL;
  423. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  424. if ( ! nsm->save )
  425. return 0;
  426. int r = nsm->save(&out_msg, nsm->save_userdata );
  427. if ( r )
  428. OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
  429. else
  430. OSC_REPLY( "OK" );
  431. if ( out_msg )
  432. free( out_msg );
  433. return 0;
  434. }
  435. NSM_EXPORT int _nsm_osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  436. {
  437. (void) path;
  438. (void) types;
  439. (void) argc;
  440. if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
  441. return -1;
  442. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  443. fprintf( stderr, "NSM: Successfully registered. NSM says: %s", &argv[1]->s );
  444. nsm->nsm_is_active = 1;
  445. nsm->_session_manager_name = strdup( &argv[2]->s );
  446. nsm->_session_manager_features = strdup( &argv[3]->s );
  447. nsm->nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  448. if ( nsm->active )
  449. nsm->active( nsm->nsm_is_active, nsm->active_userdata );
  450. return 0;
  451. }
  452. NSM_EXPORT int _nsm_osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  453. {
  454. (void) path;
  455. (void) types;
  456. (void) argc;
  457. (void) msg;
  458. if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
  459. return -1;
  460. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  461. fprintf( stderr, "NSM: Failed to register with NSM server: %s", &argv[2]->s );
  462. nsm->nsm_is_active = 0;
  463. if ( nsm->active )
  464. nsm->active( nsm->nsm_is_active, nsm->active_userdata );
  465. return 0;
  466. }
  467. NSM_EXPORT int _nsm_osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  468. {
  469. (void) path;
  470. (void) types;
  471. (void) argv;
  472. (void) argc;
  473. (void) msg;
  474. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  475. if ( ! nsm->session_is_loaded )
  476. return 0;
  477. nsm->session_is_loaded( nsm->session_is_loaded_userdata );
  478. return 0;
  479. }
  480. NSM_EXPORT int _nsm_osc_show ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  481. {
  482. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  483. if ( ! nsm->show )
  484. return 0;
  485. nsm->show( nsm->show_userdata );
  486. return 0;
  487. }
  488. NSM_EXPORT int _nsm_osc_hide ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  489. {
  490. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  491. if ( ! nsm->hide )
  492. return 0;
  493. nsm->hide( nsm->hide_userdata );
  494. return 0;
  495. }
  496. NSM_EXPORT int _nsm_osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  497. {
  498. (void) types;
  499. (void) argv;
  500. (void) argc;
  501. struct _nsm_client_t *nsm = (struct _nsm_client_t*)user_data;
  502. if ( ! nsm->broadcast )
  503. return 0;
  504. return nsm->broadcast( path, msg, nsm->broadcast_userdata );
  505. }
  506. NSM_EXPORT
  507. int
  508. nsm_init ( nsm_client_t *nsm, const char *nsm_url )
  509. {
  510. _NSM()->nsm_url = nsm_url;
  511. lo_address addr = lo_address_new_from_url( nsm_url );
  512. int proto = lo_address_get_protocol( addr );
  513. lo_address_free( addr );
  514. _NSM()->_server = lo_server_new_with_proto( NULL, proto, NULL );
  515. if ( ! _NSM()->_server )
  516. return -1;
  517. lo_server_add_method( _NSM()->_server, "/error", "sis", _nsm_osc_error, _NSM() );
  518. lo_server_add_method( _NSM()->_server, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() );
  519. lo_server_add_method( _NSM()->_server, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() );
  520. lo_server_add_method( _NSM()->_server, "/nsm/client/save", "", _nsm_osc_save, _NSM() );
  521. lo_server_add_method( _NSM()->_server, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() );
  522. lo_server_add_method( _NSM()->_server, "/nsm/client/show_optional_gui", "", _nsm_osc_show, _NSM() );
  523. lo_server_add_method( _NSM()->_server, "/nsm/client/hide_optional_gui", "", _nsm_osc_hide, _NSM() );
  524. lo_server_add_method( _NSM()->_server, NULL, NULL, _nsm_osc_broadcast, _NSM() );
  525. return 0;
  526. }
  527. NSM_EXPORT
  528. int
  529. nsm_init_thread ( nsm_client_t *nsm, const char *nsm_url )
  530. {
  531. _NSM()->nsm_url = nsm_url;
  532. lo_address addr = lo_address_new_from_url( nsm_url );
  533. int proto = lo_address_get_protocol( addr );
  534. lo_address_free( addr );
  535. _NSM()->_st = lo_server_thread_new_with_proto( NULL, proto, NULL );
  536. _NSM()->_server = lo_server_thread_get_server( _NSM()->_st );
  537. if ( ! _NSM()->_server )
  538. return -1;
  539. lo_server_thread_add_method( _NSM()->_st, "/error", "sis", _nsm_osc_error, _NSM() );
  540. lo_server_thread_add_method( _NSM()->_st, "/reply", "ssss", _nsm_osc_announce_reply, _NSM() );
  541. lo_server_thread_add_method( _NSM()->_st, "/nsm/client/open", "sss", _nsm_osc_open, _NSM() );
  542. lo_server_thread_add_method( _NSM()->_st, "/nsm/client/save", "", _nsm_osc_save, _NSM() );
  543. lo_server_thread_add_method( _NSM()->_st, "/nsm/client/session_is_loaded", "", _nsm_osc_session_is_loaded, _NSM() );
  544. lo_server_thread_add_method( _NSM()->_st, "/nsm/client/show_optional_gui", "", _nsm_osc_show, _NSM() );
  545. lo_server_thread_add_method( _NSM()->_st, "/nsm/client/hide_optional_gui", "", _nsm_osc_hide, _NSM() );
  546. lo_server_thread_add_method( _NSM()->_st, NULL, NULL, _nsm_osc_broadcast, _NSM() );
  547. return 0;
  548. }
  549. #endif /* NSM_H */