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.

995 lines
25KB

  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 "Controller_Module.H"
  20. #include <stdio.h>
  21. #include <FL/Fl.H>
  22. #include <FL/Fl_Box.H>
  23. #include <FL/fl_ask.H>
  24. #include <FL/Fl_Counter.H>
  25. #include <FL/Fl_Menu_Item.H>
  26. #include <FL/Fl_Menu_Button.H>
  27. #include <FL/Fl_Menu_.H>
  28. #include <FL/Fl_Light_Button.H>
  29. #include <FL/fl_draw.H>
  30. #include "FL/Fl_DialX.H"
  31. #include "FL/Fl_Labelpad_Group.H"
  32. #include "FL/Fl_Value_SliderX.H"
  33. #include "Panner.H"
  34. #include "FL/test_press.H"
  35. #include "FL/menu_popup.H"
  36. #include "Chain.H"
  37. #include "OSC/Endpoint.H"
  38. // needed for mixer->endpoint
  39. #include "Mixer.H"
  40. #include "Spatialization_Console.H"
  41. #include "string_util.h"
  42. bool Controller_Module::learn_by_number = false;
  43. bool Controller_Module::_learn_mode = false;
  44. void
  45. Controller_Module::take_focus ( void )
  46. {
  47. bool v = visible_focus();
  48. if ( ! v )
  49. set_visible_focus();
  50. Fl_Widget::take_focus();
  51. if ( ! v )
  52. clear_visible_focus();
  53. }
  54. Controller_Module::Controller_Module ( bool is_default ) : Module( is_default, 50, 100, name() )
  55. {
  56. // label( "" );
  57. box( FL_NO_BOX );
  58. _horizontal = true;
  59. _pad = true;
  60. control = 0;
  61. control_value =0.0f;
  62. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  63. _mode = GUI;
  64. // mode( GUI );
  65. // mode( CV );
  66. // configure_inputs( 1 );
  67. end();
  68. // clear_visible_focus();
  69. log_create();
  70. }
  71. Controller_Module::~Controller_Module ( )
  72. {
  73. log_destroy();
  74. /* shutdown JACK port, if we have one */
  75. mode( GUI );
  76. // disconnect();
  77. }
  78. void
  79. Controller_Module::handle_chain_name_changed()
  80. {
  81. if ( type() == SPATIALIZATION )
  82. {
  83. if ( Mixer::spatialization_console )
  84. Mixer::spatialization_console->update();
  85. }
  86. // change_osc_path( generate_osc_path() );
  87. }
  88. void
  89. Controller_Module::handle_control_disconnect ( Module::Port *p )
  90. {
  91. if ( type() == SPATIALIZATION )
  92. {
  93. if ( Mixer::spatialization_console )
  94. Mixer::spatialization_console->update();
  95. }
  96. }
  97. void
  98. Controller_Module::disconnect ( void )
  99. {
  100. for ( unsigned int i = 0; i < control_output.size(); ++i )
  101. control_output[i].disconnect();
  102. }
  103. void
  104. Controller_Module::get ( Log_Entry &e ) const
  105. {
  106. Module::get( e );
  107. Port *p = control_output[0].connected_port();
  108. if ( !p )
  109. {
  110. e.add( ":module", "" );
  111. e.add( ":port", "" );
  112. e.add( ":mode", "" );
  113. }
  114. else
  115. {
  116. Module *m = p->module();
  117. e.add( ":module", m );
  118. e.add( ":port", m->control_input_port_index( p ) );
  119. e.add( ":mode", mode() );
  120. }
  121. }
  122. void
  123. Controller_Module::set ( Log_Entry &e )
  124. {
  125. Module::set( e );
  126. int port = -1;
  127. Module *module = NULL;
  128. for ( int i = 0; i < e.size(); ++i )
  129. {
  130. const char *s, *v;
  131. e.get( i, &s, &v );
  132. if ( ! strcmp( s, ":port" ) )
  133. {
  134. port = atoi( v );
  135. }
  136. else if ( ! strcmp( s, ":module" ) )
  137. {
  138. int i;
  139. sscanf( v, "%X", &i );
  140. Module *t = (Module*)Loggable::find( i );
  141. assert( t );
  142. module = t;
  143. }
  144. }
  145. if ( port >= 0 && module )
  146. {
  147. connect_to( &module->control_input[port] );
  148. module->chain()->add_control( this );
  149. label( module->control_input[port].name() );
  150. }
  151. for ( int i = 0; i < e.size(); ++i )
  152. {
  153. const char *s, *v;
  154. e.get( i, &s, &v );
  155. if ( ! strcmp( s, ":mode" ) )
  156. {
  157. mode( (Mode)atoi( v ) );
  158. }
  159. }
  160. }
  161. void
  162. Controller_Module::mode ( Mode m )
  163. {
  164. if( mode() != CV && m == CV )
  165. {
  166. if ( control_output[0].connected() )
  167. {
  168. chain()->client()->lock();
  169. Port *p = control_output[0].connected_port();
  170. char prefix[512];
  171. snprintf( prefix, sizeof(prefix), "CV-%s", p->name() );
  172. add_aux_cv_input( prefix, 0 );
  173. chain()->client()->unlock();
  174. }
  175. }
  176. else if ( mode() == CV && m != CV )
  177. {
  178. chain()->client()->lock();
  179. aux_audio_input.back().jack_port()->shutdown();
  180. delete aux_audio_input.back().jack_port();
  181. aux_audio_input.pop_back();
  182. chain()->client()->unlock();
  183. }
  184. _mode = m ;
  185. }
  186. bool
  187. Controller_Module::connect_spatializer_radius_to ( Module *m )
  188. {
  189. Port *radius_port = NULL;
  190. float radius_value = 0.0f;
  191. for ( unsigned int i = 0; i < m->control_input.size(); ++i )
  192. {
  193. Port *p = &m->control_input[i];
  194. if ( !strcasecmp( "Radius", p->name() ) )
  195. /* 90.0f == p->hints.maximum && */
  196. /* -90.0f == p->hints.minimum ) */
  197. {
  198. radius_port = p;
  199. radius_value = p->control_value();
  200. continue;
  201. }
  202. }
  203. if ( ! radius_port )
  204. return false;
  205. if ( control_output.size() != 3 )
  206. {
  207. control_output.clear();
  208. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  209. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  210. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  211. }
  212. control_output[2].connect_to( radius_port );
  213. maybe_create_panner();
  214. Panner *o = (Panner*)control;
  215. o->point( 0 )->radius( radius_value );
  216. if ( Mixer::spatialization_console )
  217. Mixer::spatialization_console->update();
  218. return true;
  219. }
  220. void
  221. Controller_Module::maybe_create_panner ( void )
  222. {
  223. if ( _type != SPATIALIZATION )
  224. {
  225. clear();
  226. Panner *o = new Panner( 0,0, 92,92 );
  227. o->box(FL_FLAT_BOX);
  228. o->color(FL_GRAY0);
  229. o->selection_color(FL_BACKGROUND_COLOR);
  230. o->labeltype(FL_NORMAL_LABEL);
  231. o->labelfont(0);
  232. o->labelcolor(FL_FOREGROUND_COLOR);
  233. o->align(FL_ALIGN_TOP);
  234. o->when(FL_WHEN_CHANGED);
  235. label( "Spatialization" );
  236. o->align(FL_ALIGN_TOP);
  237. o->labelsize( 10 );
  238. // o->callback( cb_panner_value_handle, new callback_data( this, azimuth_port_number, elevation_port_number ) );
  239. o->callback( cb_spatializer_handle, this );
  240. control = (Fl_Valuator*)o;
  241. if ( _pad )
  242. {
  243. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( o );
  244. flg->position( x(), y() );
  245. flg->set_visible_focus();
  246. size( flg->w(), flg->h() );
  247. add( flg );
  248. }
  249. else
  250. {
  251. // o->clear_visible_focus();
  252. o->resize( x(), y(), w(), h() );
  253. add( o );
  254. resizable( o );
  255. init_sizes();
  256. }
  257. _type = SPATIALIZATION;
  258. }
  259. }
  260. /** attempt to transform this controller into a spatialization
  261. controller and connect to the given module's spatialization
  262. control inputs. Returns true on success, false if given module
  263. does not accept spatialization inputs. */
  264. bool
  265. Controller_Module::connect_spatializer_to ( Module *m )
  266. {
  267. connect_spatializer_radius_to( m );
  268. /* these are for detecting related parameter groups which can be
  269. better represented by a single control */
  270. Port *azimuth_port = NULL;
  271. float azimuth_value = 0.0f;
  272. Port *elevation_port = NULL;
  273. float elevation_value = 0.0f;
  274. for ( unsigned int i = 0; i < m->control_input.size(); ++i )
  275. {
  276. Port *p = &m->control_input[i];
  277. if ( !strcasecmp( "Azimuth", p->name() ) &&
  278. 180.0f == p->hints.maximum &&
  279. -180.0f == p->hints.minimum )
  280. {
  281. azimuth_port = p;
  282. azimuth_value = p->control_value();
  283. continue;
  284. }
  285. else if ( !strcasecmp( "Elevation", p->name() ) &&
  286. 90.0f == p->hints.maximum &&
  287. -90.0f == p->hints.minimum )
  288. {
  289. elevation_port = p;
  290. elevation_value = p->control_value();
  291. continue;
  292. }
  293. }
  294. if ( ! ( azimuth_port && elevation_port ) )
  295. return false;
  296. if ( control_output.size() != 3 )
  297. {
  298. control_output.clear();
  299. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  300. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  301. add_port( Port( this, Port::OUTPUT, Port::CONTROL ) );
  302. }
  303. control_output[0].connect_to( azimuth_port );
  304. control_output[1].connect_to( elevation_port );
  305. maybe_create_panner();
  306. Panner *o = (Panner*)control;
  307. o->point( 0 )->azimuth( azimuth_value );
  308. o->point( 0 )->elevation( elevation_value );
  309. if ( Mixer::spatialization_console )
  310. Mixer::spatialization_console->update();
  311. return true;
  312. }
  313. void
  314. Controller_Module::connect_to ( Port *p )
  315. {
  316. control_output[0].connect_to( p );
  317. clear();
  318. Fl_Widget *w;
  319. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  320. {
  321. Fl_Button *o = new Fl_Button( 0, 0, 40, 40, p->name() );
  322. w = o;
  323. o->type( FL_TOGGLE_BUTTON );
  324. o->value( p->control_value() );
  325. o->selection_color( fl_color_average( FL_GRAY, FL_CYAN, 0.5 ) );
  326. _type = TOGGLE;
  327. /* FIXME: hack */
  328. control = (Fl_Valuator*)o;
  329. }
  330. else if ( p->hints.type == Module::Port::Hints::INTEGER )
  331. {
  332. Fl_Counter *o = new Fl_Counter(0, 0, 58, 24, p->name() );
  333. control = o;
  334. w = o;
  335. o->type(1);
  336. o->step(1);
  337. if ( p->hints.ranged )
  338. {
  339. o->minimum( p->hints.minimum );
  340. o->maximum( p->hints.maximum );
  341. }
  342. _type = SPINNER;
  343. o->value( p->control_value() );
  344. }
  345. // else if ( p->hints.type == Module::Port::Hints::LOGARITHMIC )
  346. else
  347. {
  348. Fl_Value_SliderX *o = new Fl_Value_SliderX(0, 0, 30, 250, p->name() );
  349. control = o;
  350. w = o;
  351. if ( ! _horizontal )
  352. {
  353. o->size( 30, 250 );
  354. o->type(FL_VERT_NICE_SLIDER);
  355. }
  356. else
  357. {
  358. o->size(250,20);
  359. o->type(FL_HOR_NICE_SLIDER);
  360. }
  361. // o->type(4);
  362. o->color( FL_BACKGROUND2_COLOR );
  363. o->selection_color( fl_color_average( FL_GRAY, FL_CYAN, 0.5 ) );
  364. o->minimum(1.5);
  365. o->maximum(0);
  366. o->value(1);
  367. // o->textsize(9);
  368. if ( p->hints.ranged )
  369. {
  370. if ( ! _horizontal )
  371. {
  372. o->minimum( p->hints.maximum );
  373. o->maximum( p->hints.minimum );
  374. }
  375. else
  376. {
  377. o->minimum( p->hints.minimum );
  378. o->maximum( p->hints.maximum );
  379. }
  380. }
  381. o->precision(2);
  382. o->value( p->control_value() );
  383. _type = SLIDER;
  384. }
  385. /* else */
  386. /* { */
  387. /* { Fl_DialX *o = new Fl_DialX( 0, 0, 50, 50, p->name() ); */
  388. /* w = o; */
  389. /* control = o; */
  390. /* if ( p->hints.ranged ) */
  391. /* { */
  392. /* DMESSAGE( "Min: %f, max: %f", p->hints.minimum, p->hints.maximum ); */
  393. /* o->minimum( p->hints.minimum ); */
  394. /* o->maximum( p->hints.maximum ); */
  395. /* } */
  396. /* o->color( fl_darker( FL_GRAY ) ); */
  397. /* o->selection_color( FL_WHITE ); */
  398. /* o->value( p->control_value() ); */
  399. /* } */
  400. /* _type = KNOB; */
  401. /* } */
  402. control_value = p->control_value();
  403. w->clear_visible_focus();
  404. w->align(FL_ALIGN_TOP);
  405. w->labelsize( 10 );
  406. w->callback( cb_handle, this );
  407. if ( _pad )
  408. {
  409. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( w );
  410. flg->set_visible_focus();
  411. size( flg->w(), flg->h() );
  412. flg->position( x(), y() );
  413. add( flg );
  414. resizable(flg);
  415. // init_sizes();
  416. }
  417. else
  418. {
  419. /* HACK: hide label */
  420. if ( _type == TOGGLE )
  421. {
  422. w->align( FL_ALIGN_INSIDE );
  423. }
  424. else
  425. {
  426. w->labeltype( FL_NO_LABEL );
  427. }
  428. w->resize( x(), y(), this->w(), h() );
  429. add( w );
  430. resizable( w );
  431. init_sizes();
  432. }
  433. }
  434. void
  435. Controller_Module::update ( void )
  436. {
  437. /* we only need this in CV (JACK) mode, because with other forms
  438. * of control the change happens in the GUI thread and we know it */
  439. if ( mode() != CV )
  440. return;
  441. /* ensures that port value change callbacks are run */
  442. if ( control && control_output.size() > 0 && control_output[0].connected() )
  443. control_output[0].connected_port()->control_value( control_value );
  444. }
  445. void
  446. Controller_Module::cb_handle ( Fl_Widget *w, void *v )
  447. {
  448. ((Controller_Module*)v)->cb_handle( w );
  449. }
  450. void
  451. Controller_Module::cb_handle ( Fl_Widget *w )
  452. {
  453. if ( type() == TOGGLE )
  454. {
  455. control_value = ((Fl_Button*)w)->value();
  456. }
  457. else
  458. control_value = ((Fl_Valuator*)w)->value();
  459. if ( control_output[0].connected() )
  460. control_output[0].connected_port()->control_value( control_value );
  461. }
  462. void
  463. Controller_Module::cb_spatializer_handle ( Fl_Widget *w, void *v )
  464. {
  465. ((Controller_Module*)v)->cb_spatializer_handle( w );
  466. }
  467. void
  468. Controller_Module::cb_spatializer_handle ( Fl_Widget *w )
  469. {
  470. Panner *pan = (Panner*)w;
  471. if ( control_output[0].connected() &&
  472. control_output[1].connected() )
  473. {
  474. control_output[0].connected_port()->control_value( pan->point( 0 )->azimuth() );
  475. control_output[1].connected_port()->control_value( pan->point( 0 )->elevation() );
  476. }
  477. if ( control_output[2].connected() )
  478. {
  479. control_output[2].connected_port()->control_value( pan->point( 0 )->radius() );
  480. }
  481. }
  482. void
  483. Controller_Module::menu_cb ( Fl_Widget *w, void *v )
  484. {
  485. ((Controller_Module*)v)->menu_cb( (Fl_Menu_*) w );
  486. }
  487. void
  488. Controller_Module::menu_cb ( const Fl_Menu_ *m )
  489. {
  490. char picked[256];
  491. m->item_pathname( picked, sizeof( picked ) );
  492. Logger log( this );
  493. if ( ! strcmp( picked, "Mode/GUI + OSC" ) )
  494. mode( GUI );
  495. else if ( ! strcmp( picked, "Mode/Control Voltage (JACK)" ) )
  496. mode( CV );
  497. else if ( ! strcmp( picked, "/Remove" ) )
  498. command_remove();
  499. else if ( ! strncmp( picked, "Connect To/", strlen( "Connect To/" ) ) )
  500. {
  501. char *peer_name = index( picked, '/' ) + 1;
  502. *index( peer_name, '/' ) = 0;
  503. // OSC::Signal s = (OSC::Signal*)m->mvalue()->user_data();
  504. const char *path = ((OSC::Signal*)m->mvalue()->user_data())->path();
  505. /* if ( ! _osc_output()->is_connected_to( ((OSC::Signal*)m->mvalue()->user_data()) ) ) */
  506. /* { */
  507. /* _persistent_osc_connections.push_back( strdup(path) ); */
  508. Port *p = control_output[0].connected_port();
  509. if ( learn_by_number )
  510. mixer->osc_endpoint->add_translation( path, p->osc_number_path());
  511. else
  512. mixer->osc_endpoint->add_translation( path, p->osc_path() );
  513. }
  514. else if ( ! strncmp( picked, "Disconnect From/", strlen( "Disconnect From/" ) ) )
  515. {
  516. /* char *peer_name = index( picked, '/' ) + 1; */
  517. /* *index( peer_name, '/' ) = 0; */
  518. // OSC::Signal s = (OSC::Signal*)m->mvalue()->user_data();
  519. const char *path = (const char*)m->mvalue()->user_data();
  520. /* if ( ! _osc_output()->is_connected_to( ((OSC::Signal*)m->mvalue()->user_data()) ) ) */
  521. /* { */
  522. /* _persistent_osc_connections.push_back( strdup(path) ); */
  523. // Port *p = control_output[0].connected_port();
  524. mixer->osc_endpoint->del_translation( path );
  525. /* if ( learn_by_number ) */
  526. /* { */
  527. /* char *our_path = p->osc_number_path(); */
  528. /* mixer->osc_endpoint->add_translation( path, our_path ); */
  529. /* free(our_path); */
  530. /* } */
  531. /* else */
  532. /* mixer->osc_endpoint->add_translation( path, p->osc_path() ); */
  533. }
  534. /* } */
  535. /* else */
  536. /* { */
  537. /* /\* timeline->osc->disconnect_signal( _osc_output(), path ); *\/ */
  538. /* /\* for ( std::list<char*>::iterator i = _persistent_osc_connections.begin(); *\/ */
  539. /* /\* i != _persistent_osc_connections.end(); *\/ */
  540. /* /\* ++i ) *\/ */
  541. /* /\* { *\/ */
  542. /* /\* if ( !strcmp( *i, path ) ) *\/ */
  543. /* /\* { *\/ */
  544. /* /\* free( *i ); *\/ */
  545. /* /\* i = _persistent_osc_connections.erase( i ); *\/ */
  546. /* /\* break; *\/ */
  547. /* /\* } *\/ */
  548. /* /\* } *\/ */
  549. /* //free( path ); */
  550. /* } */
  551. }
  552. static Fl_Menu_Button *peer_menu;
  553. static const char *peer_prefix;
  554. void
  555. Controller_Module::peer_callback( OSC::Signal *sig, OSC::Signal::State state, void *v )
  556. {
  557. char *s;
  558. DMESSAGE( "Paramter limits: %f %f", sig->parameter_limits().min, sig->parameter_limits().max );
  559. /* only show outputs */
  560. if ( sig->direction() != OSC::Signal::Output )
  561. return;
  562. /* only list CV signals for now */
  563. if ( ! ( sig->parameter_limits().min == 0.0 &&
  564. sig->parameter_limits().max == 1.0 ) )
  565. return;
  566. if ( ! v )
  567. {
  568. /* if( state == OSC::Signal::Created ) */
  569. /* timeline->connect_osc(); */
  570. /* else */
  571. /* timeline->update_osc_connection_state(); */
  572. }
  573. else
  574. {
  575. /* building menu */
  576. // const char *name = sig->peer_name();
  577. assert( sig->path() );
  578. char *path = strdup( sig->path() );
  579. unescape_url( path );
  580. asprintf( &s, "%s/%s", peer_prefix, path );
  581. peer_menu->add( s, 0, NULL, (void*)( sig ), 0 );
  582. /* FL_MENU_TOGGLE | */
  583. /* ( ((Controller_Module*)v)->_osc_output()->is_connected_to( sig ) ? FL_MENU_VALUE : 0 ) ); */
  584. free( path );
  585. free( s );
  586. }
  587. }
  588. void
  589. Controller_Module::add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix )
  590. {
  591. mixer->osc_endpoint->peer_signal_notification_callback( &Controller_Module::peer_callback, NULL );
  592. peer_menu = m;
  593. peer_prefix = prefix;
  594. mixer->osc_endpoint->list_peer_signals( this );
  595. }
  596. void
  597. Controller_Module::add_osc_connections_to_menu ( Fl_Menu_Button *m, const char *prefix )
  598. {
  599. /* peer_menu = m; */
  600. const char *peer_prefix = prefix;
  601. // mixer->osc_endpoint->list_peer_signals( this );
  602. Port *p = control_output[0].connected_port();
  603. const char *number_path = p->osc_number_path();
  604. const char *name_path = p->osc_path();
  605. const char *paths[] = { number_path,name_path,NULL };
  606. for ( const char **cpath = paths; *cpath; cpath++ )
  607. {
  608. const char ** conn = mixer->osc_endpoint->get_connections( *cpath );
  609. if ( conn )
  610. {
  611. for ( const char **s = conn; *s; s++ )
  612. {
  613. /* building menu */
  614. char *path = strdup( *s );
  615. unescape_url( path );
  616. char *ns;
  617. asprintf( &ns, "%s/%s", peer_prefix, path );
  618. peer_menu->add( ns, 0, NULL, const_cast<char*>(*s), 0 );
  619. free( path );
  620. // free(*s);
  621. }
  622. free( conn );
  623. }
  624. }
  625. }
  626. /** build the context menu for this control */
  627. Fl_Menu_Button &
  628. Controller_Module::menu ( void )
  629. {
  630. static Fl_Menu_Button m( 0, 0, 0, 0, "Controller" );
  631. m.clear();
  632. if ( mode() == GUI )
  633. {
  634. add_osc_peers_to_menu( &m, "Connect To" );
  635. add_osc_connections_to_menu( &m, "Disconnect From" );
  636. }
  637. m.add( "Mode/GUI + OSC", 0, 0, 0, FL_MENU_RADIO | ( mode() == GUI ? FL_MENU_VALUE : 0 ));
  638. m.add( "Mode/Control Voltage (JACK)", 0, 0, 0, FL_MENU_RADIO | ( mode() == CV ? FL_MENU_VALUE : 0 ));
  639. m.add( "Remove", 0, 0, 0, is_default() ? FL_MENU_INACTIVE : 0 );
  640. // menu_set_callback( m.items(), &Controller_Module::menu_cb, (void*)this );
  641. m.callback( &Controller_Module::menu_cb, (void*)this );
  642. // m.copy( items, (void*)this );
  643. return m;
  644. }
  645. void
  646. Controller_Module::draw ( void )
  647. {
  648. Fl_Group::draw();
  649. draw_box(x(),y(),w(),h());
  650. if ( learn_mode() )
  651. {
  652. fl_rectf( x(),y(),w(),h(), fl_color_add_alpha( FL_MAGENTA, 50 ) );
  653. }
  654. }
  655. int
  656. Controller_Module::handle ( int m )
  657. {
  658. switch ( m )
  659. {
  660. case FL_PUSH:
  661. {
  662. if ( learn_mode() )
  663. {
  664. tooltip( "Now learning control. Move the desired control on your controller" );
  665. //connect_to( &module->control_input[port] );
  666. Port *p = control_output[0].connected_port();
  667. if ( p )
  668. {
  669. const char * path = learn_by_number ? p->osc_number_path() : p->osc_path();
  670. DMESSAGE( "Will learn %s", path );
  671. mixer->osc_endpoint->learn( path );
  672. }
  673. return 1;
  674. }
  675. if ( Fl::event_button3() )
  676. {
  677. /* context menu */
  678. /* if ( type() != SPATIALIZATION ) */
  679. menu_popup( &menu() );
  680. return 1;
  681. }
  682. else
  683. return Fl_Group::handle( m );
  684. }
  685. }
  686. return Fl_Group::handle( m );
  687. }
  688. void
  689. Controller_Module::handle_control_changed ( Port *p )
  690. {
  691. /* ignore changes initiated while mouse is over widget */
  692. if ( type() == SPATIALIZATION )
  693. {
  694. if ( Mixer::spatialization_console )
  695. Mixer::spatialization_console->handle_control_changed( this );
  696. }
  697. if ( contains( Fl::pushed() ) )
  698. return;
  699. if ( p )
  700. control_value = p->control_value();
  701. if ( control->value() == control_value )
  702. return;
  703. /* if ( control->value() != control_value ) */
  704. /* { */
  705. /* redraw(); */
  706. /* } */
  707. if ( type() == SPATIALIZATION )
  708. {
  709. Panner *pan = (Panner*)control;
  710. pan->point( 0 )->azimuth( control_output[0].control_value() );
  711. pan->point( 0 )->elevation( control_output[1].control_value() );
  712. if ( control_output[2].connected() )
  713. {
  714. // Port *pp = control_output[2].connected_port();
  715. float v = control_output[2].control_value();
  716. // float s = pp->hints.maximum - pp->hints.minimum;
  717. pan->point( 0 )->radius( v );
  718. }
  719. if ( visible_r() )
  720. pan->redraw();
  721. }
  722. else
  723. {
  724. if ( type() == TOGGLE )
  725. ((Fl_Button*)control)->value(control_value);
  726. else
  727. control->value(control_value);
  728. }
  729. }
  730. void
  731. Controller_Module::command_remove ( void )
  732. {
  733. if ( is_default() )
  734. fl_alert( "Default modules may not be deleted." );
  735. else
  736. {
  737. chain()->remove( this );
  738. Fl::delete_widget( this );
  739. }
  740. }
  741. /**********/
  742. /* Client */
  743. /**********/
  744. void
  745. Controller_Module::process ( nframes_t nframes )
  746. {
  747. THREAD_ASSERT( RT );
  748. if ( type() == SPATIALIZATION )
  749. {
  750. return;
  751. }
  752. if ( control_output[0].connected() )
  753. {
  754. float f = control_value;
  755. if ( mode() == CV )
  756. {
  757. f = *((float*)aux_audio_input[0].jack_port()->buffer( nframes ));
  758. const Port *p = control_output[0].connected_port();
  759. if (p->hints.ranged )
  760. {
  761. // scale value to range.
  762. // we assume that CV values are between 0 and 1
  763. float scale = p->hints.maximum - p->hints.minimum;
  764. float offset = p->hints.minimum;
  765. f = ( f * scale ) + offset;
  766. }
  767. }
  768. // else
  769. // f = *((float*)control_output[0].buffer());
  770. *((float*)control_output[0].buffer()) = f;
  771. control_value = f;
  772. }
  773. }