Non reinvents the DAW. Powerful enough to form a complete studio, fast and light enough to run on low-end hardware like the eeePC or Raspberry Pi, and so reliable that it can be used live https://non.tuxfamily.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
15KB

  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 "Module.H"
  33. #include "Module_Parameter_Editor.H"
  34. #include "Controller_Module.H"
  35. #include "Chain.H"
  36. #include "Panner.H"
  37. #include "debug.h"
  38. Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_Window( 800, 600 )
  39. {
  40. _module = module;
  41. _resized = false;
  42. _min_width = 100;
  43. char lab[256];
  44. if ( strcmp( module->name(), module->label() ) )
  45. {
  46. snprintf( lab, sizeof( lab ), "%s : %s", module->name(), module->label() );
  47. }
  48. else
  49. strcpy( lab, module->label() );
  50. char title[512];
  51. snprintf( title, sizeof( title ), "%s - %s - %s", "Mixer", module->chain()->name(), lab );
  52. copy_label( title );
  53. fl_font( FL_HELVETICA, 14 );
  54. _min_width = 30 + fl_width( module->label() );
  55. { Fl_Pack *o = main_pack = new Fl_Pack( 0, 0, w(), h() - 10 );
  56. o->type( FL_VERTICAL );
  57. o->label( module->label() );
  58. o->labelfont( 2 );
  59. o->labeltype( FL_SHADOW_LABEL );
  60. o->labelsize( 14 );
  61. o->align( FL_ALIGN_TOP | FL_ALIGN_RIGHT | FL_ALIGN_INSIDE );
  62. { Fl_Pack *o = new Fl_Pack( 0, 0, 50, 25 );
  63. o->type( FL_HORIZONTAL );
  64. o->spacing( 20 );
  65. { Fl_Menu_Button *o = mode_choice = new Fl_Menu_Button( 0, 0, 25, 25 );
  66. o->add( "Knobs" );
  67. o->add( "Horizontal Sliders" );
  68. o->add( "Vertical Sliders" );
  69. o->label( NULL );
  70. o->value( 0 );
  71. o->when( FL_WHEN_CHANGED );
  72. o->callback( cb_mode_handle, this );
  73. }
  74. /* { Fl_Box *o = new Fl_Box( 0, 0, 300, 25 ); */
  75. /* o->box( FL_ROUNDED_BOX ); */
  76. /* o->color( FL_YELLOW ); */
  77. /* o->label( strdup( lab ) ); */
  78. /* o->labeltype( FL_SHADOW_LABEL ); */
  79. /* o->labelsize( 18 ); */
  80. /* o->align( (Fl_Align)(FL_ALIGN_TOP | FL_ALIGN_RIGHT | FL_ALIGN_INSIDE ) ); */
  81. /* // Fl_Group::current()->resizable( o ); */
  82. /* } */
  83. o->end();
  84. }
  85. { Fl_Group *o = new Fl_Group( 0, 0, w(), h() );
  86. { Fl_Flowpack *o = control_pack = new Fl_Flowpack( 50, 0, w() - 100, h() );
  87. /* o->box( FL_ROUNDED_BOX ); */
  88. /* o->color( FL_GRAY ); */
  89. o->type( FL_HORIZONTAL );
  90. o->flow( true );
  91. o->vspacing( 10 );
  92. o->hspacing( 10 );
  93. o->end();
  94. }
  95. o->resizable( 0 );
  96. o->end();
  97. }
  98. o->end();
  99. }
  100. end();
  101. // draw();
  102. make_controls();
  103. }
  104. Module_Parameter_Editor::~Module_Parameter_Editor ( )
  105. {
  106. }
  107. void
  108. Module_Parameter_Editor::make_controls ( void )
  109. {
  110. Module *module = _module;
  111. control_pack->clear();
  112. controls_by_port.clear();
  113. /* these are for detecting related parameter groups which can be
  114. better represented by a single control */
  115. azimuth_port_number = -1;
  116. float azimuth_value = 0.0f;
  117. elevation_port_number = -1;
  118. float elevation_value = 0.0f;
  119. radius_port_number = -1;
  120. float radius_value = 0.0f;
  121. Fl_Color fc = fl_color_add_alpha( FL_CYAN, 200 );
  122. Fl_Color bc = FL_BACKGROUND2_COLOR;
  123. controls_by_port.resize( module->control_input.size() );
  124. for ( unsigned int i = 0; i < module->control_input.size(); ++i )
  125. {
  126. Fl_Widget *w;
  127. Module::Port *p = &module->control_input[i];
  128. /* if ( !p->hints.visible ) */
  129. /* continue; */
  130. if ( !strcasecmp( "Azimuth", p->name() ) &&
  131. 180.0f == p->hints.maximum &&
  132. -180.0f == p->hints.minimum )
  133. {
  134. azimuth_port_number = i;
  135. azimuth_value = p->control_value();
  136. continue;
  137. }
  138. else if ( !strcasecmp( "Elevation", p->name() ) &&
  139. 90.0f == p->hints.maximum &&
  140. -90.0f == p->hints.minimum )
  141. {
  142. elevation_port_number = i;
  143. elevation_value = p->control_value();
  144. continue;
  145. }
  146. else if ( !strcasecmp( "Radius", p->name() ) )
  147. {
  148. radius_port_number = i;
  149. radius_value = p->control_value();
  150. continue;
  151. }
  152. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  153. {
  154. Fl_Button *o = new Fl_Button( 0, 0, 30, 30, p->name() );
  155. w = o;
  156. o->selection_color( fc );
  157. o->type( FL_TOGGLE_BUTTON );
  158. o->value( p->control_value() );
  159. }
  160. else if ( p->hints.type == Module::Port::Hints::INTEGER )
  161. {
  162. Fl_Counter *o = new Fl_Counter(0, 0, 58, 24, p->name() );
  163. w = o;
  164. o->type(1);
  165. o->step(1);
  166. if ( p->hints.ranged )
  167. {
  168. o->minimum( p->hints.minimum );
  169. o->maximum( p->hints.maximum );
  170. }
  171. o->value( p->control_value() );
  172. }
  173. else
  174. {
  175. if ( mode_choice->value() == 0 )
  176. {
  177. Fl_DialX *o = new Fl_DialX( 0, 0, 60, 60, p->name() );
  178. w = o;
  179. if ( p->hints.ranged )
  180. {
  181. DMESSAGE( "Min: %f, max: %f", p->hints.minimum, p->hints.maximum );
  182. o->minimum( p->hints.minimum );
  183. o->maximum( p->hints.maximum );
  184. }
  185. o->color( bc );
  186. o->selection_color( fc );
  187. o->value( p->control_value() );
  188. o->precision( 2 );
  189. /* a couple of plugins have ridiculously small units */
  190. if ( p->hints.maximum < 0.5f )
  191. o->precision( 5 );
  192. // o->step( fabs( ( o->maximum() - o->minimum() ) ) / 32.0f );
  193. }
  194. else
  195. {
  196. Fl_Value_SliderX *o = new Fl_Value_SliderX( 0, 0, 120, 24, p->name() );
  197. w = o;
  198. if ( mode_choice->value() == 1 )
  199. {
  200. o->type( FL_HORIZONTAL );
  201. o->size( 120, 24 );
  202. if ( p->hints.ranged )
  203. {
  204. o->minimum( p->hints.minimum );
  205. o->maximum( p->hints.maximum );
  206. }
  207. }
  208. else
  209. {
  210. o->type( FL_VERTICAL );
  211. o->size( 24, 120 );
  212. /* have to reverse the meaning of these to get the
  213. * orientation of the slider right */
  214. o->maximum( p->hints.minimum );
  215. o->minimum( p->hints.maximum );
  216. }
  217. o->precision( 2 );
  218. /* a couple of plugins have ridiculously small units */
  219. if ( p->hints.maximum < 0.5f )
  220. o->precision( 5 );
  221. o->textsize( 8 );
  222. o->box( FL_NO_BOX );
  223. o->slider( FL_UP_BOX );
  224. o->color( bc );
  225. o->selection_color( fc );
  226. o->value( p->control_value() );
  227. }
  228. }
  229. controls_by_port[i] = w;
  230. w->tooltip( p->osc_path() );
  231. Fl_Button *bound;
  232. w->align(FL_ALIGN_TOP);
  233. w->labelsize( 10 );
  234. _callback_data.push_back( callback_data( this, i ) );
  235. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  236. w->callback( cb_button_handle, &_callback_data.back() );
  237. else
  238. w->callback( cb_value_handle, &_callback_data.back() );
  239. { Fl_Group *o = new Fl_Group( 0, 0, 50, 75 );
  240. {
  241. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( w );
  242. { Fl_Button *o = bound = new Fl_Button( 0, 50, 14, 14 );
  243. o->selection_color( FL_YELLOW );
  244. o->type( 0 );
  245. o->labelsize( 8 );
  246. o->value( p->connected() );
  247. o->callback( cb_bound_handle, &_callback_data.back() );
  248. }
  249. o->resizable( 0 );
  250. o->end();
  251. o->set_visible_focus();
  252. flg->set_visible_focus();
  253. flg->position( o->x(), o->y() );
  254. bound->position( o->x(), flg->y() + flg->h() );
  255. o->size( flg->w(), flg->h() + bound->h() );
  256. o->init_sizes();
  257. }
  258. if (! p->hints.visible )
  259. o->hide();
  260. control_pack->add( o );
  261. }
  262. }
  263. if ( azimuth_port_number >= 0 && elevation_port_number >= 0 )
  264. {
  265. Panner *o = new Panner( 0,0, 502,502 );
  266. o->box(FL_FLAT_BOX);
  267. o->color(FL_GRAY0);
  268. o->selection_color(FL_BACKGROUND_COLOR);
  269. o->labeltype(FL_NORMAL_LABEL);
  270. o->labelfont(0);
  271. o->labelcolor(FL_FOREGROUND_COLOR);
  272. o->align(FL_ALIGN_TOP);
  273. o->when(FL_WHEN_CHANGED);
  274. o->label( "Spatialization" );
  275. o->labelsize( 10 );
  276. _callback_data.push_back( callback_data( this, azimuth_port_number, elevation_port_number, radius_port_number ) );
  277. o->callback( cb_panner_value_handle, &_callback_data.back() );
  278. o->point( 0 )->azimuth( azimuth_value );
  279. o->point( 0 )->elevation( elevation_value );
  280. if ( radius_port_number >= 0 )
  281. {
  282. o->point( 0 )->radius_enabled = true;
  283. o->point( 0 )->radius( radius_value );
  284. }
  285. Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( o );
  286. control_pack->add( flg );
  287. controls_by_port[azimuth_port_number] = o;
  288. controls_by_port[elevation_port_number] = o;
  289. if ( radius_port_number >= 0 )
  290. controls_by_port[radius_port_number] = o;
  291. }
  292. update_control_visibility();
  293. int width = control_pack->max_width() + 100;
  294. int height = control_pack->h() + 50;
  295. if ( width < _min_width )
  296. width = _min_width;
  297. main_pack->size( width, height );
  298. size( width, height );
  299. size_range( width, height, width, height );
  300. }
  301. void
  302. Module_Parameter_Editor::update_control_visibility ( void )
  303. {
  304. for ( unsigned int i = 0; i < _module->control_input.size(); ++i )
  305. {
  306. const Module::Port *p = &_module->control_input[i];
  307. if ( p->hints.visible )
  308. controls_by_port[i]->parent()->parent()->show();
  309. else
  310. controls_by_port[i]->parent()->parent()->hide();
  311. }
  312. }
  313. void
  314. Module_Parameter_Editor::cb_value_handle ( Fl_Widget *w, void *v )
  315. {
  316. callback_data *cd = (callback_data*)v;
  317. cd->base_widget->set_value( cd->port_number[0], ((Fl_Valuator*)w)->value() );
  318. }
  319. void
  320. Module_Parameter_Editor::cb_button_handle ( Fl_Widget *w, void *v )
  321. {
  322. callback_data *cd = (callback_data*)v;
  323. cd->base_widget->set_value( cd->port_number[0], ((Fl_Button*)w)->value() );
  324. }
  325. void
  326. Module_Parameter_Editor::cb_panner_value_handle ( Fl_Widget *w, void *v )
  327. {
  328. callback_data *cd = (callback_data*)v;
  329. cd->base_widget->set_value( cd->port_number[0], ((Panner*)w)->point( 0 )->azimuth() );
  330. cd->base_widget->set_value( cd->port_number[1], ((Panner*)w)->point( 0 )->elevation() );
  331. cd->base_widget->set_value( cd->port_number[2], ((Panner*)w)->point( 0 )->radius() );
  332. }
  333. void
  334. Module_Parameter_Editor::cb_mode_handle ( Fl_Widget *, void *v )
  335. {
  336. ((Module_Parameter_Editor*)v)->make_controls();
  337. }
  338. void
  339. Module_Parameter_Editor::cb_bound_handle ( Fl_Widget *w, void *v )
  340. {
  341. callback_data *cd = (callback_data*)v;
  342. Fl_Button *fv = (Fl_Button*)w;
  343. fv->value( 1 );
  344. cd->base_widget->bind_control( cd->port_number[0] );
  345. }
  346. void
  347. Module_Parameter_Editor::bind_control ( int i )
  348. {
  349. Module::Port *p = &_module->control_input[i];
  350. if ( p->connected() )
  351. /* can only bind once */
  352. return;
  353. Controller_Module *o = new Controller_Module();
  354. o->label( p->name() );
  355. o->chain( _module->chain() );
  356. o->connect_to( p );
  357. _module->chain()->add_control( o );
  358. _module->redraw();
  359. }
  360. /* Display changes initiated via automation or from other parts of the GUI */
  361. void
  362. Module_Parameter_Editor::handle_control_changed ( Module::Port *p )
  363. {
  364. int i = _module->control_input_port_index( p );
  365. Fl_Widget *w = controls_by_port[i];
  366. if ( i == azimuth_port_number ||
  367. i == elevation_port_number ||
  368. i == radius_port_number )
  369. {
  370. Panner *_panner = (Panner*)w;
  371. if ( i == azimuth_port_number )
  372. _panner->point(0)->azimuth( p->control_value() );
  373. else if ( i == elevation_port_number )
  374. _panner->point(0)->elevation( p->control_value() );
  375. else if ( i == radius_port_number )
  376. _panner->point(0)->radius( p->control_value() );
  377. _panner->redraw();
  378. return;
  379. }
  380. if ( p->hints.type == Module::Port::Hints::BOOLEAN )
  381. {
  382. Fl_Button *v = (Fl_Button*)w;
  383. v->value( p->control_value() );
  384. }
  385. else
  386. {
  387. Fl_Valuator *v = (Fl_Valuator*)w;
  388. v->value( p->control_value() );
  389. }
  390. }
  391. void
  392. Module_Parameter_Editor::reload ( void )
  393. {
  394. // make_controls();
  395. update_control_visibility();
  396. redraw();
  397. }
  398. void
  399. Module_Parameter_Editor::set_value (int i, float value )
  400. {
  401. if ( i >= 0 )
  402. {
  403. _module->control_input[i].control_value( value );
  404. if ( _module->control_input[i].connected() )
  405. _module->control_input[i].connected_port()->module()->handle_control_changed( _module->control_input[i].connected_port() );
  406. }
  407. // _module->handle_control_changed( &_module->control_input[i] );
  408. }