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.

1268 lines
34KB

  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. /* Mixer strip control. Handles GUI and control I/O for this strip. */
  19. /* A mixer strip is home to some (JACK) input ports, a fader, some
  20. * meters, and a filter chain which can terminate either at the input
  21. * to the spacializer or some (JACK) output ports. Since mixer strips
  22. * are not necessarily in a 1:1 association with Non-DAW tracks, there
  23. * is no need for busses per se. If you want to route the output of
  24. * several strips into a single fader or filter chain, then you just
  25. * gives those strips JACK outputs and connect them to the common
  26. * inputs. This mechanism can also do away with the need for 'sends'
  27. * and 'inserts'.
  28. */
  29. /* Each mixer strip comprises a fader and a panner */
  30. #include "Project.H"
  31. #include "Mixer_Strip.H"
  32. #include <dsp.h>
  33. #include <string.h>
  34. #include "debug.h"
  35. #include "FL/Fl_Flowpack.H"
  36. #include <FL/Fl_Input.H>
  37. #include <FL/fl_ask.H>
  38. #include <FL/Fl_Color_Chooser.H>
  39. #include <FL/Fl.H>
  40. #include "Mixer.H"
  41. #include "Chain.H"
  42. #include "Gain_Module.H"
  43. #include "Meter_Module.H"
  44. #include "Controller_Module.H"
  45. #include "Meter_Indicator_Module.H"
  46. #include "debug.h"
  47. #include "FL/focus_frame.H"
  48. #include <FL/Fl_Menu_Button.H>
  49. #include "FL/test_press.H"
  50. #include "FL/menu_popup.H"
  51. #include <FL/Fl_File_Chooser.H>
  52. #include <FL/Fl_Choice.H>
  53. #include "Group.H"
  54. #include "FL/focus_frame.H"
  55. extern Mixer *mixer;
  56. /* add a new mixer strip (with default configuration) */
  57. Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
  58. {
  59. label( strdup( strip_name ) );
  60. labeltype( FL_NO_LABEL );
  61. init();
  62. _group = new Group(strip_name, true);
  63. _group->add( this );
  64. chain( new Chain() );
  65. _chain->initialize_with_default();
  66. _chain->configure_ports();
  67. color( (Fl_Color)rand() );
  68. // name( strdup( strip_name ) );
  69. log_create();
  70. }
  71. /* virgin strip created from journal */
  72. Mixer_Strip::Mixer_Strip() : Fl_Group( 0, 0, 120, 600 )
  73. {
  74. init();
  75. log_create();
  76. }
  77. Mixer_Strip::~Mixer_Strip ( )
  78. {
  79. DMESSAGE( "Destroying mixer strip" );
  80. // _chain->engine()->lock();
  81. log_destroy();
  82. mixer->remove( this );
  83. /* make sure this gets destroyed before the chain */
  84. fader_tab->clear();
  85. delete _chain;
  86. _chain = NULL;
  87. }
  88. void
  89. Mixer_Strip::get ( Log_Entry &e ) const
  90. {
  91. e.add( ":name", name() );
  92. e.add( ":width", width_button->value() ? "wide" : "narrow" );
  93. e.add( ":tab", tab_button->value() ? "signal" : "fader" );
  94. e.add( ":color", (unsigned long)color());
  95. /* since the default controllers aren't logged, we have to store
  96. * this setting as part of the mixer strip */
  97. e.add( ":gain_mode", gain_controller->mode() );
  98. e.add( ":mute_mode", mute_controller->mode() );
  99. if ( ! _group->single() )
  100. e.add( ":group", _group );
  101. else
  102. e.add( ":group", (Loggable*)0 );
  103. e.add( ":auto_input", _auto_input );
  104. e.add( ":manual_connection", _manual_connection );
  105. }
  106. void
  107. Mixer_Strip::set ( Log_Entry &e )
  108. {
  109. for ( int i = 0; i < e.size(); ++i )
  110. {
  111. const char *s, *v;
  112. e.get( i, &s, &v );
  113. if ( ! strcmp( s, ":name" ) )
  114. name( v );
  115. else if ( ! strcmp( s, ":width" ) )
  116. {
  117. width_button->value( strcmp( v, "wide" ) == 0 );
  118. width_button->do_callback();
  119. }
  120. else if ( ! strcmp( s, ":tab" ) )
  121. {
  122. tab_button->value( strcmp( v, "signal" ) == 0 );
  123. tab_button->do_callback();
  124. }
  125. else if ( ! strcmp( s, ":color" ) )
  126. {
  127. color( (Fl_Color)atoll( v ) );
  128. redraw();
  129. }
  130. else if ( ! strcmp( s, ":gain_mode" ) )
  131. {
  132. _gain_controller_mode = atoi( v );
  133. }
  134. else if ( ! strcmp( s, ":mute_mode" ) )
  135. {
  136. _mute_controller_mode = atoi( v );
  137. }
  138. else if ( ! strcmp( s, ":auto_input" ) )
  139. {
  140. auto_input( v );
  141. }
  142. else if ( ! strcmp( s, ":manual_connection" ) )
  143. {
  144. manual_connection( atoi( v ) );
  145. }
  146. else if ( ! strcmp( s, ":group" ) )
  147. {
  148. int i;
  149. sscanf( v, "%X", &i );
  150. if ( i )
  151. {
  152. Group *t = (Group*)Loggable::find( i );
  153. /* Because of strip copy/paste and import, we can't assure that the group will exist by ID*/
  154. // assert( t );
  155. group( t );
  156. }
  157. else
  158. group( 0 );
  159. }
  160. }
  161. if ( ! _group )
  162. group(0);
  163. if ( ! mixer->contains( this ) )
  164. mixer->add( this );
  165. }
  166. void
  167. Mixer_Strip::log_children ( void ) const
  168. {
  169. log_create();
  170. _chain->log_children();
  171. }
  172. void
  173. Mixer_Strip::color ( Fl_Color c )
  174. {
  175. _color = c;
  176. color_box->color( _color );
  177. color_box->redraw();
  178. }
  179. Fl_Color
  180. Mixer_Strip::color ( void ) const
  181. {
  182. return _color;
  183. }
  184. void
  185. Mixer_Strip::chain ( Chain *c )
  186. {
  187. if ( _chain )
  188. delete _chain;
  189. _chain = c;
  190. c->strip( this );
  191. Fl_Group *g = signal_tab;
  192. c->resize( g->x(), g->y(), g->w(), g->h() );
  193. g->add( c );
  194. g->resizable( c );
  195. c->labelsize( 10 );
  196. c->align( FL_ALIGN_TOP );
  197. c->color( FL_RED );
  198. c->configure_outputs_callback( configure_outputs, this );
  199. c->name( name() );
  200. /* FIXME: don't hardcode this list of modules */
  201. spatialization_controller->chain( c );
  202. gain_controller->chain( c );
  203. mute_controller->chain( c );
  204. jack_input_controller->chain( c );
  205. meter_indicator->chain( c );
  206. }
  207. void Mixer_Strip::cb_handle(Fl_Widget* o) {
  208. // parent()->parent()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );
  209. // DMESSAGE( "Callback for %s", o->label() );
  210. if ( o == tab_button )
  211. {
  212. if ( tab_button->value() == 0 )
  213. {
  214. fader_tab->resize( tab_group->x(), tab_group->y(), tab_group->w(), tab_group->h() );
  215. fader_tab->show();
  216. signal_tab->hide();
  217. tab_group->resizable( fader_tab );
  218. }
  219. else
  220. {
  221. signal_tab->resize( tab_group->x(), tab_group->y(), tab_group->w(), tab_group->h() );
  222. signal_tab->show();
  223. fader_tab->hide();
  224. tab_group->resizable( signal_tab );
  225. }
  226. set_spatializer_visibility();
  227. }
  228. else if ( o == close_button )
  229. {
  230. if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
  231. command_close();
  232. }
  233. else if ( o == name_field )
  234. {
  235. name( name_field->value() );
  236. Fl::focus( this );
  237. }
  238. else if ( o == width_button )
  239. {
  240. if ( width_button->value() )
  241. size( 220, h() );
  242. else
  243. size( 96, h() );
  244. if ( parent() )
  245. parent()->parent()->redraw();
  246. }
  247. else if ( o == output_connection_button )
  248. {
  249. if ( output_connection_button->value() == 1 )
  250. o->label( output_connection_button->mvalue()->label() );
  251. else
  252. o->label( NULL );
  253. manual_connection( output_connection_button->value() );
  254. // _manual_connection = output_connection_button->value();
  255. }
  256. else if ( o == group_choice )
  257. {
  258. // group(group_choice->value());
  259. Group *g = NULL;
  260. if ( group_choice->value() == group_choice->size() - 2 )
  261. {
  262. /* create a new group */
  263. const char *s = fl_input( "Name for Group:" );
  264. if ( !s )
  265. return;
  266. char *n = mixer->get_unique_group_name( s );
  267. g = new Group( n, false );
  268. free( n );
  269. mixer->add_group( g );
  270. }
  271. else
  272. {
  273. g = (Group*)group_choice->mvalue()->user_data();
  274. }
  275. group(g);
  276. }
  277. }
  278. void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
  279. ((Mixer_Strip*)(v))->cb_handle(o);
  280. }
  281. void
  282. Mixer_Strip::group ( Group *g )
  283. {
  284. if ( !g && _group && _group->single() )
  285. return;
  286. if ( _group )
  287. {
  288. _group->remove(this);
  289. if ( ! _group->nstrips() )
  290. {
  291. if ( ! _group->single() )
  292. mixer->remove_group( _group );
  293. delete _group;
  294. _group = NULL;
  295. }
  296. }
  297. if ( ! g )
  298. g = new Group(name(), true);
  299. const Fl_Menu_Item *menu = group_choice->menu();
  300. for ( unsigned int i = 0; menu[i].text; i++ )
  301. if ( menu[i].user_data() == g )
  302. group_choice->value( i );
  303. // group_choice->color( (Fl_Color)n );
  304. // group_choice->value( n );
  305. _group = g;
  306. g->add(this);
  307. }
  308. void
  309. Mixer_Strip::name ( const char *name )
  310. {
  311. if ( this->name() && !strcmp( name, this->name() ) )
  312. return;
  313. name = mixer->get_unique_track_name( name );
  314. char *s = strdup( name );
  315. if ( strlen( s ) > Chain::maximum_name_length() )
  316. {
  317. s[Chain::maximum_name_length() - 1] = '\0';
  318. fl_alert( "Name \"%s\" is too long, truncating to \"%s\"", name, s );
  319. }
  320. name_field->value( s );
  321. label( s );
  322. if ( _chain )
  323. _chain->name( s );
  324. }
  325. void
  326. Mixer_Strip::configure_outputs ( Fl_Widget *, void *v )
  327. {
  328. ((Mixer_Strip*)v)->configure_outputs();
  329. }
  330. void
  331. Mixer_Strip::configure_outputs ( void )
  332. {
  333. DMESSAGE( "Got signal to configure outputs" );
  334. }
  335. void
  336. Mixer_Strip::set_spatializer_visibility ( void )
  337. {
  338. if ( fader_tab->visible() && spatialization_controller->is_controlling() )
  339. {
  340. spatialization_controller->show();
  341. spatialization_label->show();
  342. }
  343. else
  344. {
  345. spatialization_controller->hide();
  346. spatialization_label->hide();
  347. }
  348. }
  349. /* called by the chain to let us know that a module has been added */
  350. void
  351. Mixer_Strip::handle_module_added ( Module *m )
  352. {
  353. if ( m->is_default() )
  354. {
  355. DMESSAGE( "Connecting controls to default module \"%s\"", m->name() );
  356. /* connect default modules to their default controllers/indicators */
  357. if ( 0 == strcmp( m->name(), "JACK" ) && m->ninputs() == 0 )
  358. {
  359. if ( !jack_input_controller->control_output[0].connected() )
  360. jack_input_controller->connect_to( &m->control_input[1] );
  361. }
  362. else if ( 0 == strcmp( m->name(), "Gain" ) )
  363. {
  364. gain_controller->connect_to( &m->control_input[0] );
  365. gain_controller->mode( (Controller_Module::Mode)_gain_controller_mode );
  366. mute_controller->connect_to( &m->control_input[1] );
  367. mute_controller->mode( (Controller_Module::Mode)_mute_controller_mode );
  368. }
  369. else if ( 0 == strcmp( m->name(), "Meter" ) )
  370. {
  371. meter_indicator->connect_to( &m->control_output[0] );
  372. }
  373. }
  374. else
  375. {
  376. if ( spatialization_controller->connect_spatializer_to( m ) )
  377. {
  378. DMESSAGE( "Connected spatializer to module \"%s\"", m->name() );
  379. set_spatializer_visibility();
  380. }
  381. }
  382. }
  383. /* called by the chain to let us know that a module has been removed */
  384. void
  385. Mixer_Strip::handle_module_removed ( Module *m )
  386. {
  387. if ( spatialization_controller->control_output[0].connected() &&
  388. spatialization_controller->control_output[0].connected_port()->module() == m )
  389. {
  390. set_spatializer_visibility();
  391. DMESSAGE( "Module \"%s\" disconnected from spatialization controller", m->label() );
  392. }
  393. }
  394. /* update GUI with values from RT thread */
  395. void
  396. Mixer_Strip::update ( void )
  397. {
  398. THREAD_ASSERT( UI );
  399. meter_indicator->update();
  400. gain_controller->update();
  401. mute_controller->update();
  402. if ( _chain )
  403. {
  404. _chain->update();
  405. }
  406. if ( group() )
  407. {
  408. if ( ( _dsp_load_index++ % 10 ) == 0 )
  409. {
  410. float l = group()->dsp_load();
  411. dsp_load_progress->value( l );
  412. {
  413. char pat[20];
  414. snprintf( pat, sizeof(pat), "%.1f%%", l * 100.0f );
  415. dsp_load_progress->copy_tooltip( pat );
  416. }
  417. if ( l <= 0.15f )
  418. dsp_load_progress->color2( fl_rgb_color( 127,127,127 ) );
  419. else
  420. dsp_load_progress->color2( FL_RED );
  421. }
  422. }
  423. }
  424. void
  425. Mixer_Strip::init ( )
  426. {
  427. selection_color( FL_YELLOW );
  428. _manual_connection = 0;
  429. _auto_input = 0;
  430. _mute_controller_mode = 0;
  431. _gain_controller_mode = 0;
  432. _chain = 0;
  433. _group = 0;
  434. _dsp_load_index = 0;
  435. box( FL_FLAT_BOX );
  436. labeltype( FL_NO_LABEL );
  437. Fl_Group::color( FL_BACKGROUND_COLOR );
  438. set_visible_focus();
  439. { Fl_Scalepack *o = new Fl_Scalepack( 2, 2, 116, 595 );
  440. o->type( FL_VERTICAL );
  441. o->spacing( 2 );
  442. { Fl_Box *o = color_box = new Fl_Box( 0,0, 25, 10 );
  443. o->box(FL_FLAT_BOX);
  444. o->tooltip( "Drag and drop to move strip" );
  445. }
  446. { Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
  447. o->type( Fl_Pack::VERTICAL );
  448. o->spacing( 2 );
  449. {
  450. Fl_Sometimes_Input *o = new Fl_Sometimes_Input( 2, 2, 144, 15 );
  451. name_field = o;
  452. o->up_box( FL_NO_BOX );
  453. o->box( FL_FLAT_BOX );
  454. o->selection_color( FL_BLACK );
  455. o->labeltype( FL_NO_LABEL );
  456. o->labelcolor( FL_GRAY0 );
  457. o->textcolor( FL_FOREGROUND_COLOR );
  458. o->textsize( 12 );
  459. o->value( name() );
  460. o->callback( cb_handle, (void*)this );
  461. }
  462. { Fl_Scalepack *o = new Fl_Scalepack( 7, 143, 110, 18 );
  463. o->type( Fl_Pack::HORIZONTAL );
  464. { Fl_Flip_Button* o = width_button = new Fl_Flip_Button(61, 183, 45, 22, "[]/[-]");
  465. o->type(1);
  466. o->tooltip( "Switch between wide and narrow views" );
  467. o->labelfont( FL_COURIER_BOLD );
  468. o->labelsize(10);
  469. o->callback( ((Fl_Callback*)cb_handle), this );
  470. o->when(FL_WHEN_RELEASE);
  471. }
  472. { Fl_Button* o = close_button = new Fl_Button(7, 143, 35, 25, "X");
  473. o->tooltip( "Remove strip" );
  474. o->type(0);
  475. o->labelfont( FL_COURIER_BOLD );
  476. o->selection_color( FL_RED );
  477. o->labelsize(10);
  478. o->when( FL_WHEN_RELEASE );
  479. o->callback( ((Fl_Callback*)cb_handle), this );
  480. } // Fl_Button* o
  481. o->end();
  482. } // Fl_Group* o
  483. { Fl_Progress* o = dsp_load_progress = new Fl_Progress(61, 183, 45, 14, "group dsp");
  484. o->box(FL_BORDER_BOX);
  485. o->type(FL_HORIZONTAL);
  486. o->labelsize( 9 );
  487. o->minimum( 0 );
  488. // o->maximum( 0.25f );
  489. o->maximum( 1 );
  490. o->color(fl_rgb_color( 10,10,10 ) );
  491. o->color2(FL_CYAN);
  492. }
  493. { Fl_Choice* o = group_choice = new Fl_Choice(61, 183, 45, 22);
  494. o->tooltip( "Create or assign group" );
  495. o->labeltype(FL_NO_LABEL);
  496. o->labelsize(10);
  497. o->textsize(10);
  498. o->add("---");
  499. o->value(0);
  500. o->callback( ((Fl_Callback*)cb_handle), this );
  501. }
  502. { Fl_Scalepack *o = new Fl_Scalepack( 0,0, 45, 22 );
  503. o->type( FL_HORIZONTAL );
  504. { Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "Fadr/Signl");
  505. o->tooltip( "Switch between fader and signal views" );
  506. o->type(1);
  507. o->labelsize( 10 );
  508. o->callback( ((Fl_Callback*)cb_handle), this );
  509. o->when(FL_WHEN_RELEASE);
  510. }
  511. { Controller_Module *o = mute_controller = new Controller_Module( true );
  512. o->pad( false );
  513. o->size( 45, 22 );
  514. }
  515. o->end();
  516. }
  517. o->end();
  518. }
  519. /* { Fl_Scalepack *o = new Fl_Scalepack( 2, 103, 114, 490 ); */
  520. /* o->type( FL_VERTICAL ); */
  521. // o->box( FL_FLAT_BOX );
  522. // o->color( FL_BACKGROUND_COLOR );
  523. { Fl_Group *o = tab_group = new Fl_Group( 2, 116, 105, 330 );
  524. o->box( FL_NO_BOX );
  525. { Fl_Group *o = fader_tab = new Fl_Group( 2, 116, 105, 330, "Fader" );
  526. o->box( FL_NO_BOX );
  527. o->labeltype( FL_NO_LABEL );
  528. { Fl_Pack *o = new Fl_Pack( 2, 116, 105, 15 );
  529. o->type( FL_VERTICAL );
  530. {
  531. Controller_Module *m = jack_input_controller = new Controller_Module( true );
  532. m->labeltype( FL_NO_LABEL );
  533. m->chain( _chain );
  534. m->pad( false );
  535. m->size( 105, 15 );
  536. }
  537. o->resizable(0);
  538. o->end();
  539. }
  540. { Fl_Scalepack* o = new Fl_Scalepack(2, 135, 105, 311 );
  541. // o->box( FL_BORDER_BOX );
  542. // o->color( FL_RED );
  543. o->spacing( 20 );
  544. o->type( Fl_Scalepack::HORIZONTAL );
  545. { Controller_Module *o = gain_controller = new Controller_Module( true );
  546. o->horizontal(false);
  547. o->clear_visible_focus();
  548. o->pad( false );
  549. o->size( 33, 100 );
  550. }
  551. { Meter_Indicator_Module *o = meter_indicator = new Meter_Indicator_Module( true );
  552. o->disable_context_menu( true );
  553. o->pad( false );
  554. o->size( 38, 100 );
  555. Fl_Group::current()->resizable(o);
  556. }
  557. o->end();
  558. Fl_Group::current()->resizable(o);
  559. } // Fl_Group* o
  560. o->end();
  561. Fl_Group::current()->resizable(o);
  562. }
  563. { Fl_Group *o = signal_tab = new Fl_Group( 2, 116, 105, 330 );
  564. o->box( FL_NO_BOX );
  565. o->labeltype( FL_NO_LABEL );
  566. o->hide();
  567. o->end();
  568. }
  569. o->end();
  570. Fl_Group::current()->resizable( o );
  571. }
  572. /* { Fl_Pack *o = panner_pack = new Fl_Pack( 2, 465, 114, 40 ); */
  573. /* o->spacing( 2 ); */
  574. /* o->type( Fl_Pack::VERTICAL ); */
  575. { Fl_Box *o = spatialization_label = new Fl_Box( 0, 0, 100, 12 );
  576. o->align( (Fl_Align)(FL_ALIGN_BOTTOM | FL_ALIGN_INSIDE) );
  577. o->labelsize( 10 );
  578. o->hide();
  579. o->label( "Spatialization" );
  580. }
  581. { Controller_Module *o = spatialization_controller = new Controller_Module( true );
  582. o->hide();
  583. o->label( 0 );
  584. o->pad( false );
  585. o->size( 92,92 );
  586. }
  587. /* o->end(); */
  588. /* } */
  589. { Fl_Menu_Button *o = output_connection_button = new Fl_Menu_Button( 0, 0, 10, 18 );
  590. o->labelsize( 9 );
  591. o->add("- auto -");
  592. o->add("- manual -");
  593. o->align( FL_ALIGN_CLIP );
  594. o->labelcolor( FL_YELLOW );
  595. o->callback( cb_handle, this );
  596. o->hide();
  597. }
  598. o->end();
  599. }
  600. end();
  601. color( FL_BLACK );
  602. size( 96, h() );
  603. update_group_choice();
  604. // redraw();
  605. // _chain->configure_ports();
  606. }
  607. void
  608. Mixer_Strip::update_group_choice ( void )
  609. {
  610. Fl_Choice *o = group_choice;
  611. o->clear();
  612. o->add( "---" );
  613. for ( std::list<Group*>::iterator i = mixer->groups.begin(); i != mixer->groups.end(); )
  614. {
  615. Group *g = *i;
  616. i++;
  617. if ( i == mixer->groups.end() )
  618. {
  619. o->add( g->name(), 0, 0, (void*)g, FL_MENU_DIVIDER );
  620. break;
  621. }
  622. else
  623. o->add( g->name(), 0, 0, (void*)g );
  624. }
  625. o->add( "New Group" );
  626. const Fl_Menu_Item *menu = o->menu();
  627. if ( ! group() || ( group() && group()->single() ) )
  628. o->value(0);
  629. else
  630. {
  631. for ( unsigned int i = 0; menu[i].text; i++ )
  632. if ( menu[i].user_data() == group() )
  633. o->value( i );
  634. }
  635. }
  636. void
  637. Mixer_Strip::draw ( void )
  638. {
  639. /* don't bother drawing anything else, all we're doing is drawing the focus. */
  640. // if ( damage() & ~FL_DAMAGE_USER1 )
  641. Fl_Group::draw();
  642. if ( focused_r( this ) )
  643. draw_focus_frame( x(),y(),w(),h(), Fl_Group::selection_color() );
  644. /* else */
  645. /* clear_focus_frame( x(),y(),w(),h(), FL_BACKGROUND_COLOR ); */
  646. }
  647. /*****************/
  648. /* Import/Export */
  649. /*****************/
  650. void
  651. Mixer_Strip::snapshot ( void *v )
  652. {
  653. ((Mixer_Strip*)v)->snapshot();
  654. }
  655. void
  656. Mixer_Strip::snapshot ( void )
  657. {
  658. log_children();
  659. }
  660. bool
  661. Mixer_Strip::export_strip ( const char *filename )
  662. {
  663. MESSAGE( "Exporting chain state" );
  664. Loggable::snapshot_callback( &Mixer_Strip::snapshot, this );
  665. Loggable::snapshot( filename );
  666. return true;
  667. }
  668. bool
  669. Mixer_Strip::import_strip ( const char *filename )
  670. {
  671. MESSAGE( "Importing new chain state" );
  672. Loggable::begin_relative_id_mode();
  673. int r = Loggable::replay( filename );
  674. Loggable::end_relative_id_mode();
  675. return r;
  676. }
  677. void
  678. Mixer_Strip::menu_cb ( const Fl_Menu_ *m )
  679. {
  680. char picked[256];
  681. m->item_pathname( picked, sizeof( picked ) );
  682. Logger log( this );
  683. if ( ! strcmp( picked, "Width/Narrow" ) )
  684. command_width( false );
  685. else if ( ! strcmp( picked, "Width/Wide" ) )
  686. command_width( true );
  687. else if ( ! strcmp( picked, "View/Fader" ) )
  688. command_view( false );
  689. else if ( ! strcmp( picked, "View/Signal" ) )
  690. command_view( true );
  691. else if ( ! strcmp( picked, "/Move Left" ) )
  692. command_move_left();
  693. else if ( ! strcmp( picked, "/Move Right" ) )
  694. command_move_right();
  695. else if ( ! strcmp( picked, "/Rename" ) )
  696. {
  697. ((Fl_Sometimes_Input*)name_field)->take_focus();
  698. }
  699. else if ( ! strcmp( picked, "/Copy" ) )
  700. {
  701. export_strip( "clipboard.strip" );
  702. char *s;
  703. asprintf( &s, "file://%s/%s\r\n", Project::path(), "clipboard.strip" );
  704. Fl::copy( s, strlen(s), 0 );
  705. free(s);
  706. }
  707. else if ( ! strcmp( picked, "/Color" ) )
  708. {
  709. unsigned char r, g, b;
  710. Fl::get_color( color(), r, g, b );
  711. if ( fl_color_chooser( "Strip Color", r, g, b ) )
  712. color( fl_rgb_color( r, g, b ) );
  713. redraw();
  714. }
  715. else if ( !strcmp( picked, "/Export Strip" ) )
  716. {
  717. char *suggested_name;
  718. asprintf( &suggested_name, "%s.strip", name() );
  719. const char *s = fl_file_chooser( "Export strip to filename:", "*.strip", suggested_name, 0 );
  720. free( suggested_name );
  721. if ( s )
  722. export_strip( s );
  723. fl_message( "Strip exported." );
  724. }
  725. else if ( ! strcmp( picked, "/Remove" ) )
  726. {
  727. if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
  728. command_close();
  729. }
  730. else if ( ! strcmp( picked, "/Gain" ) )
  731. {
  732. gain_controller->take_focus();
  733. }
  734. else if ( ! strcmp( picked, "/Mute" ) )
  735. {
  736. ((Fl_Button*)mute_controller->child(0))->value( !
  737. ((Fl_Button*)mute_controller->child(0))->value());
  738. }
  739. else if ( ! strcmp( picked, "Auto Output/On" ) )
  740. {
  741. manual_connection( false );
  742. }
  743. else if ( ! strcmp( picked, "Auto Output/Off" ) )
  744. {
  745. manual_connection( true );
  746. }
  747. else if ( ! strncmp( picked, "Auto Input/", strlen( "Auto Input/" ) ))
  748. {
  749. const char *s = index( picked, '/' ) + 1;
  750. if ( ! strcmp( s, "Off" ) )
  751. auto_input( NULL );
  752. else
  753. auto_input( s );
  754. }
  755. }
  756. void
  757. Mixer_Strip::menu_cb ( Fl_Widget *w, void *v )
  758. {
  759. ((Mixer_Strip*)v)->menu_cb( (Fl_Menu_*) w );
  760. }
  761. void
  762. Mixer_Strip::auto_input ( const char *s )
  763. {
  764. if ( _auto_input )
  765. free( _auto_input );
  766. _auto_input = NULL;
  767. if ( s )
  768. _auto_input = strdup( s );
  769. mixer->auto_connect();
  770. }
  771. void
  772. Mixer_Strip::manual_connection ( bool b )
  773. {
  774. _manual_connection = b;
  775. output_connection_button->value(b);
  776. if ( chain() )
  777. {
  778. if ( b )
  779. chain()->auto_disconnect_outputs();
  780. else
  781. chain()->auto_connect_outputs();
  782. }
  783. }
  784. static bool matches_pattern ( const char *pattern, Module::Port *p )
  785. {
  786. char group_name[256];
  787. char port_group[256];
  788. if ( 2 == sscanf( pattern, "%[^/]/%[^\n]", group_name, port_group ))
  789. {
  790. if ( strcmp( group_name, "*" ) &&
  791. strcmp( group_name, p->module()->chain()->strip()->group()->name() ))
  792. {
  793. /* group mismatch */
  794. return false;
  795. }
  796. /* group matches... try port group */
  797. if ( ! strcmp( port_group, "mains" ) )
  798. {
  799. if ( index( p->jack_port()->name(), '/' ) )
  800. return false;
  801. else
  802. return true;
  803. }
  804. else
  805. {
  806. const char *pn = p->jack_port()->name();
  807. const char *n = rindex( pn, '/' );
  808. if ( n )
  809. {
  810. // *n = 0;
  811. if ( ! strncmp( port_group, pn, ( n - 1 ) - pn ) )
  812. return true;
  813. else
  814. return false;
  815. }
  816. else
  817. return false;
  818. }
  819. }
  820. return false;
  821. }
  822. #include "JACK_Module.H"
  823. void
  824. Mixer_Strip::auto_connect_outputs ( void )
  825. {
  826. chain()->auto_connect_outputs();
  827. }
  828. bool
  829. Mixer_Strip::has_group_affinity ( void ) const
  830. {
  831. return _auto_input && strncmp( _auto_input, "*/", 2 );
  832. }
  833. bool
  834. Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
  835. {
  836. if ( p->module()->chain()->strip()->_manual_connection )
  837. return true;
  838. if ( p->module()->chain()->strip() == this )
  839. /* don't auto connect to self! */
  840. return false;
  841. if ( ! _auto_input )
  842. {
  843. if ( p->connected_port() && p->connected_port()->module()->chain()->strip() == this )
  844. {
  845. /* first break previous auto connection */
  846. p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
  847. p->disconnect();
  848. }
  849. }
  850. if ( _auto_input && matches_pattern( _auto_input, p ) )
  851. {
  852. DMESSAGE( "Auto connecting port" );
  853. if ( p->connected_port() )
  854. {
  855. /* first break previous auto connection */
  856. p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
  857. p->disconnect();
  858. }
  859. const char* jack_name = p->jack_port()->jack_name();
  860. /* get port number */
  861. const char *s = rindex( jack_name, '-' );
  862. unsigned int n = atoi( s + 1 ) - 1;
  863. /* FIXME: safe assumption? */
  864. JACK_Module *m = (JACK_Module*)chain()->module(0);
  865. if ( n < m->aux_audio_input.size() )
  866. {
  867. m->aux_audio_input[n].jack_port()->connect( jack_name );
  868. /* make a note of the connection so we know to disconnected later */
  869. m->aux_audio_input[n].connect_to( p );
  870. }
  871. if ( p->module()->is_default() )
  872. {
  873. /* only do this for mains */
  874. p->module()->chain()->strip()->output_connection_button->copy_label( name() );
  875. p->module()->chain()->strip()->output_connection_button->labelcolor( FL_FOREGROUND_COLOR );
  876. }
  877. return true;
  878. }
  879. return false;
  880. }
  881. /** build the context menu */
  882. Fl_Menu_Button &
  883. Mixer_Strip::menu ( void ) const
  884. {
  885. static Fl_Menu_Button m( 0, 0, 0, 0, "Strip" );
  886. static char label[256];
  887. snprintf( label, sizeof(label), "Strip/%s", name() );
  888. m.label( label );
  889. // int c = output.size();
  890. m.clear();
  891. std::list<std::string> sl = mixer->get_auto_connect_targets();
  892. m.add( "Auto Output/On", 0, 0, 0, FL_MENU_RADIO | ( _manual_connection ? 0 : FL_MENU_VALUE ) );
  893. m.add( "Auto Output/Off", 0, 0, 0, FL_MENU_RADIO | ( ! _manual_connection ? 0 : FL_MENU_VALUE ) );
  894. m.add( "Auto Input/Off", 0, 0, 0, FL_MENU_DIVIDER | FL_MENU_RADIO | ( _auto_input ? 0 : FL_MENU_VALUE ) );
  895. for ( std::list<std::string>::iterator i = sl.begin(); i != sl.end(); i++ )
  896. {
  897. char *s;
  898. asprintf( &s, "Auto Input/%s", i->c_str() );
  899. m.add( s, 0,0,0, FL_MENU_RADIO | ( _auto_input && !strcmp( _auto_input, i->c_str() ) ? FL_MENU_VALUE : 0 ));
  900. free(s );
  901. }
  902. m.add( "Width/Narrow", 'n', 0, 0, FL_MENU_RADIO | ( ! width_button->value() ? FL_MENU_VALUE : 0 ));
  903. m.add( "Width/Wide", 'w', 0, 0, FL_MENU_RADIO | ( width_button->value() ? FL_MENU_VALUE : 0 ) );
  904. m.add( "View/Fader", 'f', 0, 0, FL_MENU_RADIO | ( 0 == tab_button->value() ? FL_MENU_VALUE : 0 ) );
  905. m.add( "View/Signal", 's', 0, 0, FL_MENU_RADIO | ( 1 == tab_button->value() ? FL_MENU_VALUE : 0 ) );
  906. m.add( "Mute", 'm', 0, 0, 0 );
  907. // ( 1 == mute_controller->control_output[0].connected_port()->control_value() ? FL_MENU_VALUE : 0 ) );
  908. m.add( "Gain", 'g', 0, 0 );
  909. m.add( "Move Left", '[', 0, 0 );
  910. m.add( "Move Right", ']', 0, 0 );
  911. m.add( "Color", 0, 0, 0 );
  912. m.add( "Copy", FL_CTRL + 'c', 0, 0 );
  913. m.add( "Export Strip", 0, 0, 0 );
  914. m.add( "Rename", FL_CTRL + 'n', 0, 0 );
  915. m.add( "Remove", FL_Delete, 0, 0 );
  916. menu_set_callback( const_cast<Fl_Menu_Item*>(m.menu()), &Mixer_Strip::menu_cb, (void*)this );
  917. return m;
  918. }
  919. Controller_Module *
  920. Mixer_Strip::spatializer ( void )
  921. {
  922. return spatialization_controller;
  923. }
  924. void
  925. Mixer_Strip::get_output_ports ( std::list<std::string> &ports )
  926. {
  927. _chain->get_output_ports(ports);
  928. }
  929. int
  930. Mixer_Strip::handle ( int m )
  931. {
  932. static int _button = 0;
  933. Logger log( this );
  934. static Fl_Widget *dragging = NULL;
  935. if ( Fl_Group::handle( m ) )
  936. return 1;
  937. switch ( m )
  938. {
  939. case FL_FOCUS:
  940. damage( FL_DAMAGE_USER1 );
  941. return 1;
  942. case FL_UNFOCUS:
  943. damage( FL_DAMAGE_USER1 );
  944. return 1;
  945. }
  946. /* if ( m == FL_PUSH ) */
  947. /* take_focus(); */
  948. switch ( m )
  949. {
  950. case FL_KEYBOARD:
  951. {
  952. if ( Fl::event_key() == FL_Menu )
  953. {
  954. menu_popup( &menu(), x(), y() );
  955. return 1;
  956. }
  957. else
  958. return menu().test_shortcut() != 0;
  959. break;
  960. }
  961. case FL_PUSH:
  962. if ( Fl::event_button1() && Fl::event_inside( color_box ) )
  963. dragging = this;
  964. else
  965. dragging = NULL;
  966. _button = Fl::event_button();
  967. return 1;
  968. break;
  969. case FL_DRAG:
  970. return 1;
  971. break;
  972. case FL_RELEASE:
  973. if ( dragging == this && ! Fl::event_is_click() )
  974. {
  975. mixer->insert( this, mixer->event_inside() );
  976. /* FIXME: do better! */
  977. mixer->redraw();
  978. dragging = NULL;
  979. return 1;
  980. }
  981. dragging = NULL;
  982. int b = _button;
  983. _button = 0;
  984. /* if ( 1 == b ) */
  985. /* { */
  986. /* take_focus(); */
  987. /* } */
  988. /* else */
  989. if ( 3 == b )
  990. {
  991. menu_popup( &menu() );
  992. return 1;
  993. }
  994. break;
  995. }
  996. return 0;
  997. }
  998. void
  999. Mixer_Strip::send_feedback ( void )
  1000. {
  1001. if ( _chain )
  1002. _chain->send_feedback();
  1003. }
  1004. int
  1005. Mixer_Strip::number ( void ) const
  1006. {
  1007. return mixer->find_strip( this );
  1008. }
  1009. /************/
  1010. /* Commands */
  1011. /************/
  1012. void
  1013. Mixer_Strip::command_toggle_fader_view ( void )
  1014. {
  1015. tab_button->value( ! tab_button->value() );
  1016. tab_button->do_callback();
  1017. }
  1018. void
  1019. Mixer_Strip::command_move_left ( void )
  1020. {
  1021. mixer->move_left( this );
  1022. }
  1023. void
  1024. Mixer_Strip::command_move_right ( void )
  1025. {
  1026. mixer->move_right( this );
  1027. }
  1028. void
  1029. Mixer_Strip::command_close ( void )
  1030. {
  1031. mixer->remove( this );
  1032. Fl::delete_widget( this );
  1033. }
  1034. void
  1035. Mixer_Strip::command_rename ( const char * s )
  1036. {
  1037. name( s );
  1038. }
  1039. void
  1040. Mixer_Strip::command_width ( bool b )
  1041. {
  1042. width_button->value( b );
  1043. width_button->do_callback();
  1044. }
  1045. void
  1046. Mixer_Strip::command_view ( bool b )
  1047. {
  1048. tab_button->value( b );
  1049. tab_button->do_callback();
  1050. }