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.

713 lines
20KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2009 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. #include "const.h"
  19. #include <string.h>
  20. #include <FL/fl_ask.H>
  21. #include <FL/Fl_Box.H>
  22. #include <FL/Fl_Pack.H>
  23. #include <FL/Fl_Scalepack.H>
  24. #include "dsp.h"
  25. #include "Chain.H"
  26. #include "JACK_Module.H"
  27. #include <FL/fl_draw.H>
  28. #include <FL/Fl.H>
  29. #include <FL/Fl_Browser.H>
  30. #include <FL/Fl_PNG_Image.H>
  31. #include <FL/img_io_input_connector_10x10_png.h>
  32. #include <FL/img_io_output_connector_10x10_png.h>
  33. static Fl_PNG_Image *input_connector_image = NULL;
  34. static Fl_PNG_Image *output_connector_image = NULL;
  35. extern char *instance_name;
  36. #include "Mixer.H"
  37. #include "Group.H"
  38. static JACK_Module *receptive_to_drop = NULL;
  39. JACK_Module::JACK_Module ( bool log )
  40. : Module ( 25, 25, name() )
  41. {
  42. _prefix = 0;
  43. _connection_handle_outputs[0][0] = 0;
  44. _connection_handle_outputs[0][1] = 0;
  45. _connection_handle_outputs[1][0] = 0;
  46. _connection_handle_outputs[1][1] = 0;
  47. align( FL_ALIGN_TOP | FL_ALIGN_INSIDE );
  48. if ( log )
  49. {
  50. /* FIXME: how do Controls find out that a connected value has changed? How does this work in ladspa? */
  51. {
  52. Port p( this, Port::INPUT, Port::CONTROL, "Inputs" );
  53. p.hints.type = Port::Hints::INTEGER;
  54. p.hints.minimum = 0;
  55. p.hints.maximum = 16;
  56. p.hints.ranged = true;
  57. p.hints.visible = false;
  58. p.connect_to( new float );
  59. p.control_value_no_callback( 0 );
  60. add_port( p );
  61. }
  62. {
  63. Port p( this, Port::INPUT, Port::CONTROL, "Outputs" );
  64. p.hints.type = Port::Hints::INTEGER;
  65. p.hints.minimum = 0;
  66. p.hints.maximum = 16;
  67. p.hints.ranged = true;
  68. p.hints.visible = false;
  69. p.connect_to( new float );
  70. p.control_value_no_callback( 0 );
  71. add_port( p );
  72. }
  73. color( FL_DARK1 );
  74. log_create();
  75. }
  76. { Fl_Scalepack *o = new Fl_Scalepack( x() + Fl::box_dx(box()),
  77. y() + Fl::box_dy(box()),
  78. w() - Fl::box_dw(box()),
  79. h() - Fl::box_dh(box()) );
  80. o->type( Fl_Pack::VERTICAL );
  81. o->spacing(0);
  82. { Fl_Scalepack *o = new Fl_Scalepack( x() + Fl::box_dx(box()),
  83. y() + Fl::box_dy(box()),
  84. w(),
  85. 24 - Fl::box_dh(box()) );
  86. o->type( Fl_Pack::HORIZONTAL );
  87. o->spacing( 0 );
  88. { Fl_Box *o = input_connection_handle = new Fl_Box( x(), y(), 18, 18 );
  89. o->tooltip( "Drag and drop to make and break JACK connections.");
  90. o->hide();
  91. o->image( input_connector_image ? input_connector_image : input_connector_image = new Fl_PNG_Image( "input_connector", img_io_input_connector_10x10_png, img_io_input_connector_10x10_png_len ) );
  92. }
  93. { Fl_Box *o = new Fl_Box( x() + 10, y(), w() - 20, h() );
  94. Fl_Group::current()->resizable(o);
  95. }
  96. { Fl_Button *o = dec_button = new Fl_Button( 0, 0, 12, h(), "-" );
  97. o->callback( cb_button, this );
  98. o->labelsize(10);
  99. o->labelfont( FL_HELVETICA_BOLD );
  100. o->hide();
  101. }
  102. { Fl_Button *o = inc_button = new Fl_Button( 0,0, 12, h(), "+" );
  103. o->labelsize(10);
  104. o->labelfont( FL_HELVETICA_BOLD );
  105. o->callback( cb_button, this );
  106. o->hide();
  107. }
  108. { Fl_Box *o = output_connection_handle = new Fl_Box( x(), y(), 12, 12 );
  109. o->tooltip( "Drag and drop to make and break JACK connections.");
  110. o->image( output_connector_image ? output_connector_image : output_connector_image = new Fl_PNG_Image( "output_connector", img_io_output_connector_10x10_png, img_io_output_connector_10x10_png_len ) );
  111. o->hide();
  112. }
  113. { Fl_Box *o = output_connection2_handle = new Fl_Box( x(), y(), 12, 12 );
  114. o->tooltip( "Drag and drop to make and break JACK connections.");
  115. o->image( output_connector_image ? output_connector_image : output_connector_image = new Fl_PNG_Image( "output_connector", img_io_output_connector_10x10_png, img_io_output_connector_10x10_png_len ) );
  116. o->hide();
  117. }
  118. o->end();
  119. }
  120. {
  121. Fl_Browser *o = connection_display = new Fl_Browser( 0, 0, w(), h() );
  122. o->has_scrollbar(Fl_Browser_::VERTICAL);
  123. o->textsize( 10 );
  124. o->textcolor( FL_LIGHT3 );
  125. o->textfont( FL_COURIER );
  126. o->box( FL_FLAT_BOX );
  127. o->color( FL_DARK1 );
  128. // o->color( fl_color_add_alpha( fl_rgb_color( 10, 10, 10 ), 100 ));
  129. Fl_Group::current()->resizable(o);
  130. }
  131. o->end();
  132. resizable(o);
  133. }
  134. end();
  135. }
  136. JACK_Module::~JACK_Module ( )
  137. {
  138. log_destroy();
  139. configure_inputs( 0 );
  140. configure_outputs( 0 );
  141. if ( _prefix )
  142. free( _prefix );
  143. }
  144. void
  145. JACK_Module::draw ( void )
  146. {
  147. Module::draw();
  148. if ( this == receptive_to_drop )
  149. {
  150. Fl_Widget *o = input_connection_handle;
  151. fl_draw_box( FL_OVAL_BOX, o->x(), o->y(), o->w(), o->h(), fl_color_add_alpha( FL_GREEN, 127 ) );
  152. }
  153. }
  154. static std::list<std::string>
  155. get_connections_for_ports ( std::vector<Module::Port> ports )
  156. {
  157. std::list<std::string> names;
  158. for ( unsigned int i = 0; i < ports.size(); ++i )
  159. {
  160. const char **connections = ports[i].jack_port()->connections();
  161. if ( ! connections )
  162. return names;
  163. bool is_output = ports[i].jack_port()->direction() == JACK::Port::Output;
  164. for ( const char **c = connections; *c; c++ )
  165. {
  166. char *client_id = 0;
  167. char *strip_name = 0;
  168. // char *client_name = 0;
  169. if ( 2 == sscanf( *c, "Non-Mixer.%a[^:/]/%a[^:]:", &client_id, &strip_name ) )
  170. {
  171. free( client_id );
  172. char *s = NULL;
  173. asprintf( &s, "%s%s", is_output ? "@r" : "", strip_name );
  174. free( strip_name );
  175. strip_name = s;
  176. }
  177. else
  178. if ( 2 == sscanf( *c, "Non-Mixer.%a[^:(] (%a[^:)]):", &client_id, &strip_name ) )
  179. {
  180. free( client_id );
  181. char *s = NULL;
  182. asprintf( &s, "%s%s", is_output ? "@r" : "", strip_name );
  183. free( strip_name );
  184. strip_name = s;
  185. }
  186. else
  187. if ( 2 == sscanf( *c, "Non-Timeline.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
  188. {
  189. free( client_id );
  190. char *s = NULL;
  191. asprintf( &s, "@C2%s%s", is_output ? "@r" : "", strip_name );
  192. free( strip_name );
  193. strip_name = s;
  194. }
  195. else
  196. if ( 2 == sscanf( *c, "Non-DAW.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
  197. {
  198. free( client_id );
  199. char *s = NULL;
  200. asprintf( &s, "@C2%s%s", is_output ? "@r" : "", strip_name );
  201. free( strip_name );
  202. strip_name = s;
  203. }
  204. else if ( 1 == sscanf( *c, "%a[^:]:", &strip_name ) )
  205. {
  206. char *s = NULL;
  207. asprintf( &s, "@C3%s%s", is_output ? "@r" : "", strip_name );
  208. free( strip_name );
  209. strip_name = s;
  210. }
  211. else
  212. {
  213. continue;
  214. }
  215. for ( std::list<std::string>::const_iterator j = names.begin();
  216. j != names.end();
  217. j++ )
  218. {
  219. if ( !strcmp( j->c_str(), strip_name ) )
  220. {
  221. goto skip;
  222. }
  223. }
  224. names.push_back( strip_name );
  225. skip:
  226. free( strip_name );
  227. ;
  228. }
  229. }
  230. names.sort();
  231. return names;
  232. }
  233. void
  234. JACK_Module::update_connection_status ( void )
  235. {
  236. std::list<std::string> output_names = get_connections_for_ports( aux_audio_output );
  237. std::list<std::string> input_names = get_connections_for_ports( aux_audio_input );
  238. connection_display->clear();
  239. int n = 0;
  240. for ( std::list<std::string>::const_iterator j = input_names.begin();
  241. j != input_names.end();
  242. j++ )
  243. {
  244. connection_display->add( j->c_str() );
  245. n++;
  246. }
  247. for ( std::list<std::string>::const_iterator j = output_names.begin();
  248. j != output_names.end();
  249. j++ )
  250. {
  251. connection_display->add( j->c_str() );
  252. n++;
  253. }
  254. /* limit number of lines displayed */
  255. if ( n > 15 )
  256. n = 15;
  257. if ( n > 0 )
  258. size( w(), 26 + ( n * ( connection_display->incr_height() ) ) );
  259. else
  260. size( w(), 24 );
  261. parent()->parent()->redraw();
  262. }
  263. void
  264. JACK_Module::cb_button ( Fl_Widget *w, void *v )
  265. {
  266. ((JACK_Module*)v)->cb_button( w );
  267. }
  268. void
  269. JACK_Module::cb_button( Fl_Widget *w )
  270. {
  271. int n = audio_output.size();
  272. Logger log(this);
  273. if ( w == dec_button )
  274. {
  275. --n;
  276. }
  277. else if ( w == inc_button )
  278. {
  279. ++n;
  280. }
  281. control_input[1].control_value( n );
  282. }
  283. int
  284. JACK_Module::can_support_inputs ( int )
  285. {
  286. return audio_output.size();
  287. }
  288. void
  289. JACK_Module::remove_aux_audio_outputs ( void )
  290. {
  291. for ( unsigned int i = aux_audio_output.size(); i--; )
  292. {
  293. aux_audio_output.back().jack_port()->shutdown();
  294. aux_audio_output.pop_back();
  295. }
  296. }
  297. bool
  298. JACK_Module::configure_inputs ( int n )
  299. {
  300. if ( n > 0 )
  301. {
  302. if ( is_default() )
  303. control_input[0].hints.minimum = 1;
  304. output_connection_handle->show();
  305. }
  306. int on = audio_input.size();
  307. if ( n > on )
  308. {
  309. for ( int i = on; i < n; ++i )
  310. {
  311. if ( add_aux_audio_output(_prefix, i ) )
  312. {
  313. add_port( Port( this, Port::INPUT, Port::AUDIO ) );
  314. }
  315. }
  316. }
  317. else
  318. {
  319. for ( int i = on; i > n; --i )
  320. {
  321. audio_input.back().disconnect();
  322. audio_input.pop_back();
  323. aux_audio_output.back().jack_port()->shutdown();
  324. delete aux_audio_output.back().jack_port();
  325. aux_audio_output.pop_back();
  326. }
  327. }
  328. _connection_handle_outputs[0][0] = 0;
  329. _connection_handle_outputs[0][1] = aux_audio_output.size();
  330. if ( is_default() )
  331. control_input[0].control_value_no_callback( n );
  332. return true;
  333. }
  334. bool
  335. JACK_Module::configure_outputs ( int n )
  336. {
  337. int on = audio_output.size();
  338. if ( n > 0 )
  339. {
  340. input_connection_handle->show();
  341. }
  342. if ( n > on )
  343. {
  344. for ( int i = on; i < n; ++i )
  345. {
  346. if ( add_aux_audio_input(_prefix, i ) )
  347. {
  348. add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
  349. }
  350. }
  351. }
  352. else
  353. {
  354. for ( int i = on; i > n; --i )
  355. {
  356. audio_output.back().disconnect();
  357. audio_output.pop_back();
  358. aux_audio_input.back().jack_port()->shutdown();
  359. delete aux_audio_input.back().jack_port();
  360. aux_audio_input.pop_back();
  361. }
  362. }
  363. if ( is_default() )
  364. control_input[1].control_value_no_callback( n );
  365. if ( n > 0 && is_default() )
  366. {
  367. dec_button->show();
  368. inc_button->show();
  369. }
  370. return true;
  371. }
  372. bool
  373. JACK_Module::initialize ( void )
  374. {
  375. return true;
  376. }
  377. void
  378. JACK_Module::handle_control_changed ( Port *p )
  379. {
  380. // THREAD_ASSERT( UI );
  381. if ( 0 == strcmp( p->name(), "Inputs" ) )
  382. {
  383. DMESSAGE( "Adjusting number of inputs (JACK outputs)" );
  384. configure_inputs( p->control_value() );
  385. if ( chain() )
  386. chain()->configure_ports();
  387. }
  388. else if ( 0 == strcmp( p->name(), "Outputs" ) )
  389. {
  390. DMESSAGE( "Adjusting number of outputs (JACK inputs)" );
  391. if ( ! chain() )
  392. {
  393. configure_outputs( p->control_value() );
  394. }
  395. else if ( chain()->can_configure_outputs( this, p->control_value() ) )
  396. {
  397. configure_outputs( p->control_value() );
  398. chain()->configure_ports();
  399. }
  400. else
  401. {
  402. p->connected_port()->control_value( noutputs() );
  403. }
  404. }
  405. Module::handle_control_changed( p );
  406. }
  407. int
  408. JACK_Module::handle ( int m )
  409. {
  410. static unsigned long _event_state = 0;
  411. unsigned long evstate = Fl::event_state();
  412. switch ( m )
  413. {
  414. case FL_PUSH:
  415. if ( Fl::event_inside( output_connection_handle ) ||
  416. Fl::event_inside( output_connection2_handle ) ||
  417. Fl::event_inside( input_connection_handle ) )
  418. {
  419. _event_state = evstate;
  420. return 1;
  421. }
  422. return Module::handle(m) || 1;
  423. case FL_RELEASE:
  424. Fl::selection_owner(0);
  425. receptive_to_drop = NULL;
  426. if ( Fl::event_inside( output_connection_handle ) ||
  427. Fl::event_inside( output_connection2_handle ) ||
  428. Fl::event_inside( input_connection_handle ) )
  429. {
  430. if ( _event_state & FL_BUTTON3 )
  431. {
  432. /* was a right click */
  433. // TODO: Pop up connection menu.
  434. }
  435. }
  436. return Module::handle(m) || 1;
  437. case FL_DRAG:
  438. {
  439. if ( Fl::event_is_click() )
  440. return 1;
  441. int connection_handle = -1;
  442. if ( Fl::event_inside( output_connection_handle ) )
  443. connection_handle = 0;
  444. if ( Fl::event_inside( output_connection2_handle ) )
  445. connection_handle = 1;
  446. if ( Fl::event_button1() &&
  447. connection_handle >= 0
  448. && ! Fl::selection_owner() )
  449. {
  450. DMESSAGE( "initiation of drag" );
  451. char *s = (char*)malloc(256);
  452. s[0] = 0;
  453. for ( unsigned int i = _connection_handle_outputs[connection_handle][0];
  454. i < aux_audio_output.size() && i < _connection_handle_outputs[connection_handle][1]; ++i )
  455. {
  456. char *s2;
  457. asprintf(&s2, "jack.port://%s\r\n",
  458. aux_audio_output[i].jack_port()->jack_name() );
  459. s = (char*)realloc( s, strlen( s ) + strlen( s2 ) + 1 );
  460. strcat( s, s2 );
  461. free( s2 );
  462. }
  463. Fl::copy(s, strlen(s) + 1, 0);
  464. Fl::selection_owner(this);
  465. free( s );
  466. Fl::dnd();
  467. return 1;
  468. }
  469. return 1;
  470. }
  471. /* we have to prevent Fl_Group::handle() from getting these, otherwise it will mess up Fl::belowmouse() */
  472. case FL_MOVE:
  473. if ( Fl::event_inside( output_connection_handle ) ||
  474. Fl::event_inside( output_connection2_handle ) ||
  475. Fl::event_inside( input_connection_handle ) )
  476. {
  477. fl_cursor( FL_CURSOR_HAND );
  478. }
  479. else
  480. fl_cursor( FL_CURSOR_DEFAULT );
  481. Module::handle(m);
  482. return 1;
  483. case FL_ENTER:
  484. case FL_DND_ENTER:
  485. Module::handle(m);
  486. return 1;
  487. case FL_LEAVE:
  488. case FL_DND_LEAVE:
  489. Module::handle(m);
  490. if ( this == receptive_to_drop )
  491. {
  492. receptive_to_drop = NULL;
  493. redraw();
  494. }
  495. fl_cursor( FL_CURSOR_DEFAULT );
  496. return 1;
  497. case FL_DND_RELEASE:
  498. Fl::selection_owner(0);
  499. receptive_to_drop = NULL;
  500. redraw();
  501. return 1;
  502. case FL_DND_DRAG:
  503. {
  504. if ( this == receptive_to_drop )
  505. return 1;
  506. if ( aux_audio_input.size() )
  507. {
  508. receptive_to_drop = this;
  509. redraw();
  510. return 1;
  511. }
  512. return 0;
  513. }
  514. case FL_PASTE:
  515. {
  516. receptive_to_drop = NULL;
  517. redraw();
  518. if ( ! Fl::event_inside( this ) )
  519. return 0;
  520. /* NOW we get the text... */
  521. const char *text = Fl::event_text();
  522. DMESSAGE( "Got drop text \"%s\"",text);
  523. if ( strncmp( text, "jack.port://", strlen( "jack.port://" ) ) )
  524. {
  525. return 0;
  526. }
  527. std::vector<std::string> port_names;
  528. char *port_name;
  529. int end;
  530. while ( sscanf( text, "jack.port://%a[^\r\n]\r\n%n", &port_name, &end ) > 0 )
  531. {
  532. DMESSAGE( "Scanning %s", port_name );
  533. port_names.push_back( port_name );
  534. free(port_name );
  535. text += end;
  536. }
  537. for ( unsigned int i = 0; i < aux_audio_input.size() && i < port_names.size(); i++)
  538. {
  539. const char *pn = port_names[i].c_str();
  540. JACK::Port *ji = aux_audio_input[i].jack_port();
  541. if ( ji->connected_to( pn ) )
  542. {
  543. DMESSAGE( "Disconnecting from \"%s\"", pn );
  544. ji->disconnect( pn );
  545. }
  546. else
  547. {
  548. DMESSAGE( "Connecting to %s", pn );
  549. ji->connect( pn );
  550. }
  551. }
  552. Fl::selection_owner(0);
  553. return 1;
  554. }
  555. }
  556. return Module::handle(m);
  557. }
  558. /**********/
  559. /* Engine */
  560. /**********/
  561. void
  562. JACK_Module::process ( nframes_t nframes )
  563. {
  564. for ( unsigned int i = 0; i < audio_input.size(); ++i )
  565. {
  566. if ( audio_input[i].connected() )
  567. {
  568. buffer_copy( (sample_t*)aux_audio_output[i].jack_port()->buffer(nframes),
  569. (sample_t*)audio_input[i].buffer(),
  570. nframes );
  571. }
  572. }
  573. for ( unsigned int i = 0; i < audio_output.size(); ++i )
  574. {
  575. if ( audio_output[i].connected() )
  576. {
  577. buffer_copy( (sample_t*)audio_output[i].buffer(),
  578. (sample_t*)aux_audio_input[i].jack_port()->buffer(nframes),
  579. nframes );
  580. }
  581. }
  582. }