tidy up AU GUIs, make bypass button work and add preset/automation placeholders
[ardour.git] / gtk2_ardour / generic_pluginui.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <climits>
21 #include <cerrno>
22 #include <cmath>
23 #include <string>
24
25 #include <pbd/stl_delete.h>
26 #include <pbd/xml++.h>
27 #include <pbd/failed_constructor.h>
28
29 #include <gtkmm2ext/click_box.h>
30 #include <gtkmm2ext/fastmeter.h>
31 #include <gtkmm2ext/barcontroller.h>
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/doi.h>
34 #include <gtkmm2ext/slider_controller.h>
35
36 #include <midi++/manager.h>
37
38 #include <ardour/plugin.h>
39 #include <ardour/insert.h>
40 #include <ardour/ladspa_plugin.h>
41 #ifdef HAVE_LV2
42 #include <ardour/lv2_plugin.h>
43 #endif
44
45 #include <lrdf.h>
46
47 #include "ardour_ui.h"
48 #include "prompter.h"
49 #include "plugin_ui.h"
50 #include "utils.h"
51 #include "gui_thread.h"
52
53 #include "i18n.h"
54
55 using namespace std;
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace Gtkmm2ext;
59 using namespace Gtk;
60 using namespace sigc;
61
62 GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrollable)
63         : PlugUIBase (pi),
64           button_table (initial_button_rows, initial_button_cols),
65           output_table (initial_output_rows, initial_output_cols),
66           hAdjustment(0.0, 0.0, 0.0),
67           vAdjustment(0.0, 0.0, 0.0),
68           scroller_view(hAdjustment, vAdjustment),
69           automation_menu (0),
70           is_scrollable(scrollable)
71 {
72         set_name ("PluginEditor");
73         set_border_width (10);
74         set_homogeneous (false);
75
76         settings_box.set_homogeneous (false);
77
78         HBox* constraint_hbox = manage (new HBox);
79         HBox* smaller_hbox = manage (new HBox);
80         Label* combo_label = manage (new Label (_("<span size=\"large\">Presets</span>")));
81         combo_label->set_use_markup (true);
82
83         smaller_hbox->pack_start (*combo_label, false, false, 10);
84         smaller_hbox->pack_start (preset_combo, false, false);
85         smaller_hbox->pack_start (save_button, false, false);
86
87         constraint_hbox->set_spacing (5);
88         constraint_hbox->pack_start (*smaller_hbox, true, false);
89         constraint_hbox->pack_end (bypass_button, false, false);
90
91         settings_box.pack_end (*constraint_hbox, false, false);
92
93         pack_start (settings_box, false, false);
94
95         if ( is_scrollable ) {
96                 scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
97                 scroller.set_name ("PluginEditor");
98                 scroller_view.set_name("PluginEditor");
99                 scroller_view.add (hpacker);
100                 scroller.add (scroller_view);
101                 
102                 pack_start (scroller, true, true);
103
104         }
105         else {
106                 pack_start (hpacker, false, false);
107         }
108
109         insert->active_changed.connect (mem_fun(*this, &GenericPluginUI::redirect_active_changed));
110         bypass_button.set_active (!insert->active());
111         
112         build ();
113 }
114
115 GenericPluginUI::~GenericPluginUI ()
116 {
117         if (output_controls.size() > 0) {
118                 screen_update_connection.disconnect();
119         }
120 }
121
122 void
123 GenericPluginUI::build ()
124
125 {
126         guint32 i = 0;
127         guint32 x = 0;
128         Frame* frame;
129         Frame* bt_frame;
130         VBox* box;
131         int output_row, output_col;
132         int button_row, button_col;
133         int output_rows, output_cols;
134         int button_rows, button_cols;
135         guint32 n_ins=0, n_outs = 0;
136
137         prefheight = 30;
138         hpacker.set_spacing (10);
139
140         output_rows = initial_output_rows;
141         output_cols = initial_output_cols;
142         button_rows = initial_button_rows;
143         button_cols = initial_button_cols;
144         output_row = 0;
145         button_row = 0;
146         output_col = 0;
147         button_col = 0;
148
149         button_table.set_homogeneous (false);
150         button_table.set_row_spacings (2);
151         button_table.set_col_spacings (2);
152         output_table.set_homogeneous (true);
153         output_table.set_row_spacings (2);
154         output_table.set_col_spacings (2);
155         button_table.set_border_width (5);
156         output_table.set_border_width (5);
157
158         hpacker.set_border_width (10);
159
160         bt_frame = manage (new Frame);
161         bt_frame->set_name ("BaseFrame");
162         bt_frame->add (button_table);
163         hpacker.pack_start(*bt_frame, true, true);
164
165         box = manage (new VBox);
166         box->set_border_width (5);
167         box->set_spacing (1);
168
169         frame = manage (new Frame);
170         frame->set_name ("BaseFrame");
171         frame->set_label (_("Controls"));
172         frame->add (*box);
173         hpacker.pack_start(*frame, true, true);
174
175         /* find all ports. build control elements for all appropriate control ports */
176
177         for (i = 0; i < plugin->parameter_count(); ++i) {
178
179                 if (plugin->parameter_is_control (i)) {
180                         
181                         /* Don't show latency control ports */
182
183                         if (plugin->describe_parameter (i) == X_("latency")) {
184                                 continue;
185                         }
186
187                         ControlUI* cui;
188         
189                         /* if we are scrollable, just use one long column */
190
191                         if (!is_scrollable) {
192                                 if (x++ > 7){
193                                         frame = manage (new Frame);
194                                         frame->set_name ("BaseFrame");
195                                         box = manage (new VBox);
196                                         
197                                         box->set_border_width (5);
198                                         box->set_spacing (1);
199
200                                         frame->add (*box);
201                                         hpacker.pack_start(*frame,true,true);
202
203                                         x = 1;
204                                 }
205                         }
206
207                         if ((cui = build_control_ui (i, plugin->get_nth_control (i))) == 0) {
208                                 error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg;
209                                 continue;
210                         }
211                                 
212                         if (cui->control || cui->clickbox || cui->combo) {
213
214                                 box->pack_start (*cui, false, false);
215
216                         } else if (cui->button) {
217
218                                 if (button_row == button_rows) {
219                                         button_row = 0;
220                                         if (++button_col == button_cols) {
221                                                 button_cols += 2;
222                                                 button_table.resize (button_rows, button_cols);
223                                         }
224                                 }
225
226                                 button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1, 
227                                                      FILL|EXPAND, FILL);
228                                 button_row++;
229
230                         } else if (cui->display) {
231
232                                 output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, 
233                                                      FILL|EXPAND, FILL);
234                                 
235                                 // TODO: The meters should be divided into multiple rows 
236                                 
237                                 if (++output_col == output_cols) {
238                                         output_cols ++;
239                                         output_table.resize (output_rows, output_cols);
240                                 }
241                                 
242                                 /* old code, which divides meters into
243                                  * columns first, rows later. New code divides into one row
244                                  
245                                 if (output_row == output_rows) {
246                                         output_row = 0;
247                                         if (++output_col == output_cols) {
248                                                 output_cols += 2;
249                                                 output_table.resize (output_rows, output_cols);
250                                         }
251                                 }
252                                 
253                                 output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, 
254                                                      FILL|EXPAND, FILL);
255  
256                                 output_row++;
257                                 */
258                         }
259                                 
260                         /* HACK: ideally the preferred height would be queried from
261                            the complete hpacker, but I can't seem to get that
262                            information in time, so this is an estimation 
263                         */
264
265                         prefheight += 30;
266
267                 } 
268         }
269
270         n_ins = plugin->get_info()->n_inputs;
271         n_outs = plugin->get_info()->n_outputs;
272
273         if (box->children().empty()) {
274                 hpacker.remove (*frame);
275         }
276
277         if (button_table.children().empty()) {
278                 hpacker.remove (*bt_frame);
279         }
280
281         if (!output_table.children().empty()) {
282                 frame = manage (new Frame);
283                 frame->set_name ("BaseFrame");
284                 frame->add (output_table);
285                 hpacker.pack_end (*frame, true, true);
286         }
287
288         output_update ();
289
290         output_table.show_all ();
291         button_table.show_all ();
292 }
293
294 GenericPluginUI::ControlUI::ControlUI ()
295         : automate_button (X_("")) // force creation of a label 
296 {
297         automate_button.set_name ("PluginAutomateButton");
298         ARDOUR_UI::instance()->tooltips().set_tip (automate_button, _("Automation control"));
299
300         /* XXX translators: use a string here that will be at least as long
301            as the longest automation label (see ::automation_state_changed()
302            below). be sure to include a descender.
303         */
304
305         set_size_request_to_display_given_text (*automate_button.get_child(), _("Mgnual"), 5, 5);
306
307         ignore_change = 0;
308         display = 0;
309         button = 0;
310         control = 0;
311         clickbox = 0;
312         adjustment = 0;
313         meterinfo = 0;
314 }
315
316 GenericPluginUI::ControlUI::~ControlUI() 
317 {
318         if (adjustment) {
319                 delete adjustment;
320         }
321
322         if (meterinfo) {
323                 delete meterinfo->meter;
324                 delete meterinfo;
325         }
326 }
327
328 void
329 GenericPluginUI::automation_state_changed (ControlUI* cui)
330 {
331         /* update button label */
332
333         switch (insert->get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) {
334         case Off:
335                 cui->automate_button.set_label (_("Manual"));
336                 break;
337         case Play:
338                 cui->automate_button.set_label (_("Play"));
339                 break;
340         case Write:
341                 cui->automate_button.set_label (_("Write"));
342                 break;
343         case Touch:
344                 cui->automate_button.set_label (_("Touch"));
345                 break;
346         default:
347                 cui->automate_button.set_label (_("???"));
348                 break;
349         }
350 }
351
352
353 static void integer_printer (char buf[32], Adjustment &adj, void *arg)
354 {
355         snprintf (buf, 32, "%.0f", adj.get_value());
356 }
357
358 void
359 GenericPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param)
360 {
361         plugin->print_parameter (param, buf, len);
362 }
363
364 GenericPluginUI::ControlUI*
365 GenericPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontrol)
366
367 {
368         ControlUI* control_ui;
369         Plugin::ParameterDescriptor desc;
370
371         plugin->get_parameter_descriptor (port_index, desc);
372
373         control_ui = manage (new ControlUI ());
374         control_ui->adjustment = 0;
375         control_ui->combo = 0;
376         control_ui->combo_map = 0;
377         control_ui->port_index = port_index;
378         control_ui->update_pending = false;
379         control_ui->label.set_text (desc.label);
380         control_ui->label.set_alignment (0.0, 0.5);
381         control_ui->label.set_name ("PluginParameterLabel");
382
383         control_ui->set_spacing (5);
384
385         Gtk::Requisition req (control_ui->automate_button.size_request());
386
387         if (plugin->parameter_is_input (port_index)) {
388
389                 boost::shared_ptr<LadspaPlugin> lp;
390 #ifdef HAVE_LV2
391                 boost::shared_ptr<LV2Plugin> lv2p;
392 #endif
393                 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
394
395                         // all LADPSA plugins have a numeric unique ID
396                         uint32_t id = atol (lp->unique_id().c_str());
397
398                         lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index);
399                         
400                         if (defaults && defaults->count > 0)    {
401                                 
402                                 control_ui->combo = new Gtk::ComboBoxText;
403                                 //control_ui->combo->set_value_in_list(true, false);
404                                 set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui));
405                                 control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui));
406                                 plugin->ParameterChanged.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui));
407                                 control_ui->pack_start(control_ui->label, true, true);
408                                 control_ui->pack_start(*control_ui->combo, false, true);
409                                 
410                                 update_control_display(control_ui);
411                                 
412                                 lrdf_free_setting_values(defaults);
413                                 return control_ui;
414                         }
415
416 #ifdef HAVE_LV2
417                 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
418
419                         SLV2Port port = lv2p->slv2_port(port_index);
420                         SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port);
421
422                         if (points) {
423                                 control_ui->combo = new Gtk::ComboBoxText;
424                                 //control_ui->combo->set_value_in_list(true, false);
425                                 set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui));
426                                 control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui));
427                                 plugin->ParameterChanged.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui));
428                                 control_ui->pack_start(control_ui->label, true, true);
429                                 control_ui->pack_start(*control_ui->combo, false, true);
430                                 
431                                 update_control_display(control_ui);
432                                 
433                                 slv2_scale_points_free(points);
434                                 return control_ui;
435                         }
436 #endif
437                 }
438                         
439                 if (desc.toggled) {
440
441                         /* Build a button */
442                 
443                         control_ui->button = manage (new ToggleButton ());
444                         control_ui->button->set_name ("PluginEditorButton");
445                         control_ui->button->set_size_request (20, 20);
446
447                         control_ui->pack_start (control_ui->label, true, true);
448                         control_ui->pack_start (*control_ui->button, false, true);
449                         control_ui->pack_start (control_ui->automate_button, false, false);
450
451                         control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::control_port_toggled), control_ui));
452                 
453                         if(plugin->get_parameter (port_index) == 1){
454                                 control_ui->button->set_active(true);
455                         }
456
457                         return control_ui;
458                 }
459         
460                 control_ui->adjustment = new Adjustment (0, 0, 0, 0, 0);
461
462                 /* XXX this code is not right yet, because it doesn't handle
463                    the absence of bounds in any sensible fashion.
464                 */
465
466                 control_ui->adjustment->set_lower (desc.lower);
467                 control_ui->adjustment->set_upper (desc.upper);
468
469                 control_ui->logarithmic = desc.logarithmic;
470                 if (control_ui->logarithmic) {
471                         if (control_ui->adjustment->get_lower() == 0.0) {
472                                 control_ui->adjustment->set_lower (control_ui->adjustment->get_upper()/10000);
473                         }
474                         control_ui->adjustment->set_upper (log(control_ui->adjustment->get_upper()));
475                         control_ui->adjustment->set_lower (log(control_ui->adjustment->get_lower()));
476                 }
477         
478                 float delta = desc.upper - desc.lower;
479
480                 control_ui->adjustment->set_page_size (delta/100.0);
481                 control_ui->adjustment->set_step_increment (desc.step);
482                 control_ui->adjustment->set_page_increment (desc.largestep);
483
484                 if (desc.integer_step) {
485                         control_ui->clickbox = new ClickBox (control_ui->adjustment, "PluginUIClickBox");
486                         Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2);
487                         control_ui->clickbox->set_print_func (integer_printer, 0);
488                 } else {
489                         sigc::slot<void,char*,uint32_t> pslot = sigc::bind (mem_fun(*this, &GenericPluginUI::print_parameter), (uint32_t) port_index);
490
491                         control_ui->control = new BarController (*control_ui->adjustment, *mcontrol, pslot);
492                         control_ui->control->set_size_request (200, req.height);
493                         control_ui->control->set_name (X_("PluginSlider"));
494                         control_ui->control->set_style (BarController::LeftToRight);
495                         control_ui->control->set_use_parent (true);
496
497                         control_ui->control->StartGesture.connect (bind (mem_fun(*this, &GenericPluginUI::start_touch), control_ui));
498                         control_ui->control->StopGesture.connect (bind (mem_fun(*this, &GenericPluginUI::stop_touch), control_ui));
499                         
500                 }
501
502                 if (control_ui->logarithmic) {
503                         control_ui->adjustment->set_value(log(plugin->get_parameter(port_index)));
504                 } else{
505                         control_ui->adjustment->set_value(plugin->get_parameter(port_index));
506                 }
507
508                 /* XXX memory leak: SliderController not destroyed by ControlUI
509                    destructor, and manage() reports object hierarchy
510                    ambiguity.
511                 */
512
513                 control_ui->pack_start (control_ui->label, true, true);
514                 if (desc.integer_step) {
515                         control_ui->pack_start (*control_ui->clickbox, false, false);
516                 } else {
517                         control_ui->pack_start (*control_ui->control, false, false);
518                 }
519
520                 control_ui->pack_start (control_ui->automate_button, false, false);
521                 control_ui->adjustment->signal_value_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_adjustment_changed), control_ui));
522                 control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::astate_clicked), control_ui, (uint32_t) port_index));
523
524                 automation_state_changed (control_ui);
525
526                 plugin->ParameterChanged.connect (bind (mem_fun(*this, &GenericPluginUI::parameter_changed), control_ui));
527                 insert->automation_list (port_index).automation_state_changed.connect 
528                         (bind (mem_fun(*this, &GenericPluginUI::automation_state_changed), control_ui));
529
530         } else if (plugin->parameter_is_output (port_index)) {
531
532                 control_ui->display = manage (new EventBox);
533                 control_ui->display->set_name ("ParameterValueDisplay");
534
535                 control_ui->display_label = manage (new Label);
536
537                 control_ui->display_label->set_name ("ParameterValueDisplay");
538
539                 control_ui->display->add (*control_ui->display_label);
540                 Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->display, "-99,99", 2, 2);
541
542                 control_ui->display->show_all ();
543
544                 /* set up a meter */
545                 /* TODO: only make a meter if the port is Hinted for it */
546
547                 MeterInfo * info = new MeterInfo(port_index);
548                 control_ui->meterinfo = info;
549                 
550                 info->meter = new FastMeter (5, 5, FastMeter::Vertical);
551
552                 info->min_unbound = desc.min_unbound;
553                 info->max_unbound = desc.max_unbound;
554
555                 info->min = desc.lower;
556                 info->max = desc.upper;
557
558                 control_ui->vbox = manage (new VBox);
559                 control_ui->hbox = manage (new HBox);
560                 
561                 control_ui->label.set_angle(90);
562                 control_ui->hbox->pack_start (control_ui->label, false, false);
563                 control_ui->hbox->pack_start (*info->meter, false, false);
564
565                 control_ui->vbox->pack_start (*control_ui->hbox, false, false);
566                 
567                 control_ui->vbox->pack_start (*control_ui->display, false, false);
568
569                 control_ui->pack_start (*control_ui->vbox);
570
571                 control_ui->meterinfo->meter->show_all();
572                 control_ui->meterinfo->packed = true;
573                 
574                 output_controls.push_back (control_ui);
575         }
576         
577         plugin->ParameterChanged.connect (bind (mem_fun(*this, &GenericPluginUI::parameter_changed), control_ui));
578         return control_ui;
579 }
580
581 void
582 GenericPluginUI::start_touch (GenericPluginUI::ControlUI* cui)
583 {
584         insert->automation_list (cui->port_index).start_touch ();
585 }
586
587 void
588 GenericPluginUI::stop_touch (GenericPluginUI::ControlUI* cui)
589 {
590         insert->automation_list (cui->port_index).stop_touch ();
591 }
592
593 void
594 GenericPluginUI::astate_clicked (ControlUI* cui, uint32_t port)
595 {
596         using namespace Menu_Helpers;
597
598         if (automation_menu == 0) {
599                 automation_menu = manage (new Menu);
600                 automation_menu->set_name ("ArdourContextMenu");
601         } 
602
603         MenuList& items (automation_menu->items());
604
605         items.clear ();
606         items.push_back (MenuElem (_("Manual"), 
607                                    bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Off, cui)));
608         items.push_back (MenuElem (_("Play"),
609                                    bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Play, cui)));
610         items.push_back (MenuElem (_("Write"),
611                                    bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Write, cui)));
612         items.push_back (MenuElem (_("Touch"),
613                                    bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Touch, cui)));
614
615         automation_menu->popup (1, gtk_get_current_event_time());
616 }
617
618 void
619 GenericPluginUI::set_automation_state (AutoState state, ControlUI* cui)
620 {
621         insert->set_port_automation_state (cui->port_index, state);
622 }
623
624 void
625 GenericPluginUI::control_adjustment_changed (ControlUI* cui)
626 {
627         if (cui->ignore_change) {
628                 return;
629         }
630
631         double value = cui->adjustment->get_value();
632
633         if (cui->logarithmic) {
634                 value = exp(value);
635         }
636
637         insert->set_parameter (cui->port_index, (float) value);
638 }
639
640 void
641 GenericPluginUI::parameter_changed (uint32_t abs_port_id, float val, ControlUI* cui)
642 {
643         if (cui->port_index == abs_port_id) {
644                 if (!cui->update_pending) {
645                         cui->update_pending = true;
646                         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &GenericPluginUI::update_control_display), cui));
647                 }
648         }
649 }
650
651 void
652 GenericPluginUI::update_control_display (ControlUI* cui)        
653 {
654         /* XXX how do we handle logarithmic stuff here ? */
655         
656         cui->update_pending = false;
657
658         float val = plugin->get_parameter (cui->port_index);
659
660         cui->ignore_change++;
661         if (cui->combo) {
662                 std::map<string,float>::iterator it;
663                 for (it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) {
664                         if (it->second == val) {
665                                 cui->combo->set_active_text(it->first);
666                                 break;
667                         }
668                 }
669         } else if (cui->adjustment == 0) {
670
671                 if (val > 0.5) {
672                         cui->button->set_active (true);
673                 } else {
674                         cui->button->set_active (false);
675                 }
676
677         } else {
678                 if (cui->logarithmic) {
679                         val = log(val);
680                 }
681                 if (val != cui->adjustment->get_value()) {
682                         cui->adjustment->set_value (val);
683                 }
684         }
685         cui->ignore_change--;
686 }
687
688 void
689 GenericPluginUI::control_port_toggled (ControlUI* cui)
690 {
691         if (!cui->ignore_change) {
692                 insert->set_parameter (cui->port_index, cui->button->get_active());
693         }
694 }
695
696 void
697 GenericPluginUI::control_combo_changed (ControlUI* cui)
698 {
699         if (!cui->ignore_change) {
700                 string value = cui->combo->get_active_text();
701                 std::map<string,float> mapping = *cui->combo_map;
702                 insert->set_parameter (cui->port_index, mapping[value]);
703         }
704
705 }
706
707 void
708 GenericPluginUI::redirect_active_changed (Redirect* r, void* src)
709 {
710         ENSURE_GUI_THREAD(bind (mem_fun(*this, &GenericPluginUI::redirect_active_changed), r, src));
711         
712         bypass_button.set_active (!r->active());
713 }
714
715 bool
716 GenericPluginUI::start_updating (GdkEventAny* ignored)
717 {
718         if (output_controls.size() > 0 ) {
719                 screen_update_connection.disconnect();
720                 screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect 
721                         (mem_fun(*this, &GenericPluginUI::output_update));
722         }
723         return false;
724 }
725
726 bool
727 GenericPluginUI::stop_updating (GdkEventAny* ignored)
728 {
729         if (output_controls.size() > 0 ) {
730                 screen_update_connection.disconnect();
731         }
732         return false;
733 }
734
735 void
736 GenericPluginUI::output_update ()
737 {
738         for (vector<ControlUI*>::iterator i = output_controls.begin(); i != output_controls.end(); ++i) {
739                 float val = plugin->get_parameter ((*i)->port_index);
740                 char buf[32];
741                 snprintf (buf, sizeof(buf), "%.2f", val);
742                 (*i)->display_label->set_text (buf);
743
744                 /* autoscaling for the meter */
745                 if ((*i)->meterinfo && (*i)->meterinfo->packed) {
746                         
747                         if (val < (*i)->meterinfo->min) {
748                                 if ((*i)->meterinfo->min_unbound)
749                                         (*i)->meterinfo->min = val;
750                                 else
751                                         val = (*i)->meterinfo->min;
752                         }
753
754                         if (val > (*i)->meterinfo->max) {
755                                 if ((*i)->meterinfo->max_unbound)
756                                         (*i)->meterinfo->max = val;
757                                 else
758                                         val = (*i)->meterinfo->max;
759                         }
760                         
761                         if ((*i)->meterinfo->max > (*i)->meterinfo->min ) {
762                                 float lval = (val - (*i)->meterinfo->min) / ((*i)->meterinfo->max - (*i)->meterinfo->min) ;
763                                 (*i)->meterinfo->meter->set (lval );
764                         }
765                 }
766         }
767 }
768
769 vector<string> 
770 GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
771 {
772         vector<string> enums;
773         boost::shared_ptr<LadspaPlugin> lp;
774 #ifdef HAVE_LV2
775         boost::shared_ptr<LV2Plugin> lv2p;
776 #endif
777
778         if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
779                 // all LADPSA plugins have a numeric unique ID
780                 uint32_t id = atol (lp->unique_id().c_str());
781
782                 cui->combo_map = new std::map<string, float>;
783                 lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index);
784                 if (defaults)   {
785                         for (uint32_t i = 0; i < defaults->count; ++i) {
786                                 enums.push_back(defaults->items[i].label);
787                                 pair<string, float> newpair;
788                                 newpair.first = defaults->items[i].label;
789                                 newpair.second = defaults->items[i].value;
790                                 cui->combo_map->insert(newpair);
791                         }
792
793                         lrdf_free_setting_values(defaults);
794                 }
795
796 #ifdef HAVE_LV2
797         } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
798
799                 SLV2Port port = lv2p->slv2_port(port_index);
800                 SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port);
801                 cui->combo_map = new std::map<string, float>;
802         
803                 for (unsigned i=0; i < slv2_scale_points_size(points); ++i) {
804                         SLV2ScalePoint p = slv2_scale_points_get_at(points, i);
805                         SLV2Value label = slv2_scale_point_get_label(p);
806                         SLV2Value value = slv2_scale_point_get_value(p);
807                         if (label && (slv2_value_is_float(value) || slv2_value_is_int(value))) {
808                                 enums.push_back(slv2_value_as_string(label));
809                                 pair<string, float> newpair;
810                                 newpair.first = slv2_value_as_string(label);
811                                 newpair.second = slv2_value_as_float(value);
812                                 cui->combo_map->insert(newpair);
813                         }
814                 }
815
816                 slv2_scale_points_free(points);
817 #endif
818         }
819         
820
821         return enums;
822 }