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.

853 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 "Module.H"
  19. #include <FL/fl_draw.H>
  20. #include <FL/fl_ask.H>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include "Module_Parameter_Editor.H"
  25. #include "Chain.H"
  26. #include "JACK_Module.H"
  27. #include "Gain_Module.H"
  28. #include "Mono_Pan_Module.H"
  29. #include "Meter_Module.H"
  30. #include "Plugin_Module.H"
  31. #include <FL/Fl_Menu_Button.H>
  32. #include "FL/test_press.H"
  33. #include "FL/menu_popup.H"
  34. #include "Mixer.H"
  35. #include "OSC/Endpoint.H"
  36. #include "string_util.h"
  37. Module *Module::_copied_module_empty = 0;
  38. char *Module::_copied_module_settings = 0;
  39. Module::Module ( int W, int H, const char *L ) : Fl_Group( 0, 0, W, H, L )
  40. {
  41. init();
  42. log_create();
  43. }
  44. Module::Module ( bool is_default, int W, int H, const char *L ) : Fl_Group( 0, 0, W, H, L ), Loggable( !is_default )
  45. {
  46. this->is_default( is_default );
  47. init();
  48. log_create();
  49. }
  50. Module::Module ( ) : Fl_Group( 0, 0, 50, 50, "Unnamed" )
  51. {
  52. init();
  53. log_create();
  54. }
  55. Module::~Module ( )
  56. {
  57. /* we assume that the engine for this chain is already locked */
  58. if ( _editor )
  59. {
  60. delete _editor;
  61. _editor = NULL;
  62. }
  63. for ( unsigned int i = 0; i < audio_input.size(); ++i )
  64. audio_input[i].disconnect();
  65. for ( unsigned int i = 0; i < audio_output.size(); ++i )
  66. audio_output[i].disconnect();
  67. for ( unsigned int i = 0; i < control_input.size(); ++i )
  68. {
  69. /* destroy connected Controller_Module */
  70. if ( control_input[i].connected() )
  71. {
  72. Module *o = (Module*)control_input[i].connected_port()->module();
  73. control_input[i].disconnect();
  74. delete o;
  75. }
  76. control_input[i].destroy_osc_port();
  77. }
  78. for ( unsigned int i = 0; i < control_output.size(); ++i )
  79. control_output[i].disconnect();
  80. audio_input.clear();
  81. audio_output.clear();
  82. control_input.clear();
  83. control_output.clear();
  84. if ( parent() )
  85. parent()->remove( this );
  86. }
  87. void
  88. Module::init ( void )
  89. {
  90. _is_default = false;
  91. _editor = 0;
  92. _chain = 0;
  93. _instances = 1;
  94. _bypass = 0;
  95. box( FL_UP_BOX );
  96. labeltype( FL_NO_LABEL );
  97. set_visible_focus();
  98. selection_color( FL_RED );
  99. }
  100. void
  101. Module::get ( Log_Entry &e ) const
  102. {
  103. // e.add( ":name", label() );
  104. // e.add( ":color", (unsigned long)color());
  105. {
  106. char *s = get_parameters();
  107. if ( strlen( s ) )
  108. e.add( ":parameter_values", s );
  109. delete[] s;
  110. }
  111. e.add( ":is_default", is_default() );
  112. e.add( ":chain", chain() );
  113. e.add( ":active", ! bypass() );
  114. }
  115. void
  116. Module::copy ( void ) const
  117. {
  118. Module *m = clone_empty();
  119. if ( ! m )
  120. {
  121. DMESSAGE( "Module \"%s\" doesn't support cloning", name() );
  122. }
  123. Log_Entry *ne = new Log_Entry();
  124. _copied_module_empty = m;
  125. {
  126. Log_Entry e;
  127. get( e );
  128. for ( int i = 0; i < e.size(); ++i )
  129. {
  130. const char *s, *v;
  131. e.get( i, &s, &v );
  132. /* we don't want this module to get added to the current
  133. chain... */
  134. if ( !( !strcmp( s, ":chain" ) ||
  135. !strcmp( s, ":is_default" ) ) )
  136. {
  137. DMESSAGE( "%s = %s", s, v );
  138. ne->add_raw( s, v );
  139. }
  140. }
  141. }
  142. _copied_module_settings = ne->print();
  143. }
  144. void
  145. Module::paste_before ( void )
  146. {
  147. Module *m = _copied_module_empty;
  148. m->chain( chain() );
  149. Log_Entry le( _copied_module_settings );
  150. m->set( le );
  151. if ( ! chain()->insert( this, m ) )
  152. {
  153. fl_alert( "Copied module cannot be inserted at this point in the chain" );
  154. }
  155. free( _copied_module_settings );
  156. _copied_module_settings = NULL;
  157. _copied_module_empty = NULL;
  158. /* set up for another copy */
  159. m->copy();
  160. }
  161. void
  162. Module::handle_control_changed ( Port *p )
  163. {
  164. if ( _editor )
  165. _editor->handle_control_changed ( p );
  166. }
  167. bool
  168. Module::Port::connected_osc ( void ) const
  169. {
  170. return _scaled_signal->connected();
  171. }
  172. char *
  173. Module::Port::generate_osc_path ()
  174. {
  175. const Port *p = this;
  176. char *path = NULL;
  177. // /strip/STRIPNAME/MODULENAME/CONTROLNAME
  178. if ( ! module()->allows_external_control() )
  179. {
  180. /* Don't create signals for the default modules other than Gain */
  181. return NULL;
  182. }
  183. int n = module()->chain()->get_module_instance_number( module() );
  184. if ( n > 0 )
  185. asprintf( &path, "/strip/%s/%s.%i/%s", module()->chain()->name(), p->module()->label(), n, p->name() );
  186. else
  187. asprintf( &path, "/strip/%s/%s/%s", module()->chain()->name(), p->module()->label(), p->name() );
  188. char *s = escape_url( path );
  189. free( path );
  190. path = s;
  191. return path;
  192. }
  193. void
  194. Module::Port::handle_signal_connection_state_changed ( OSC::Signal *, void *o )
  195. {
  196. ((Module::Port*)o)->module()->redraw();
  197. }
  198. void
  199. Module::Port::change_osc_path ( char *path )
  200. {
  201. if ( path )
  202. {
  203. char *scaled_path = path;
  204. char *unscaled_path = NULL;
  205. asprintf( &unscaled_path, "%s/unscaled", path );
  206. if ( NULL == _scaled_signal )
  207. {
  208. float scaled_default = 0.5f;
  209. if ( hints.ranged )
  210. {
  211. float scale = hints.maximum - hints.minimum;
  212. float offset = hints.minimum;
  213. scaled_default = ( hints.default_value - offset ) / scale;
  214. }
  215. _scaled_signal = mixer->osc_endpoint->add_signal( scaled_path,
  216. OSC::Signal::Input,
  217. 0.0, 1.0, scaled_default,
  218. &Module::Port::osc_control_change_cv, this );
  219. _scaled_signal->connection_state_callback( handle_signal_connection_state_changed, this );
  220. _unscaled_signal = mixer->osc_endpoint->add_signal( unscaled_path,
  221. OSC::Signal::Input,
  222. hints.minimum, hints.maximum, hints.default_value,
  223. &Module::Port::osc_control_change_exact, this );
  224. }
  225. else
  226. {
  227. DMESSAGE( "Renaming OSC signals" );
  228. _scaled_signal->rename( scaled_path );
  229. _unscaled_signal->rename( unscaled_path );
  230. }
  231. free( unscaled_path );
  232. /* this was path, it's ok to free because it was malloc()'d in generate_osc_path */
  233. free( scaled_path );
  234. }
  235. }
  236. int
  237. Module::Port::osc_control_change_exact ( float v, void *user_data )
  238. {
  239. Module::Port *p = (Module::Port*)user_data;
  240. Fl::lock();
  241. float f = v;
  242. if ( p->hints.ranged )
  243. {
  244. if ( f > p->hints.maximum )
  245. f = p->hints.maximum;
  246. else if ( f < p->hints.minimum )
  247. f = p->hints.minimum;
  248. }
  249. p->control_value( f );
  250. Fl::unlock();
  251. // mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f );
  252. return 0;
  253. }
  254. int
  255. Module::Port::osc_control_change_cv ( float v, void *user_data )
  256. {
  257. Module::Port *p = (Module::Port*)user_data;
  258. float f = v;
  259. Fl::lock();
  260. // clamp value to control voltage range.
  261. if ( f > 1.0 )
  262. f = 1.0;
  263. else if ( f < 0.0 )
  264. f = 0.0;
  265. if ( p->hints.ranged )
  266. {
  267. // scale value to range.
  268. float scale = p->hints.maximum - p->hints.minimum;
  269. float offset = p->hints.minimum;
  270. f = ( f * scale ) + offset;
  271. }
  272. p->control_value( f );
  273. Fl::unlock();
  274. // mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f );
  275. return 0;
  276. }
  277. void
  278. Module::set ( Log_Entry &e )
  279. {
  280. for ( int i = 0; i < e.size(); ++i )
  281. {
  282. const char *s, *v;
  283. e.get( i, &s, &v );
  284. if ( ! strcmp( s, ":chain" ) )
  285. {
  286. /* This trickiness is because we may need to know the name of
  287. our chain before we actually get added to it. */
  288. int i;
  289. sscanf( v, "%X", &i );
  290. Chain *t = (Chain*)Loggable::find( i );
  291. assert( t );
  292. chain( t );
  293. }
  294. }
  295. for ( int i = 0; i < e.size(); ++i )
  296. {
  297. const char *s, *v;
  298. e.get( i, &s, &v );
  299. /* if ( ! strcmp( s, ":name" ) ) */
  300. /* label( v ); */
  301. if ( ! strcmp( s, ":parameter_values" ) )
  302. {
  303. set_parameters( v );
  304. }
  305. else if ( ! ( strcmp( s, ":is_default" ) ) )
  306. {
  307. is_default( atoi( v ) );
  308. }
  309. else if ( ! ( strcmp( s, ":active" ) ) )
  310. {
  311. bypass( ! atoi( v ) );
  312. }
  313. else if ( ! strcmp( s, ":chain" ) )
  314. {
  315. int i;
  316. sscanf( v, "%X", &i );
  317. Chain *t = (Chain*)Loggable::find( i );
  318. assert( t );
  319. t->add( this );
  320. }
  321. }
  322. }
  323. /* return a string serializing this module's parameter settings. The
  324. format is 1.0:2.0:... Where 1.0 is the value of the first control
  325. input, 2.0 is the value of the second control input etc.
  326. */
  327. char *
  328. Module::get_parameters ( void ) const
  329. {
  330. char *s = new char[1024];
  331. s[0] = 0;
  332. char *sp = s;
  333. if ( control_input.size() )
  334. {
  335. for ( unsigned int i = 0; i < control_input.size(); ++i )
  336. sp += snprintf( sp, 1024 - (sp - s),"%f:", control_input[i].control_value() );
  337. *(sp - 1) = '\0';
  338. }
  339. return s;
  340. }
  341. void
  342. Module::set_parameters ( const char *parameters )
  343. {
  344. char *s = strdup( parameters );
  345. char *start = s;
  346. unsigned int i = 0;
  347. for ( char *sp = s; ; ++sp )
  348. {
  349. if ( ':' == *sp || '\0' == *sp )
  350. {
  351. char was = *sp;
  352. *sp = '\0';
  353. DMESSAGE( start );
  354. if ( i < control_input.size() )
  355. control_input[i].control_value( atof( start ) );
  356. else
  357. {
  358. WARNING( "Module has no parameter at index %i", i );
  359. break;
  360. }
  361. i++;
  362. if ( '\0' == was )
  363. break;
  364. start = sp + 1;
  365. }
  366. }
  367. free( s );
  368. }
  369. void
  370. Module::draw_box ( void )
  371. {
  372. fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) );
  373. int tw, th, tx, ty;
  374. tw = w();
  375. th = h();
  376. ty = y();
  377. tx = x();
  378. fl_push_clip( tx, ty, tw, th );
  379. Fl_Color c = is_default() ? FL_BLACK : color();
  380. c = active() && ! bypass() ? c : fl_inactive( c );
  381. int spacing = w() / instances();
  382. for ( int i = instances(); i--; )
  383. {
  384. fl_draw_box( box(), tx + (spacing * i), ty, tw / instances(), th, Fl::belowmouse() == this ? fl_lighter( c ) : c );
  385. }
  386. if ( this == Fl::focus() )
  387. {
  388. fl_draw_box( FL_UP_FRAME, x(), y(), w(), h(), selection_color() );
  389. }
  390. if ( audio_input.size() && audio_output.size() )
  391. {
  392. /* maybe draw control indicators */
  393. if ( control_input.size() )
  394. {
  395. fl_draw_box( FL_ROUNDED_BOX, tx + 4, ty + 4, 5, 5, is_being_controlled() ? FL_YELLOW : fl_inactive( FL_YELLOW ) );
  396. fl_draw_box( FL_ROUNDED_BOX, tx + 4, ty + th - 8, 5, 5, is_being_controlled_osc() ? FL_YELLOW : fl_inactive( FL_YELLOW ) );
  397. }
  398. if ( control_output.size() )
  399. fl_draw_box( FL_ROUNDED_BOX, tx + tw - 8, ty + 4, 5, 5, is_controlling() ? FL_YELLOW : fl_inactive( FL_YELLOW ) );
  400. }
  401. Fl_Group::draw_children();
  402. fl_pop_clip();
  403. }
  404. void
  405. Module::draw_label ( void )
  406. {
  407. int tw, th, tx, ty;
  408. bbox( tx, ty, tw, th );
  409. const char *lp = label();
  410. int l = strlen( label() );
  411. Fl_Color c = FL_FOREGROUND_COLOR;
  412. if ( bypass() || ! active() )
  413. c = FL_BLACK;
  414. fl_color( fl_contrast( c, is_default() ? FL_BLACK : color() ) );
  415. char *s = NULL;
  416. if ( l > 10 )
  417. {
  418. s = new char[l];
  419. char *sp = s;
  420. for ( ; *lp; ++lp )
  421. switch ( *lp )
  422. {
  423. case 'i': case 'e': case 'o': case 'u': case 'a':
  424. break;
  425. default:
  426. *(sp++) = *lp;
  427. }
  428. *sp = '\0';
  429. }
  430. if ( l > 20 )
  431. fl_font( FL_HELVETICA, 10 );
  432. else
  433. fl_font( FL_HELVETICA, 14 );
  434. fl_draw( s ? s : lp, tx, ty, tw, th, (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP ) );
  435. if ( s )
  436. delete[] s;
  437. }
  438. void
  439. Module::insert_menu_cb ( const Fl_Menu_ *m )
  440. {
  441. if ( ! m->mvalue() || m->mvalue()->flags & FL_SUBMENU_POINTER || m->mvalue()->flags & FL_SUBMENU )
  442. return;
  443. void * v = m->mvalue()->user_data();
  444. if ( v )
  445. {
  446. unsigned long id = *((unsigned long *)v);
  447. Module *mod = NULL;
  448. switch ( id )
  449. {
  450. case 1:
  451. mod = new JACK_Module();
  452. break;
  453. case 2:
  454. mod = new Gain_Module();
  455. break;
  456. case 3:
  457. mod = new Meter_Module();
  458. break;
  459. case 4:
  460. mod = new Mono_Pan_Module();
  461. break;
  462. default:
  463. {
  464. Plugin_Module *m = new Plugin_Module();
  465. m->load( id );
  466. mod = m;
  467. }
  468. }
  469. if ( mod )
  470. {
  471. if ( !strcmp( mod->name(), "JACK" ) )
  472. {
  473. DMESSAGE( "Special casing JACK module" );
  474. JACK_Module *jm = (JACK_Module*)mod;
  475. jm->chain( chain() );
  476. jm->configure_inputs( ninputs() );
  477. jm->configure_outputs( ninputs() );
  478. }
  479. if ( ! chain()->insert( this, mod ) )
  480. {
  481. fl_alert( "Cannot insert this module at this point in the chain" );
  482. delete mod;
  483. return;
  484. }
  485. redraw();
  486. }
  487. }
  488. }
  489. void
  490. Module::insert_menu_cb ( Fl_Widget *w, void *v )
  491. {
  492. ((Module*)v)->insert_menu_cb( (Fl_Menu_*) w );
  493. }
  494. void
  495. Module::menu_cb ( const Fl_Menu_ *m )
  496. {
  497. char picked[256];
  498. if ( ! m->mvalue() || m->mvalue()->flags & FL_SUBMENU_POINTER || m->mvalue()->flags & FL_SUBMENU )
  499. return;
  500. strncpy( picked, m->mvalue()->label(), sizeof( picked ) );
  501. // m->item_pathname( picked, sizeof( picked ) );
  502. DMESSAGE( "%s", picked );
  503. Logger log( this );
  504. if ( ! strcmp( picked, "Edit Parameters" ) )
  505. command_open_parameter_editor();
  506. else if ( ! strcmp( picked, "Bypass" ) )
  507. bypass( ! ( m->mvalue()->flags & FL_MENU_VALUE ) );
  508. else if ( ! strcmp( picked, "Cut" ) )
  509. {
  510. copy();
  511. chain()->remove( this );
  512. Fl::delete_widget( this );
  513. }
  514. else if ( ! strcmp( picked, "Copy" ) )
  515. {
  516. copy();
  517. }
  518. else if ( ! strcmp( picked, "Paste" ) )
  519. {
  520. paste_before();
  521. }
  522. else if ( ! strcmp( picked, "Remove" ) )
  523. command_remove();
  524. }
  525. void
  526. Module::menu_cb ( Fl_Widget *w, void *v )
  527. {
  528. ((Module*)v)->menu_cb( (Fl_Menu_*) w );
  529. }
  530. /** build the context menu */
  531. Fl_Menu_Button &
  532. Module::menu ( void ) const
  533. {
  534. static Fl_Menu_Button m( 0, 0, 0, 0, "Module" );
  535. static Fl_Menu_Button *insert_menu = NULL;
  536. if ( ! insert_menu )
  537. {
  538. insert_menu = new Fl_Menu_Button( 0, 0, 0, 0 );
  539. insert_menu->add( "Gain", 0, 0, new unsigned long(2) );
  540. insert_menu->add( "Meter", 0, 0, new unsigned long(3) );
  541. insert_menu->add( "Mono Pan", 0, 0, new unsigned long(4) );
  542. Plugin_Module::add_plugins_to_menu( insert_menu );
  543. // menu_set_callback( insert_menu, &Module::insert_menu_cb, (void*)this );
  544. insert_menu->callback( &Module::insert_menu_cb, (void*)this );
  545. }
  546. m.clear();
  547. m.add( "Insert", 0, &Module::menu_cb, (void*)this, 0);
  548. m.add( "Insert", 0, &Module::menu_cb, const_cast< Fl_Menu_Item *>( insert_menu->menu() ), FL_SUBMENU_POINTER );
  549. m.add( "Edit Parameters", ' ', &Module::menu_cb, (void*)this, 0 );
  550. m.add( "Bypass", 'b', &Module::menu_cb, (void*)this, FL_MENU_TOGGLE | ( bypass() ? FL_MENU_VALUE : 0 ) );
  551. m.add( "Cut", FL_CTRL + 'x', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 );
  552. m.add( "Copy", FL_CTRL + 'c', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 );
  553. m.add( "Paste", FL_CTRL + 'v', &Module::menu_cb, (void*)this, _copied_module_empty ? 0 : FL_MENU_INACTIVE );
  554. m.add( "Remove", FL_Delete, &Module::menu_cb, (void*)this );
  555. // menu_set_callback( menu, &Module::menu_cb, (void*)this );
  556. m.callback( &Module::insert_menu_cb, (void*)this );
  557. return m;
  558. }
  559. void
  560. Module::handle_chain_name_changed ( )
  561. {
  562. // pass it along to our connected Controller_Modules, if any.
  563. for ( int i = 0; i < ncontrol_inputs(); ++i )
  564. {
  565. if ( control_input[i].connected() )
  566. control_input[i].connected_port()->module()->handle_chain_name_changed();
  567. control_input[i].update_osc_port();
  568. }
  569. }
  570. int
  571. Module::handle ( int m )
  572. {
  573. switch ( m )
  574. {
  575. case FL_KEYBOARD:
  576. {
  577. if ( Fl_Group::handle( m ) )
  578. return 1;
  579. if ( Fl::event_key() == FL_Menu )
  580. {
  581. menu_popup( &menu(), x(), y() );
  582. return 1;
  583. }
  584. else
  585. return menu().test_shortcut() != 0;
  586. }
  587. case FL_PUSH:
  588. {
  589. take_focus();
  590. if ( Fl_Group::handle( m ) )
  591. return 1;
  592. else if ( test_press( FL_BUTTON3 ) )
  593. {
  594. menu_popup( &menu() );
  595. return 1;
  596. }
  597. else if ( test_press( FL_BUTTON1 ) )
  598. {
  599. command_open_parameter_editor();
  600. return 1;
  601. }
  602. else if ( test_press( FL_BUTTON3 | FL_CTRL ) )
  603. {
  604. command_remove();
  605. return 1;
  606. }
  607. else if ( test_press( FL_BUTTON2 ) )
  608. {
  609. bypass( !bypass() );
  610. redraw();
  611. return 1;
  612. }
  613. return 0;
  614. }
  615. case FL_FOCUS:
  616. case FL_UNFOCUS:
  617. redraw();
  618. return 1;
  619. }
  620. return Fl_Group::handle( m );
  621. }
  622. /************/
  623. /* Commands */
  624. /************/
  625. void
  626. Module::command_open_parameter_editor ( void )
  627. {
  628. if ( _editor )
  629. {
  630. _editor->show();
  631. }
  632. else if ( ncontrol_inputs() )
  633. {
  634. DMESSAGE( "Opening module parameters for \"%s\"", label() );
  635. _editor = new Module_Parameter_Editor( this );
  636. _editor->show();
  637. }
  638. }
  639. void
  640. Module::command_activate ( void )
  641. {
  642. bypass( false );
  643. }
  644. void
  645. Module::command_deactivate ( void )
  646. {
  647. bypass( true );
  648. }
  649. void
  650. Module::command_remove ( void )
  651. {
  652. if ( is_default() )
  653. fl_alert( "Default modules may not be deleted." );
  654. else
  655. {
  656. chain()->remove( this );
  657. Fl::delete_widget( this );
  658. }
  659. }