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.

861 lines
19KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */
  3. /* Copyright (C) 2020- Nils Hilbricht */
  4. /* */
  5. /* This file is part of New-Session-Manager */
  6. /* */
  7. /* New-Session-Manager is free software: you can redistribute it and/or modify */
  8. /* it under the terms of the GNU General Public License as published by */
  9. /* the Free Software Foundation, either version 3 of the License, or */
  10. /* (at your option) any later version. */
  11. /* */
  12. /* New-Session-Manager is distributed in the hope that it will be useful, */
  13. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  14. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  15. /* GNU General Public License for more details. */
  16. /* */
  17. /* You should have received a copy of the GNU General Public License */
  18. /* along with New-Session-Manager. If not, see <https://www.gnu.org/licenses/>.*/
  19. /*******************************************************************************/
  20. /* jackpatch.c
  21. This program is just like ASSPatch, except that it works with Jack ports (audio and MIDI).
  22. */
  23. #pragma GCC diagnostic ignored "-Wunused-parameter"
  24. #pragma GCC diagnostic ignored "-Wunused-result"
  25. /* needed for asprintf */
  26. #define _GNU_SOURCE
  27. #include <string.h>
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #include <string.h>
  34. #include <signal.h>
  35. #include <getopt.h>
  36. #include <sys/types.h>
  37. #include <sys/time.h>
  38. #include <errno.h>
  39. #include <stdlib.h>
  40. #include <jack/jack.h>
  41. #include <getopt.h>
  42. #include <lo/lo.h>
  43. #include <jack/ringbuffer.h>
  44. int client_active = 0;
  45. jack_client_t *client;
  46. lo_server losrv;
  47. lo_address nsm_addr;
  48. int nsm_is_active;
  49. char *project_file;
  50. #undef VERSION
  51. #define APP_TITLE "JACKPatch"
  52. #define VERSION "0.2"
  53. struct patch_record {
  54. struct {
  55. char *client;
  56. char *port;
  57. } src , dst;
  58. int active; /* true if patch has already been activate (by us) */
  59. struct patch_record *next;
  60. };
  61. struct port_record {
  62. char *port;
  63. struct port_record *next;
  64. };
  65. struct port_notification_record {
  66. int len;
  67. int reg; /* true if registered, false if unregistered */
  68. char port[];
  69. };
  70. static struct port_record *known_ports = NULL;
  71. static struct patch_record *patch_list = NULL;
  72. static jack_ringbuffer_t *port_ringbuffer = NULL;
  73. /**
  74. * Pretty-print patch relationship of /pr/
  75. */
  76. void
  77. print_patch ( struct patch_record *pr, int mode )
  78. {
  79. printf( "[jackpatch] %s from '%s:%s' to '%s:%s'\n", mode ? ">>" : "::",
  80. pr->src.client, pr->src.port, pr->dst.client, pr->dst.port );
  81. }
  82. void
  83. enqueue ( struct patch_record *p )
  84. {
  85. p->next = patch_list;
  86. patch_list = p;
  87. }
  88. void
  89. dequeue ( struct patch_record *pr )
  90. {
  91. if ( !pr )
  92. return;
  93. free( pr->src.port );
  94. free( pr->dst.port );
  95. free( pr->src.client );
  96. free( pr->dst.client );
  97. free( pr );
  98. }
  99. void
  100. enqueue_port ( struct port_record **q, const char *port )
  101. {
  102. struct port_record *p = malloc( sizeof( struct port_record ));
  103. p->port = strdup( port );
  104. p->next = *q;
  105. *q = p;
  106. }
  107. void enqueue_known_port ( const char *port )
  108. {
  109. enqueue_port( &known_ports, port );
  110. }
  111. const char * find_known_port ( const char *port )
  112. {
  113. struct port_record *pr;
  114. for ( pr = known_ports; pr; pr = pr->next )
  115. if ( !strcmp( port, pr->port ) )
  116. return pr->port;
  117. return NULL;
  118. }
  119. int
  120. process_patch ( const char *patch )
  121. {
  122. struct patch_record *pr;
  123. char *leftc, *rightc, *leftp, *rightp;
  124. char dir[3];
  125. int retval;
  126. retval = sscanf( patch, " %m[^:]:%m[^|] |%1[<>|] %m[^:]:%m[^\n]",
  127. &leftc, &leftp, dir, &rightc, &rightp );
  128. if ( retval == EOF )
  129. return -1;
  130. if ( retval != 5 )
  131. return 0;
  132. /* trim space */
  133. int j;
  134. for ( j = strlen( leftp ) - 1; j > 0; j-- )
  135. {
  136. if ( leftp[j] == ' ' || leftp[j] == '\t' )
  137. leftp[j] = 0;
  138. else
  139. break;
  140. }
  141. dir[2] = 0;
  142. pr = malloc( sizeof( struct patch_record ) );
  143. switch ( *dir )
  144. {
  145. case '<':
  146. pr->src.client = rightc;
  147. pr->src.port = rightp;
  148. pr->dst.client = leftc;
  149. pr->dst.port = leftp;
  150. enqueue( pr );
  151. break;
  152. case '>':
  153. pr->src.client = leftc;
  154. pr->src.port = leftp;
  155. pr->dst.client = rightc;
  156. pr->dst.port = rightp;
  157. enqueue( pr );
  158. break;
  159. case '|':
  160. pr->src.client = rightc;
  161. pr->src.port = rightp;
  162. pr->dst.client = leftc;
  163. pr->dst.port = leftp;
  164. enqueue( pr );
  165. pr = malloc( sizeof( struct patch_record ) );
  166. pr->src.client = strdup( leftc );
  167. pr->src.port = strdup( leftp );
  168. pr->dst.client = strdup( rightc );
  169. pr->dst.port = strdup( rightp );
  170. enqueue( pr );
  171. break;
  172. default:
  173. // fprintf( stderr, "[jackpatch] Invalid token '|%s' at line %i of %s!", dir, i, file );
  174. free( pr );
  175. return 0;
  176. }
  177. pr->active = 0;
  178. print_patch( pr, 1 );
  179. return 1;
  180. }
  181. void
  182. clear_all_patches ( )
  183. {
  184. struct patch_record *pr;
  185. while ( patch_list )
  186. {
  187. pr = patch_list;
  188. patch_list = pr->next;
  189. dequeue( pr );
  190. }
  191. }
  192. /**
  193. * Crudely parse configuration file named by /file/ using fscanf
  194. */
  195. int
  196. read_config ( const char *file )
  197. {
  198. FILE *fp;
  199. int i = 0;
  200. if ( NULL == ( fp = fopen( file, "r" ) ) )
  201. return 0;
  202. clear_all_patches();
  203. while ( !feof( fp ) && !ferror( fp ) )
  204. {
  205. int retval;
  206. unsigned int k;
  207. char buf[BUFSIZ];
  208. i++;
  209. for ( k = 0; k < sizeof( buf ) - 1; k++ )
  210. {
  211. retval = fread( buf + k, 1, 1, fp );
  212. if ( retval != 1 )
  213. break;
  214. if ( buf[k] == '\n' )
  215. {
  216. if ( k == 0 )
  217. continue;
  218. else
  219. break;
  220. }
  221. }
  222. if ( retval == 0 )
  223. break;
  224. retval = process_patch( buf );
  225. if ( retval < 0 )
  226. break;
  227. if ( retval == 0 )
  228. {
  229. printf( "[jackpatch] bad line %i.\n", i );
  230. continue;
  231. }
  232. }
  233. fclose( fp );
  234. return 1;
  235. }
  236. /* returns 0 if connection failed, true if succeeded. Already connected
  237. * is not considered failure */
  238. void
  239. connect_path ( struct patch_record *pr )
  240. {
  241. int r = 0;
  242. char srcport[512];
  243. char dstport[512];
  244. snprintf( srcport, 512, "%s:%s", pr->src.client, pr->src.port );
  245. snprintf( dstport, 512, "%s:%s", pr->dst.client, pr->dst.port );
  246. if ( pr->active )
  247. {
  248. /* patch is already active, don't bother JACK with it... */
  249. return;
  250. }
  251. if ( ! ( find_known_port( srcport ) && find_known_port( dstport ) ) )
  252. {
  253. /* one of the ports doesn't exist yet... don't attempt
  254. * connection, jack will just complain. */
  255. printf( "[jackpatch] Not attempting connection because one of the ports is missing.\n" );
  256. return;
  257. }
  258. printf( "[jackpatch] Connecting %s |> %s\n", srcport, dstport );
  259. r = jack_connect( client, srcport, dstport );
  260. print_patch( pr, r );
  261. if ( r == 0 || r == EEXIST )
  262. {
  263. pr->active = 1;
  264. return;
  265. }
  266. else
  267. {
  268. pr->active = 0;
  269. printf( "[jackpatch] Error is %i\n", r );
  270. return;
  271. }
  272. }
  273. void
  274. do_for_matching_patches ( const char *portname, void (*func)( struct patch_record * ) )
  275. {
  276. struct patch_record *pr;
  277. char client[512];
  278. char port[512];
  279. sscanf( portname, "%[^:]:%[^\n]", client, port );
  280. for ( pr = patch_list; pr; pr = pr->next )
  281. {
  282. if ( ( !strcmp( client, pr->src.client ) && !strcmp( port, pr->src.port ) ) ||
  283. ( !strcmp( client, pr->dst.client ) && !strcmp( port, pr->dst.port ) ) )
  284. {
  285. func( pr );
  286. }
  287. }
  288. }
  289. void
  290. inactivate_path ( struct patch_record *pr )
  291. {
  292. pr->active = 0;
  293. }
  294. void
  295. inactivate_patch ( const char *portname )
  296. {
  297. do_for_matching_patches( portname, inactivate_path );
  298. }
  299. void
  300. activate_patch ( const char *portname )
  301. {
  302. do_for_matching_patches( portname, connect_path );
  303. }
  304. void remove_known_port ( const char *port )
  305. {
  306. /* remove it from the list of known ports */
  307. {
  308. struct port_record *pr;
  309. struct port_record *lp = NULL;
  310. for ( pr = known_ports; pr; lp = pr, pr = pr->next )
  311. if ( !strcmp( port, pr->port ) )
  312. {
  313. if ( lp )
  314. lp->next = pr->next;
  315. else
  316. known_ports = pr->next;
  317. free( pr->port );
  318. free( pr );
  319. break;
  320. }
  321. }
  322. /* now mark all patches including this port as inactive */
  323. inactivate_patch ( port );
  324. }
  325. /** called for every new port */
  326. void
  327. handle_new_port ( const char *portname )
  328. {
  329. enqueue_known_port( portname );
  330. printf( "[jackpatch] New endpoint '%s' registered.\n", portname );
  331. /* this is a new port */
  332. activate_patch( portname );
  333. }
  334. void
  335. register_prexisting_ports ( void )
  336. {
  337. const char **port;
  338. const char **ports = jack_get_ports( client, NULL, NULL, 0 );
  339. if ( ! ports )
  340. return;
  341. for ( port = ports; *port; port++ )
  342. {
  343. handle_new_port( *port );
  344. }
  345. free( ports );
  346. }
  347. static int stringsort ( const void *a, const void *b )
  348. {
  349. return strcmp(* (char * const *) a, * (char * const *) b);
  350. }
  351. void
  352. snapshot ( const char *file )
  353. {
  354. FILE *fp;
  355. const char **port;
  356. const char **ports = jack_get_ports( client, NULL, NULL, JackPortIsOutput );
  357. if ( ! ports )
  358. return;
  359. if ( NULL == ( fp = fopen( file, "w" ) ) )
  360. {
  361. fprintf( stderr, "[jackpatch] Error opening snapshot file for writing" );
  362. return;
  363. }
  364. clear_all_patches();
  365. const int table_increment = 16;
  366. int table_index = 0;
  367. size_t table_size = table_increment;
  368. char **table = (char**)malloc( sizeof( char * ) * table_increment );
  369. for ( port = ports; *port; port++ )
  370. {
  371. jack_port_t *p;
  372. p = jack_port_by_name( client, *port );
  373. const char **connections;
  374. const char **connection;
  375. connections = jack_port_get_all_connections( client, p );
  376. if ( ! connections )
  377. continue;
  378. for ( connection = connections; *connection; connection++ )
  379. {
  380. char *s;
  381. asprintf( &s, "%-40s |> %s\n", *port, *connection );
  382. if ( table_index >= table_size )
  383. {
  384. table_size += table_increment;
  385. table = (char**)realloc( table, table_size * sizeof( char *) );
  386. }
  387. table[table_index++] = s;
  388. process_patch( s );
  389. printf( "[jackpatch] ++ %s |> %s\n", *port, *connection );
  390. }
  391. free( connections );
  392. }
  393. free( ports );
  394. qsort( table, table_index, sizeof(char*), stringsort );
  395. int i;
  396. for ( i = 0; i < table_index; i++ )
  397. {
  398. fprintf( fp, "%s", table[i] );
  399. free(table[i]);
  400. }
  401. free(table);
  402. fclose( fp );
  403. }
  404. static int die_now = 0;
  405. void
  406. signal_handler ( int x )
  407. {
  408. die_now = 1;
  409. }
  410. void
  411. die ( void )
  412. {
  413. if ( client_active )
  414. jack_deactivate( client );
  415. printf( "[jackpatch] Closing jack client\n" );
  416. jack_client_close( client );
  417. client = NULL;
  418. exit( 0 );
  419. }
  420. /** set_traps
  421. *
  422. * Handle signals
  423. */
  424. void
  425. set_traps ( void )
  426. {
  427. signal( SIGHUP, signal_handler );
  428. signal( SIGINT, signal_handler );
  429. // signal( SIGQUIT, signal_handler );
  430. // signal( SIGSEGV, signal_handler );
  431. // signal( SIGPIPE, signal_handler );
  432. signal( SIGTERM, signal_handler );
  433. }
  434. /****************/
  435. /* OSC HANDLERS */
  436. /****************/
  437. int
  438. osc_announce_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  439. {
  440. if ( strcmp( types, "sis" ) )
  441. return -1;
  442. if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
  443. return -1;
  444. printf( "[jackpatch] Failed to register with NSM: %s\n", &argv[2]->s );
  445. nsm_is_active = 0;
  446. return 0;
  447. }
  448. int
  449. osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  450. {
  451. if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
  452. return -1;
  453. printf( "[jackpatch] Successfully registered. NSM says: %s", &argv[1]->s );
  454. nsm_is_active = 1;
  455. nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ) );
  456. return 0;
  457. }
  458. int
  459. osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  460. {
  461. snapshot( project_file );
  462. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
  463. return 0;
  464. }
  465. void
  466. maybe_activate_jack_client ( void )
  467. {
  468. if ( ! client_active )
  469. {
  470. jack_activate( client );
  471. client_active = 1;
  472. }
  473. }
  474. int
  475. osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  476. {
  477. const char *new_path = &argv[0]->s;
  478. // const char *display_name = &argv[1]->s;
  479. char *new_filename;
  480. asprintf( &new_filename, "%s.jackpatch", new_path );
  481. struct stat st;
  482. if ( 0 == stat( new_filename, &st ) )
  483. {
  484. printf( "[jackpatch] Reading patch definitions from: %s\n", new_filename );
  485. if ( read_config( new_filename ) )
  486. {
  487. /* wipe_ports(); */
  488. /* check_for_new_ports(); */
  489. maybe_activate_jack_client();
  490. register_prexisting_ports();
  491. }
  492. else
  493. {
  494. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Could not open file" );
  495. return 0;
  496. }
  497. }
  498. else
  499. {
  500. maybe_activate_jack_client();
  501. clear_all_patches();
  502. }
  503. if ( project_file )
  504. free( project_file );
  505. project_file = new_filename;
  506. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
  507. return 0;
  508. }
  509. void
  510. announce ( const char *nsm_url, const char *client_name, const char *process_name )
  511. {
  512. printf( "[jackpatch] Announcing to NSM\n" );
  513. lo_address to = lo_address_new_from_url( nsm_url );
  514. int pid = (int)getpid();
  515. lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
  516. client_name,
  517. ":switch:",
  518. process_name,
  519. 0, /* api_major_version */
  520. 8, /* api_minor_version */
  521. pid );
  522. lo_address_free( to );
  523. }
  524. void
  525. init_osc ( const char *osc_port )
  526. {
  527. losrv = lo_server_new( osc_port, NULL );
  528. //error_handler );
  529. char *url = lo_server_get_url(losrv);
  530. printf("[jackpatch] OSC: %s\n",url);
  531. free(url);
  532. lo_server_add_method( losrv, "/nsm/client/save", "", osc_save, NULL );
  533. lo_server_add_method( losrv, "/nsm/client/open", "sss", osc_open, NULL );
  534. lo_server_add_method( losrv, "/error", "sis", osc_announce_error, NULL );
  535. lo_server_add_method( losrv, "/reply", "ssss", osc_announce_reply, NULL );
  536. }
  537. struct port_notification_record *
  538. dequeue_new_port ( void )
  539. {
  540. int size = 0;
  541. if ( sizeof( int ) == jack_ringbuffer_peek( port_ringbuffer, (char*)&size, sizeof( int ) ) )
  542. {
  543. if ( jack_ringbuffer_read_space( port_ringbuffer ) >= size )
  544. {
  545. struct port_notification_record *pr = malloc( size );
  546. jack_ringbuffer_read( port_ringbuffer, (char*)pr, size );
  547. return pr;
  548. }
  549. }
  550. return NULL;
  551. }
  552. void
  553. check_for_new_ports ( void )
  554. {
  555. struct port_notification_record *p = NULL;
  556. while ( ( p = dequeue_new_port() ) )
  557. {
  558. if ( p->reg )
  559. handle_new_port( p->port );
  560. else
  561. remove_known_port( p->port );
  562. free( p );
  563. }
  564. }
  565. void
  566. port_registration_callback( jack_port_id_t id, int reg, void *arg )
  567. {
  568. jack_port_t *p = jack_port_by_id( client, id );
  569. const char *port = jack_port_name( p );
  570. int size = strlen(port) + 1 + sizeof( struct port_notification_record );
  571. struct port_notification_record *pr = malloc( size );
  572. pr->len = size;
  573. pr->reg = reg;
  574. strcpy( pr->port, port );
  575. if ( size != jack_ringbuffer_write( port_ringbuffer, (const char *)pr, size ) )
  576. {
  577. fprintf( stderr, "[jackpatch] ERROR: port notification buffer overrun" );
  578. }
  579. // enqueue_new_port( port, reg );
  580. }
  581. /* */
  582. int
  583. main ( int argc, char **argv )
  584. {
  585. //Command line parameters
  586. static struct option long_options[] =
  587. {
  588. { "help", no_argument, 0, 'h' },
  589. { 0, 0, 0, 0 }
  590. };
  591. int option_index = 0;
  592. int c = 0;
  593. while ( ( c = getopt_long_only( argc, argv, "", long_options, &option_index ) ) != -1 )
  594. {
  595. switch ( c )
  596. {
  597. case 'h':
  598. {
  599. const char *usage =
  600. "jackpatch - Remember the JACK Audio Connection Kit Graph in NSM\n\n"
  601. "It is a module for the 'New Session Manager' and only communicates\n"
  602. "over OSC in an NSM-Session and has no standalone functionality.\n"
  603. "\n"
  604. "Usage:\n"
  605. " jackpatch --help\n"
  606. "\n"
  607. "Options:\n"
  608. " --help Show this screen\n"
  609. "";
  610. puts ( usage );
  611. exit(0);
  612. break;
  613. }
  614. }
  615. }
  616. jack_status_t status;
  617. client = jack_client_open( APP_TITLE, JackNullOption, &status );
  618. jack_set_port_registration_callback( client, port_registration_callback, NULL );
  619. if ( ! client )
  620. {
  621. fprintf( stderr, "[jackpatch] Could not register JACK client\n" );
  622. exit(1);
  623. }
  624. port_ringbuffer = jack_ringbuffer_create( 1024 * 8 );
  625. set_traps();
  626. if ( argc > 1 )
  627. {
  628. maybe_activate_jack_client();
  629. if ( ! strcmp( argv[1], "--save" ) )
  630. {
  631. if ( argc > 2 )
  632. {
  633. printf( "[jackpatch] Saving current graph to: %s\n", argv[2] );
  634. snapshot( argv[2] );
  635. die();
  636. }
  637. }
  638. else
  639. {
  640. read_config( argv[1] );
  641. printf( "[jackpatch] Monitoring...\n" );
  642. for ( ;; )
  643. {
  644. usleep( 50000 );
  645. check_for_new_ports();
  646. }
  647. }
  648. }
  649. init_osc( NULL );
  650. const char *nsm_url = getenv( "NSM_URL" );
  651. if ( nsm_url )
  652. {
  653. announce( nsm_url, APP_TITLE, argv[0] );
  654. }
  655. else
  656. {
  657. fprintf( stderr, "[jackpatch] Could not register as NSM client.\n" );
  658. exit(1);
  659. }
  660. for ( ;; )
  661. {
  662. lo_server_recv_noblock( losrv, 200 );
  663. if ( client_active )
  664. check_for_new_ports();
  665. if ( die_now )
  666. die();
  667. }
  668. }