Non reinvents the DAW. Powerful enough to form a complete studio, fast and light enough to run on low-end hardware like the eeePC or Raspberry Pi, and so reliable that it can be used live https://non.tuxfamily.org/
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.

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