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.

769 lines
16KB

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