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.

672 lines
19KB

  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 <FL/Fl.H>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include <FL/fl_draw.H>
  24. #include <FL/Fl_Pack.H>
  25. #include <FL/Fl_Box.H>
  26. #include <FL/Fl_Menu_Button.H>
  27. #include <FL/Fl_Counter.H>
  28. #include "FL/Fl_Flowpack.H"
  29. #include "FL/Fl_Labelpad_Group.H"
  30. #include "FL/Fl_Value_SliderX.H"
  31. #include "FL/Fl_DialX.H"
  32. #include <FL/Fl_Scroll.H>
  33. #include "Module.H"
  34. #include "Module_Parameter_Editor.H"
  35. #include "Controller_Module.H"
  36. #include "Chain.H"
  37. #include "Panner.H"
  38. #include <FL/fl_ask.H>
  39. #include "debug.h"
  40. #include <FL/Fl_Menu_Button.H>
  41. #include "FL/test_press.H"
  42. #include "FL/menu_popup.H"
  43. #include "SpectrumView.H"
  44. #include "string.h"
  45. bool
  46. Module_Parameter_Editor::is_probably_eq ( void )
  47. {
  48. const char *name = _module->label();
  49. return strcasestr( name, "eq" ) ||
  50. strcasestr( name, "filter" ) ||
  51. strcasestr( name, "parametric" ) ||
  52. strcasestr( name, "band" );
  53. }
  54. Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_Window( 900,240)
  55. {
  56. _module = module;
  57. _resized = false;
  58. _min_width = 100;
  59. char lab[256];
  60. if ( strcmp( module->name(), module->label() ) )
  61. {
  62. snprintf( lab, sizeof( lab ), "%s : %s", module->name(), module->label() );
  63. }
  64. else
  65. strcpy( lab, module->label() );
  66. char title[512];
  67. snprintf( title, sizeof( title ), "%s - %s - %s", "Mixer", module->chain()->name(), lab );
  68. copy_label( title );
  69. // fl_font( FL_HELVETICA, 14 );
  70. _min_width = 30 + fl_width( module->label() );
  71. { Fl_Group *o = new Fl_Group( 0, 0, w(), 25 );
  72. o->label( module->label() );
  73. o->labelfont( 2 );
  74. o->labeltype( FL_SHADOW_LABEL );
  75. o->labelsize( 14 );
  76. o->align( FL_ALIGN_TOP | FL_ALIGN_RIGHT | FL_ALIGN_INSIDE );
  77. { Fl_Menu_Button *o = mode_choice = new Fl_Menu_Button( 0, 0, 25, 25 );
  78. o->add( "Knobs" );
  79. o->add( "Horizontal Sliders" );
  80. o->add( "Vertical Sliders" );
  81. o->label( NULL );
  82. o->value( 1 );
  83. o->when( FL_WHEN_CHANGED );
  84. o->callback( cb_mode_handle, this );
  85. }
  86. o->resizable(0);
  87. o->end();
  88. }
  89. { Fl_Scroll *o = control_scroll = new Fl_Scroll( 0, 40, w(), h() - 40 );
  90. { Fl_Group *o = new Fl_Group( 0, 40, w(), h() - 40 );
  91. { Fl_Flowpack *o = control_pack = new Fl_Flowpack( 50, 40, w() - 100, h() - 40 );
  92. o->type( FL_HORIZONTAL );
  93. o->flow( true );
  94. o->vspacing( 5 );
  95. o->hspacing( 5 );
  96. o->end();
  97. }
  98. o->resizable( 0 );
  99. o->end();
  100. }
  101. o->end();
  102. }
  103. resizable(control_scroll);
  104. end();
  105. make_controls();
  106. }
  107. Module_Parameter_Editor::~Module_Parameter_Editor ( )
  108. {
  109. }
  110. void
  111. Module_Parameter_Editor::update_spectrum ( void )
  112. {
  113. nframes_t sample_rate = _module->sample_rate();
  114. SpectrumView *o = spectrum_view;
  115. o->sample_rate( sample_rate );
  116. nframes_t nframes = sample_rate / 10;
  117. float *buf = new float[nframes];
  118. memset( buf, 0, sizeof(float) * nframes );
  119. buf[0] = 1;
  120. bool show = false;
  121. if ( ! _module->get_impulse_response( buf, nframes ) )
  122. show = is_probably_eq();
  123. else
  124. show = true;
  125. o->data( buf, nframes );
  126. if ( show && ! o->parent()->visible() )
  127. {
  128. o->parent()->show();
  129. update_control_visibility();
  130. }
  131. o->redraw();
  132. }
  133. void
  134. Module_Parameter_Editor::make_controls ( void )
  135. {
  136. Module *module = _module;
  137. control_pack->clear();
  138. { SpectrumView *o = spectrum_view = new SpectrumView( 25, 40, 300, 240, "Spectrum" );
  139. o->labelsize(9);
  140. o->align(FL_ALIGN_TOP);
  141. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( (Fl_Widget*)o );
  142. flg->hide();
  143. control_pack->add( flg );
  144. }
  145. controls_by_port.clear();
  146. /* these are for detecting related parameter groups which can be
  147. better represented by a single control */
  148. azimuth_port_number = -1;
  149. float azimuth_value = 0.0f;
  150. elevation_port_number = -1;
  151. float elevation_value = 0.0f;
  152. radius_port_number = -1;
  153. float radius_value = 0.0f;
  154. Fl_Color fc = fl_color_add_alpha( FL_CYAN, 200 );
  155. Fl_Color bc = FL_BACKGROUND2_COLOR;
  156. controls_by_port.resize( module->control_input.size() );
  157. if ( mode_choice->value() == 1 )
  158. {
  159. control_pack->vspacing( 1 );
  160. control_pack->hspacing( 10 );
  161. control_pack->flow(true);
  162. control_pack->flowdown(true);
  163. control_pack->type( FL_HORIZONTAL );
  164. control_pack->size( 900, 240 );
  165. }
  166. else if ( mode_choice->value() == 2 )
  167. {
  168. control_pack->vspacing( 10 );
  169. control_pack->hspacing( 10 );
  170. control_pack->flow(true);
  171. control_pack->flowdown(false);
  172. control_pack->type( FL_HORIZONTAL );
  173. control_pack->size( 900, 250 );
  174. }
  175. else if ( mode_choice->value() == 0 )
  176. {
  177. control_pack->vspacing( 10 );
  178. control_pack->hspacing( 10 );
  179. control_pack->flow(true);
  180. control_pack->flowdown(true);
  181. control_pack->type( FL_HORIZONTAL );
  182. control_pack->size( 700, 50 );
  183. }
  184. for ( unsigned int i = 0; i < module->control_input.size(); ++i )
  185. {
  186. Fl_Widget *w;
  187. Module::Port *p = &module->control_input[i];
  188. /* if ( !p->hints.visible ) */
  189. /* continue; */
  190. if ( !strcasecmp( "Azimuth", p->name() ) &&
  191. 180.0f == p->hints.maximum &&
  192. -180.0f == p->hints.minimum )
  193. {
  194. azimuth_port_number = i;
  195. azimuth_value = p->control_value();
  196. continue;
  197. }
  198. else if ( !strcasecmp( "Elevation", p->name() ) &&
  199. 90.0f == p->hints.maximum &&
  200. -90.0f == p->hints.minimum )
  201. {
  202. elevation_port_number = i;
  203. elevation_value = p->control_value();
  204. continue;
  205. }
  206. else if ( !strcasecmp( "Radius", p->name() ) )
  207. {
  208. radius_port_number = i;
  209. radius_value = p->control_value();
  210. continue;
  211. }
  212. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  213. {
  214. Fl_Button *o = new Fl_Button( 0, 0, 24, 24, p->name() );
  215. w = o;
  216. o->selection_color( fc );
  217. o->type( FL_TOGGLE_BUTTON );
  218. o->value( p->control_value() );
  219. o->align(FL_ALIGN_TOP);
  220. }
  221. else if ( p->hints.type == Module::Port::Hints::INTEGER )
  222. {
  223. Fl_Counter *o = new Fl_Counter(0, 0, 58, 24, p->name() );
  224. w = o;
  225. o->type(1);
  226. o->step(1);
  227. o->align(FL_ALIGN_TOP);
  228. if ( p->hints.ranged )
  229. {
  230. o->minimum( p->hints.minimum );
  231. o->maximum( p->hints.maximum );
  232. }
  233. o->value( p->control_value() );
  234. }
  235. else
  236. {
  237. if ( mode_choice->value() == 0 )
  238. {
  239. Fl_DialX *o = new Fl_DialX( 0, 0, 60, 60, p->name() );
  240. w = o;
  241. if ( p->hints.ranged )
  242. {
  243. DMESSAGE( "Min: %f, max: %f", p->hints.minimum, p->hints.maximum );
  244. o->minimum( p->hints.minimum );
  245. o->maximum( p->hints.maximum );
  246. }
  247. o->color( bc );
  248. o->selection_color( fc );
  249. o->value( p->control_value() );
  250. o->align(FL_ALIGN_TOP);
  251. o->box( FL_DOWN_BOX );
  252. /* a couple of plugins have ridiculously small units */
  253. float r = fabs( p->hints.maximum - p->hints.minimum );
  254. if ( r <= 0.01f )
  255. o->precision( 4 );
  256. else if ( r <= 0.1f )
  257. o->precision( 3 );
  258. else if ( r <= 100.0f )
  259. o->precision( 2 );
  260. else if ( r <= 5000.0f )
  261. o->precision( 1 );
  262. /* else if ( r <= 10000.0f ) */
  263. /* o->precision( 1 ); */
  264. else
  265. o->precision( 0 );
  266. }
  267. else
  268. {
  269. Fl_Value_SliderX *o = new Fl_Value_SliderX( 0, 0, 120, 24, p->name() );
  270. w = o;
  271. if ( mode_choice->value() == 1 )
  272. {
  273. o->type( FL_HORIZONTAL );
  274. o->align( FL_ALIGN_RIGHT );
  275. o->size( 200, 24 );
  276. if ( p->hints.ranged )
  277. {
  278. o->minimum( p->hints.minimum );
  279. o->maximum( p->hints.maximum );
  280. }
  281. }
  282. else
  283. {
  284. o->type( FL_VERTICAL );
  285. o->align(FL_ALIGN_TOP);
  286. o->size( 24, 200 );
  287. /* have to reverse the meaning of these to get the
  288. * orientation of the slider right */
  289. o->maximum( p->hints.minimum );
  290. o->minimum( p->hints.maximum );
  291. }
  292. if ( p->hints.type & Module::Port::Hints::LOGARITHMIC )
  293. o->log(true);
  294. o->precision( 2 );
  295. /* a couple of plugins have ridiculously small units */
  296. float r = fabs( p->hints.maximum - p->hints.minimum );
  297. if ( r <= 0.01f )
  298. o->precision( 4 );
  299. else if ( r <= 0.1f )
  300. o->precision( 3 );
  301. else if ( r <= 100.0f )
  302. o->precision( 2 );
  303. else if ( r <= 5000.0f )
  304. o->precision( 1 );
  305. /* else if ( r <= 10000.0f ) */
  306. /* o->precision( 1 ); */
  307. else
  308. o->precision( 0 );
  309. o->textsize( 8 );
  310. // o->box( FL_NO_BOX );
  311. o->slider( FL_UP_BOX );
  312. o->color( bc );
  313. o->selection_color( fc );
  314. o->value( p->control_value() );
  315. }
  316. }
  317. // w->align(FL_ALIGN_TOP);
  318. w->labelsize( 10 );
  319. controls_by_port[i] = w;
  320. w->copy_tooltip( p->osc_path() );
  321. _callback_data.push_back( callback_data( this, i ) );
  322. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  323. w->callback( cb_button_handle, &_callback_data.back() );
  324. else
  325. w->callback( cb_value_handle, &_callback_data.back() );
  326. {
  327. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( w );
  328. flg->set_visible_focus();
  329. control_pack->add( flg );
  330. }
  331. }
  332. if ( azimuth_port_number >= 0 && elevation_port_number >= 0 )
  333. {
  334. Panner *o = new Panner( 0,0, 502,502 );
  335. o->box(FL_FLAT_BOX);
  336. o->color(FL_GRAY0);
  337. o->selection_color(FL_BACKGROUND_COLOR);
  338. o->labeltype(FL_NORMAL_LABEL);
  339. o->labelfont(0);
  340. o->labelcolor(FL_FOREGROUND_COLOR);
  341. o->align(FL_ALIGN_TOP);
  342. o->when(FL_WHEN_CHANGED);
  343. o->label( "Spatialization" );
  344. o->labelsize( 10 );
  345. _callback_data.push_back( callback_data( this, azimuth_port_number, elevation_port_number, radius_port_number ) );
  346. o->callback( cb_panner_value_handle, &_callback_data.back() );
  347. o->point( 0 )->azimuth( azimuth_value );
  348. o->point( 0 )->elevation( elevation_value );
  349. if ( radius_port_number >= 0 )
  350. {
  351. o->point( 0 )->radius_enabled = true;
  352. o->point( 0 )->radius( radius_value );
  353. }
  354. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( o );
  355. flg->resizable(o);
  356. control_pack->add( flg );
  357. controls_by_port[azimuth_port_number] = o;
  358. controls_by_port[elevation_port_number] = o;
  359. if ( radius_port_number >= 0 )
  360. controls_by_port[radius_port_number] = o;
  361. }
  362. update_spectrum();
  363. update_control_visibility();
  364. }
  365. void
  366. Module_Parameter_Editor::update_control_visibility ( void )
  367. {
  368. for ( unsigned int i = 0; i < _module->control_input.size(); ++i )
  369. {
  370. const Module::Port *p = &_module->control_input[i];
  371. if ( p->hints.visible )
  372. controls_by_port[i]->parent()->show();
  373. else
  374. controls_by_port[i]->parent()->hide();
  375. }
  376. control_pack->dolayout();
  377. int width = control_pack->w() + 100;
  378. int height = control_pack->h() + 60;
  379. if ( width < _min_width )
  380. width = _min_width;
  381. control_pack->parent()->size( control_pack->w() + 100, control_pack->h() );
  382. control_scroll->scroll_to(0, 0 );
  383. size( width, height );
  384. size_range( width, height, width, height );
  385. }
  386. void
  387. Module_Parameter_Editor::cb_value_handle ( Fl_Widget *w, void *v )
  388. {
  389. callback_data *cd = (callback_data*)v;
  390. cd->base_widget->set_value( cd->port_number[0], ((Fl_Valuator*)w)->value() );
  391. }
  392. void
  393. Module_Parameter_Editor::cb_button_handle ( Fl_Widget *w, void *v )
  394. {
  395. callback_data *cd = (callback_data*)v;
  396. cd->base_widget->set_value( cd->port_number[0], ((Fl_Button*)w)->value() );
  397. }
  398. void
  399. Module_Parameter_Editor::cb_panner_value_handle ( Fl_Widget *w, void *v )
  400. {
  401. callback_data *cd = (callback_data*)v;
  402. cd->base_widget->set_value( cd->port_number[0], ((Panner*)w)->point( 0 )->azimuth() );
  403. cd->base_widget->set_value( cd->port_number[1], ((Panner*)w)->point( 0 )->elevation() );
  404. cd->base_widget->set_value( cd->port_number[2], ((Panner*)w)->point( 0 )->radius() );
  405. }
  406. void
  407. Module_Parameter_Editor::cb_mode_handle ( Fl_Widget *, void *v )
  408. {
  409. ((Module_Parameter_Editor*)v)->make_controls();
  410. }
  411. void
  412. Module_Parameter_Editor::bind_control ( int i )
  413. {
  414. Module::Port *p = &_module->control_input[i];
  415. if ( p->connected() )
  416. /* can only bind once */
  417. return;
  418. Controller_Module *o = new Controller_Module();
  419. o->label( p->name() );
  420. o->chain( _module->chain() );
  421. o->horizontal( true );
  422. o->connect_to( p );
  423. _module->chain()->add_control( o );
  424. _module->redraw();
  425. }
  426. /* Display changes initiated via automation or from other parts of the GUI */
  427. void
  428. Module_Parameter_Editor::handle_control_changed ( Module::Port *p )
  429. {
  430. int i = _module->control_input_port_index( p );
  431. Fl_Widget *w = controls_by_port[i];
  432. if ( i == azimuth_port_number ||
  433. i == elevation_port_number ||
  434. i == radius_port_number )
  435. {
  436. Panner *_panner = (Panner*)w;
  437. if ( i == azimuth_port_number )
  438. _panner->point(0)->azimuth( p->control_value() );
  439. else if ( i == elevation_port_number )
  440. _panner->point(0)->elevation( p->control_value() );
  441. else if ( i == radius_port_number )
  442. _panner->point(0)->radius( p->control_value() );
  443. _panner->redraw();
  444. return;
  445. }
  446. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  447. {
  448. Fl_Button *v = (Fl_Button*)w;
  449. v->value( p->control_value() );
  450. }
  451. else
  452. {
  453. Fl_Valuator *v = (Fl_Valuator*)w;
  454. v->value( p->control_value() );
  455. }
  456. update_spectrum();
  457. }
  458. void
  459. Module_Parameter_Editor::reload ( void )
  460. {
  461. // make_controls();
  462. update_control_visibility();
  463. redraw();
  464. }
  465. void
  466. Module_Parameter_Editor::set_value (int i, float value )
  467. {
  468. if ( i >= 0 )
  469. {
  470. _module->control_input[i].control_value( value );
  471. if ( _module->control_input[i].connected() )
  472. _module->control_input[i].connected_port()->module()->handle_control_changed( _module->control_input[i].connected_port() );
  473. }
  474. update_spectrum();
  475. // _module->handle_control_changed( &_module->control_input[i] );
  476. }
  477. void
  478. Module_Parameter_Editor::menu_cb ( Fl_Widget *w, void *v )
  479. {
  480. ((Module_Parameter_Editor*)v)->menu_cb((Fl_Menu_*)w);
  481. }
  482. void
  483. Module_Parameter_Editor::menu_cb ( Fl_Menu_* m )
  484. {
  485. char picked[256];
  486. if ( ! m->mvalue() || m->mvalue()->flags & FL_SUBMENU_POINTER || m->mvalue()->flags & FL_SUBMENU )
  487. return;
  488. strncpy( picked, m->mvalue()->label(), sizeof( picked ) );
  489. // m->item_pathname( picked, sizeof( picked ) );
  490. DMESSAGE( "%s", picked );
  491. if ( ! strcmp( picked, "Bind" ) )
  492. {
  493. bind_control( _selected_control );
  494. }
  495. }
  496. Fl_Menu_Button &
  497. Module_Parameter_Editor::menu ( void ) const
  498. {
  499. static Fl_Menu_Button m( 0, 0, 0, 0, "Control" );
  500. m.clear();
  501. m.add( "Bind", 0, 0, 0, FL_MENU_RADIO | (_module->control_input[_selected_control].connected() ? FL_MENU_VALUE : 0 ));
  502. // m.add( "Unbind", 0, &Module::menu_cb, this, 0, FL_MENU_RADIO );
  503. m.callback( menu_cb, (void*)this );
  504. return m;
  505. }
  506. int
  507. Module_Parameter_Editor::handle ( int m )
  508. {
  509. switch ( m )
  510. {
  511. case FL_PUSH:
  512. if ( test_press( FL_BUTTON3 ) )
  513. {
  514. for ( unsigned int i = 0; i < controls_by_port.size(); i++ )
  515. {
  516. if ( Fl::event_inside( controls_by_port[i] ) )
  517. {
  518. _selected_control = i;
  519. Fl_Menu_Button &m = menu();
  520. menu_popup(&m,Fl::event_x(), Fl::event_y());
  521. return 1;
  522. }
  523. }
  524. return 0;
  525. }
  526. }
  527. return Fl_Group::handle(m);
  528. }