2 Copyright (C) 2000 Paul Davis
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.
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.
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.
21 #include "gtk2ardour-config.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/xml++.h"
31 #include "pbd/failed_constructor.h"
33 #include <gtkmm2ext/click_box.h>
34 #include <gtkmm2ext/fastmeter.h>
35 #include <gtkmm2ext/barcontroller.h>
36 #include <gtkmm2ext/utils.h>
37 #include <gtkmm2ext/doi.h>
38 #include <gtkmm2ext/slider_controller.h>
40 #include "midi++/manager.h"
42 #include "ardour/plugin.h"
43 #include "ardour/plugin_insert.h"
44 #include "ardour/session.h"
48 #include "ardour_ui.h"
50 #include "plugin_ui.h"
52 #include "gui_thread.h"
53 #include "automation_controller.h"
58 using namespace ARDOUR
;
60 using namespace Gtkmm2ext
;
63 GenericPluginUI::GenericPluginUI (boost::shared_ptr
<PluginInsert
> pi
, bool scrollable
)
65 button_table (initial_button_rows
, initial_button_cols
),
66 output_table (initial_output_rows
, initial_output_cols
),
67 hAdjustment(0.0, 0.0, 0.0),
68 vAdjustment(0.0, 0.0, 0.0),
69 scroller_view(hAdjustment
, vAdjustment
),
71 is_scrollable(scrollable
)
73 set_name ("PluginEditor");
74 set_border_width (10);
75 //set_homogeneous (false);
77 pack_start (main_contents
, true, true);
78 settings_box
.set_homogeneous (false);
80 HBox
* constraint_hbox
= manage (new HBox
);
81 HBox
* smaller_hbox
= manage (new HBox
);
82 smaller_hbox
->set_spacing (4);
83 Label
* combo_label
= manage (new Label (_("<span size=\"large\">Presets</span>")));
84 combo_label
->set_use_markup (true);
86 latency_button
.add (latency_label
);
87 latency_button
.signal_clicked().connect (sigc::mem_fun (*this, &PlugUIBase::latency_button_clicked
));
90 smaller_hbox
->pack_start (latency_button
, false, false, 10);
91 smaller_hbox
->pack_start (_preset_box
, false, false);
92 smaller_hbox
->pack_start (add_button
, false, false);
93 smaller_hbox
->pack_start (save_button
, false, false);
94 smaller_hbox
->pack_start (delete_button
, false, false);
95 smaller_hbox
->pack_start (bypass_button
, false, true);
97 constraint_hbox
->set_spacing (5);
98 constraint_hbox
->set_homogeneous (false);
100 VBox
* v1_box
= manage (new VBox
);
101 VBox
* v2_box
= manage (new VBox
);
102 pack_end (plugin_analysis_expander
, false, false);
104 v1_box
->pack_start (*smaller_hbox
, false, true);
105 v2_box
->pack_start (focus_button
, false, true);
107 main_contents
.pack_start (settings_box
, false, false);
109 constraint_hbox
->pack_end (*v2_box
, false, false);
110 constraint_hbox
->pack_end (*v1_box
, false, false);
112 main_contents
.pack_start (*constraint_hbox
, false, false);
114 if (is_scrollable
) {
115 scroller
.set_policy (Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
116 scroller
.set_name ("PluginEditor");
117 scroller_view
.set_name("PluginEditor");
118 scroller_view
.add (hpacker
);
119 scroller
.add (scroller_view
);
121 main_contents
.pack_start (scroller
, true, true);
124 main_contents
.pack_start (hpacker
, false, false);
127 pi
->ActiveChanged
.connect (active_connection
, invalidator (*this), boost::bind (&GenericPluginUI::processor_active_changed
, this, boost::weak_ptr
<Processor
>(pi
)), gui_context());
129 bypass_button
.set_active (!pi
->active());
135 GenericPluginUI::~GenericPluginUI ()
137 if (output_controls
.size() > 0) {
138 screen_update_connection
.disconnect();
142 // Some functions for calculating the 'similarity' of two plugin
145 static int get_number(string label
) {
146 static const char *digits
= "0123456789";
149 std::size_t first_digit_pos
= label
.find_first_of(digits
);
150 if (first_digit_pos
!= string::npos
) {
151 // found some digits: there's a number in there somewhere
153 s
<< label
.substr(first_digit_pos
);
159 static int match_or_digit(char c1
, char c2
) {
160 return c1
== c2
|| (isdigit(c1
) && isdigit(c2
));
163 static std::size_t matching_chars_at_head(const string s1
, const string s2
) {
164 std::size_t length
, n
= 0;
166 length
= min(s1
.length(), s2
.length());
168 if (!match_or_digit(s1
[n
], s2
[n
]))
175 static std::size_t matching_chars_at_tail(const string s1
, const string s2
) {
176 std::size_t s1pos
, s2pos
, n
= 0;
180 while (s1pos
-- > 0 && s2pos
-- > 0) {
181 if (!match_or_digit(s1
[s1pos
], s2
[s2pos
]) )
188 static const guint32 min_controls_per_column
= 17, max_controls_per_column
= 24;
189 static const float default_similarity_threshold
= 0.3;
192 GenericPluginUI::build ()
199 int output_row
, output_col
;
200 int button_row
, button_col
;
201 int output_rows
, output_cols
;
202 int button_rows
, button_cols
;
204 hpacker
.set_spacing (10);
206 output_rows
= initial_output_rows
;
207 output_cols
= initial_output_cols
;
208 button_rows
= initial_button_rows
;
209 button_cols
= initial_button_cols
;
215 button_table
.set_homogeneous (false);
216 button_table
.set_row_spacings (2);
217 button_table
.set_col_spacings (2);
218 output_table
.set_homogeneous (true);
219 output_table
.set_row_spacings (2);
220 output_table
.set_col_spacings (2);
221 button_table
.set_border_width (5);
222 output_table
.set_border_width (5);
224 hpacker
.set_border_width (10);
226 bt_frame
= manage (new Frame
);
227 bt_frame
->set_name ("BaseFrame");
228 bt_frame
->set_label (_("Switches"));
229 bt_frame
->add (button_table
);
230 hpacker
.pack_start(*bt_frame
, true, true);
232 box
= manage (new VBox
);
233 box
->set_border_width (5);
234 box
->set_spacing (1);
236 frame
= manage (new Frame
);
237 frame
->set_name ("BaseFrame");
238 frame
->set_label (_("Controls"));
240 hpacker
.pack_start(*frame
, true, true);
242 /* find all ports. build control elements for all appropriate control ports */
243 std::vector
<ControlUI
*> cui_controls_list
;
245 for (i
= 0; i
< plugin
->parameter_count(); ++i
) {
247 if (plugin
->parameter_is_control (i
)) {
249 /* Don't show latency control ports */
251 if (plugin
->describe_parameter (Evoral::Parameter(PluginAutomation
, 0, i
)) == X_("latency")) {
257 boost::shared_ptr
<ARDOUR::AutomationControl
> c
258 = boost::dynamic_pointer_cast
<ARDOUR::AutomationControl
>(
259 insert
->control(Evoral::Parameter(PluginAutomation
, 0, i
)));
261 if ((cui
= build_control_ui (i
, c
)) == 0) {
262 error
<< string_compose(_("Plugin Editor: could not build control element for port %1"), i
) << endmsg
;
266 if (cui
->controller
|| cui
->clickbox
|| cui
->combo
) {
267 // Get all of the controls into a list, so that
268 // we can lay them out a bit more nicely later.
269 cui_controls_list
.push_back(cui
);
270 } else if (cui
->button
) {
272 if (!is_scrollable
&& button_row
== button_rows
) {
274 if (++button_col
== button_cols
) {
276 button_table
.resize (button_rows
, button_cols
);
280 button_table
.attach (*cui
, button_col
, button_col
+ 1, button_row
, button_row
+1,
284 } else if (cui
->display
) {
286 output_table
.attach (*cui
, output_col
, output_col
+ 1, output_row
, output_row
+1,
289 // TODO: The meters should be divided into multiple rows
291 if (++output_col
== output_cols
) {
293 output_table
.resize (output_rows
, output_cols
);
299 // Iterate over the list of controls to find which adjacent controls
300 // are similar enough to be grouped together.
302 string label
, previous_label
= "";
303 int numbers_in_labels
[cui_controls_list
.size()];
305 float similarity_scores
[cui_controls_list
.size()];
306 float most_similar
= 0.0, least_similar
= 1.0;
309 for (vector
<ControlUI
*>::iterator cuip
= cui_controls_list
.begin(); cuip
!= cui_controls_list
.end(); ++cuip
, ++i
) {
310 label
= (*cuip
)->label
.get_text();
311 numbers_in_labels
[i
] = get_number(label
);
314 // A hand-wavy calculation of how similar this control's
315 // label is to the previous.
316 similarity_scores
[i
] =
318 ( matching_chars_at_head(label
, previous_label
) +
319 matching_chars_at_tail(label
, previous_label
) +
322 ) / (label
.length() + previous_label
.length());
323 if (numbers_in_labels
[i
] >= 0) {
324 similarity_scores
[i
] += (numbers_in_labels
[i
] == numbers_in_labels
[i
-1]);
326 least_similar
= min(least_similar
, similarity_scores
[i
]);
327 most_similar
= max(most_similar
, similarity_scores
[i
]);
329 similarity_scores
[0] = 1.0;
332 // cerr << "label: " << label << " sim: " << fixed << setprecision(3) << similarity_scores[i] << " num: " << numbers_in_labels[i] << endl;
333 previous_label
= label
;
337 // cerr << "most similar: " << most_similar << ", least similar: " << least_similar << endl;
338 float similarity_threshold
;
340 if (most_similar
> 1.0) {
341 similarity_threshold
= default_similarity_threshold
;
343 similarity_threshold
= most_similar
- (1 - default_similarity_threshold
);
346 // Now iterate over the list of controls to display them, placing an
347 // HSeparator between controls of less than a certain similarity, and
348 // starting a new column when necessary.
351 for (vector
<ControlUI
*>::iterator cuip
= cui_controls_list
.begin(); cuip
!= cui_controls_list
.end(); ++cuip
, ++i
) {
353 ControlUI
* cui
= *cuip
;
355 if (!is_scrollable
) {
359 if (x
> max_controls_per_column
|| similarity_scores
[i
] <= similarity_threshold
) {
360 if (x
> min_controls_per_column
) {
361 frame
= manage (new Frame
);
362 frame
->set_name ("BaseFrame");
363 frame
->set_label (_("Controls"));
364 box
= manage (new VBox
);
365 box
->set_border_width (5);
366 box
->set_spacing (1);
368 hpacker
.pack_start(*frame
, true, true);
371 HSeparator
*split
= new HSeparator();
372 split
->set_size_request(-1, 5);
373 box
->pack_start(*split
, false, false, 0);
377 box
->pack_start (*cui
, false, false);
384 if (box
->children().empty()) {
385 hpacker
.remove (*frame
);
388 if (button_table
.children().empty()) {
389 hpacker
.remove (*bt_frame
);
392 if (!output_table
.children().empty()) {
393 frame
= manage (new Frame
);
394 frame
->set_name ("BaseFrame");
395 frame
->set_label(_("Meters"));
396 frame
->add (output_table
);
397 hpacker
.pack_end (*frame
, true, true);
402 output_table
.show_all ();
403 button_table
.show_all ();
406 GenericPluginUI::ControlUI::ControlUI ()
407 : automate_button (X_("")) // force creation of a label
409 automate_button
.set_name ("PluginAutomateButton");
410 ARDOUR_UI::instance()->set_tip (automate_button
, _("Automation control"));
412 /* XXX translators: use a string here that will be at least as long
413 as the longest automation label (see ::automation_state_changed()
414 below). be sure to include a descender.
417 set_size_request_to_display_given_text (automate_button
, _("Mgnual"), 15, 10);
426 GenericPluginUI::ControlUI::~ControlUI()
429 delete meterinfo
->meter
;
435 GenericPluginUI::automation_state_changed (ControlUI
* cui
)
437 /* update button label */
439 // don't lock to avoid deadlock because we're triggered by
440 // AutomationControl::Changed() while the automation lock is taken
441 switch (insert
->get_parameter_automation_state (cui
->parameter())
442 & (Off
|Play
|Touch
|Write
)) {
444 cui
->automate_button
.set_label (_("Manual"));
447 cui
->automate_button
.set_label (_("Play"));
450 cui
->automate_button
.set_label (_("Write"));
453 cui
->automate_button
.set_label (_("Touch"));
456 cui
->automate_button
.set_label (_("???"));
462 static void integer_printer (char buf
[32], Adjustment
&adj
, void */
*arg*/
)
464 snprintf (buf
, 32, "%.0f", adj
.get_value());
468 GenericPluginUI::print_parameter (char *buf
, uint32_t len
, uint32_t param
)
470 plugin
->print_parameter (param
, buf
, len
);
473 GenericPluginUI::ControlUI
*
474 GenericPluginUI::build_control_ui (guint32 port_index
, boost::shared_ptr
<AutomationControl
> mcontrol
)
476 ControlUI
* control_ui
= 0;
478 Plugin::ParameterDescriptor desc
;
480 plugin
->get_parameter_descriptor (port_index
, desc
);
482 control_ui
= manage (new ControlUI ());
483 control_ui
->combo
= 0;
484 control_ui
->combo_map
= 0;
485 control_ui
->control
= mcontrol
;
486 control_ui
->update_pending
= false;
487 control_ui
->label
.set_text (desc
.label
);
488 control_ui
->label
.set_alignment (0.0, 0.5);
489 control_ui
->label
.set_name ("PluginParameterLabel");
490 control_ui
->port_index
= port_index
;
492 control_ui
->set_spacing (5);
494 Gtk::Requisition
req (control_ui
->automate_button
.size_request());
496 if (plugin
->parameter_is_input(port_index
)) {
498 /* Build a combo box */
500 boost::shared_ptr
<ARDOUR::Plugin::ScalePoints
> points
501 = plugin
->get_scale_points(port_index
);
504 std::vector
<std::string
> labels
;
505 for (ARDOUR::Plugin::ScalePoints::const_iterator i
= points
->begin();
506 i
!= points
->end(); ++i
) {
507 labels
.push_back(i
->first
);
510 control_ui
->combo
= new Gtk::ComboBoxText();
511 set_popdown_strings(*control_ui
->combo
, labels
);
512 control_ui
->combo
->signal_changed().connect(
513 sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed
),
515 mcontrol
->Changed
.connect(control_connections
, invalidator(*this),
516 boost::bind(&GenericPluginUI::ui_parameter_changed
,
519 control_ui
->pack_start(control_ui
->label
, true, true);
520 control_ui
->pack_start(*control_ui
->combo
, false, true);
522 update_control_display(control_ui
);
531 control_ui
->button
= manage (new ToggleButton ());
532 control_ui
->button
->set_name ("PluginEditorButton");
533 control_ui
->button
->set_size_request (20, 20);
535 control_ui
->pack_start (control_ui
->label
, true, true);
536 control_ui
->pack_start (*control_ui
->button
, false, true);
537 control_ui
->pack_start (control_ui
->automate_button
, false, false);
539 control_ui
->button
->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_port_toggled
), control_ui
));
540 control_ui
->automate_button
.signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::astate_clicked
), control_ui
, (uint32_t) port_index
));
542 mcontrol
->Changed
.connect (control_connections
, invalidator (*this), boost::bind (&GenericPluginUI::toggle_parameter_changed
, this, control_ui
), gui_context());
543 mcontrol
->alist()->automation_state_changed
.connect (control_connections
, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed
, this, control_ui
), gui_context());
545 if (plugin
->get_parameter (port_index
) > 0.5){
546 control_ui
->button
->set_active(true);
549 automation_state_changed (control_ui
);
554 /* create the controller */
557 control_ui
->controller
= AutomationController::create(insert
, mcontrol
->parameter(), mcontrol
);
560 /* XXX this code is not right yet, because it doesn't handle
561 the absence of bounds in any sensible fashion.
564 Adjustment
* adj
= control_ui
->controller
->adjustment();
565 boost::shared_ptr
<PluginInsert::PluginControl
> pc
= boost::dynamic_pointer_cast
<PluginInsert::PluginControl
> (control_ui
->control
);
567 adj
->set_lower (pc
->user_to_ui (desc
.lower
));
568 adj
->set_upper (pc
->user_to_ui (desc
.upper
));
570 adj
->set_step_increment (desc
.step
);
571 adj
->set_page_increment (desc
.largestep
);
573 if (desc
.integer_step
) {
574 control_ui
->clickbox
= new ClickBox (adj
, "PluginUIClickBox");
575 Gtkmm2ext::set_size_request_to_display_given_text (*control_ui
->clickbox
, "g9999999", 2, 2);
576 control_ui
->clickbox
->set_print_func (integer_printer
, 0);
578 //sigc::slot<void,char*,uint32_t> pslot = sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::print_parameter), (uint32_t) port_index);
580 control_ui
->controller
->set_size_request (200, req
.height
);
581 control_ui
->controller
->set_name (X_("PluginSlider"));
582 control_ui
->controller
->set_style (BarController::LeftToRight
);
583 control_ui
->controller
->set_use_parent (true);
584 control_ui
->controller
->set_logarithmic (desc
.logarithmic
);
586 control_ui
->controller
->StartGesture
.connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::start_touch
), control_ui
));
587 control_ui
->controller
->StopGesture
.connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::stop_touch
), control_ui
));
591 adj
->set_value (pc
->plugin_to_ui (plugin
->get_parameter (port_index
)));
593 /* XXX memory leak: SliderController not destroyed by ControlUI
594 destructor, and manage() reports object hierarchy
598 control_ui
->pack_start (control_ui
->label
, true, true);
599 if (desc
.integer_step
) {
600 control_ui
->pack_start (*control_ui
->clickbox
, false, false);
602 control_ui
->pack_start (*control_ui
->controller
, false, false);
605 control_ui
->pack_start (control_ui
->automate_button
, false, false);
606 control_ui
->automate_button
.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::astate_clicked
), control_ui
, (uint32_t) port_index
));
608 automation_state_changed (control_ui
);
610 mcontrol
->Changed
.connect (control_connections
, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed
, this, control_ui
), gui_context());
611 mcontrol
->alist()->automation_state_changed
.connect (control_connections
, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed
, this, control_ui
), gui_context());
613 input_controls
.push_back (control_ui
);
615 } else if (plugin
->parameter_is_output (port_index
)) {
617 control_ui
->display
= manage (new EventBox
);
618 control_ui
->display
->set_name ("ParameterValueDisplay");
620 control_ui
->display_label
= manage (new Label
);
622 control_ui
->display_label
->set_name ("ParameterValueDisplay");
624 control_ui
->display
->add (*control_ui
->display_label
);
625 Gtkmm2ext::set_size_request_to_display_given_text (*control_ui
->display
, "-99,99", 2, 2);
627 control_ui
->display
->show_all ();
630 /* TODO: only make a meter if the port is Hinted for it */
632 MeterInfo
* info
= new MeterInfo(port_index
);
633 control_ui
->meterinfo
= info
;
635 info
->meter
= new FastMeter (5, 5, FastMeter::Vertical
);
637 info
->min_unbound
= desc
.min_unbound
;
638 info
->max_unbound
= desc
.max_unbound
;
640 info
->min
= desc
.lower
;
641 info
->max
= desc
.upper
;
643 control_ui
->vbox
= manage (new VBox
);
644 control_ui
->hbox
= manage (new HBox
);
646 control_ui
->label
.set_angle(90);
647 control_ui
->hbox
->pack_start (control_ui
->label
, false, false);
648 control_ui
->hbox
->pack_start (*info
->meter
, false, false);
650 control_ui
->vbox
->pack_start (*control_ui
->hbox
, false, false);
652 control_ui
->vbox
->pack_start (*control_ui
->display
, false, false);
654 control_ui
->pack_start (*control_ui
->vbox
);
656 control_ui
->meterinfo
->meter
->show_all();
657 control_ui
->meterinfo
->packed
= true;
659 output_controls
.push_back (control_ui
);
663 mcontrol
->Changed
.connect (control_connections
, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed
, this, control_ui
), gui_context());
670 GenericPluginUI::start_touch (GenericPluginUI::ControlUI
* cui
)
672 cui
->control
->start_touch (cui
->control
->session().transport_frame());
676 GenericPluginUI::stop_touch (GenericPluginUI::ControlUI
* cui
)
678 cui
->control
->stop_touch (false, cui
->control
->session().transport_frame());
682 GenericPluginUI::astate_clicked (ControlUI
* cui
, uint32_t /*port*/)
684 using namespace Menu_Helpers
;
686 if (automation_menu
== 0) {
687 automation_menu
= manage (new Menu
);
688 automation_menu
->set_name ("ArdourContextMenu");
691 MenuList
& items (automation_menu
->items());
694 items
.push_back (MenuElem (_("Manual"),
695 sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state
), (AutoState
) Off
, cui
)));
696 items
.push_back (MenuElem (_("Play"),
697 sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state
), (AutoState
) Play
, cui
)));
698 items
.push_back (MenuElem (_("Write"),
699 sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state
), (AutoState
) Write
, cui
)));
700 items
.push_back (MenuElem (_("Touch"),
701 sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state
), (AutoState
) Touch
, cui
)));
703 automation_menu
->popup (1, gtk_get_current_event_time());
707 GenericPluginUI::set_automation_state (AutoState state
, ControlUI
* cui
)
709 insert
->set_parameter_automation_state (cui
->parameter(), state
);
713 GenericPluginUI::toggle_parameter_changed (ControlUI
* cui
)
715 float val
= cui
->control
->get_value();
717 if (!cui
->ignore_change
) {
719 cui
->button
->set_active (true);
721 cui
->button
->set_active (false);
727 GenericPluginUI::ui_parameter_changed (ControlUI
* cui
)
729 if (!cui
->update_pending
) {
730 cui
->update_pending
= true;
731 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR
, boost::bind (&GenericPluginUI::update_control_display
, this, cui
));
736 GenericPluginUI::update_control_display (ControlUI
* cui
)
738 /* XXX how do we handle logarithmic stuff here ? */
740 cui
->update_pending
= false;
742 float val
= cui
->control
->get_value();
744 cui
->ignore_change
++;
746 if (cui
->combo
&& cui
->combo_map
) {
747 std::map
<string
,float>::iterator it
;
748 for (it
= cui
->combo_map
->begin(); it
!= cui
->combo_map
->end(); ++it
) {
749 if (it
->second
== val
) {
750 cui
->combo
->set_active_text(it
->first
);
754 } else if (cui
->button
) {
757 cui
->button
->set_active (true);
759 cui
->button
->set_active (false);
763 if( cui
->controller
) {
764 cui
->controller
->display_effective_value();
769 if (cui->logarithmic) {
772 if (val != cui->adjustment->get_value()) {
773 cui->adjustment->set_value (val);
776 cui
->ignore_change
--;
780 GenericPluginUI::control_port_toggled (ControlUI
* cui
)
782 cui
->ignore_change
++;
783 insert
->automation_control (cui
->parameter())->set_value (cui
->button
->get_active());
784 cui
->ignore_change
--;
788 GenericPluginUI::control_combo_changed (ControlUI
* cui
)
790 if (!cui
->ignore_change
&& cui
->combo_map
) {
791 string value
= cui
->combo
->get_active_text();
792 std::map
<string
,float> mapping
= *cui
->combo_map
;
793 insert
->automation_control(cui
->parameter())->set_value(mapping
[value
]);
798 GenericPluginUI::processor_active_changed (boost::weak_ptr
<Processor
> weak_processor
)
800 ENSURE_GUI_THREAD (*this, &GenericPluginUI::processor_active_changed
, weak_processor
)
802 boost::shared_ptr
<Processor
> processor
= weak_processor
.lock();
804 bypass_button
.set_active (!processor
|| !processor
->active());
808 GenericPluginUI::start_updating (GdkEventAny
*)
810 if (output_controls
.size() > 0 ) {
811 screen_update_connection
.disconnect();
812 screen_update_connection
= ARDOUR_UI::instance()->RapidScreenUpdate
.connect
813 (sigc::mem_fun(*this, &GenericPluginUI::output_update
));
819 GenericPluginUI::stop_updating (GdkEventAny
*)
821 for (vector
<ControlUI
*>::iterator i
= input_controls
.begin(); i
!= input_controls
.end(); ++i
) {
822 (*i
)->controller
->stop_updating ();
825 if (output_controls
.size() > 0 ) {
826 screen_update_connection
.disconnect();
833 GenericPluginUI::output_update ()
835 for (vector
<ControlUI
*>::iterator i
= output_controls
.begin(); i
!= output_controls
.end(); ++i
) {
836 float val
= plugin
->get_parameter ((*i
)->port_index
);
838 snprintf (buf
, sizeof(buf
), "%.2f", val
);
839 (*i
)->display_label
->set_text (buf
);
841 /* autoscaling for the meter */
842 if ((*i
)->meterinfo
&& (*i
)->meterinfo
->packed
) {
844 if (val
< (*i
)->meterinfo
->min
) {
845 if ((*i
)->meterinfo
->min_unbound
)
846 (*i
)->meterinfo
->min
= val
;
848 val
= (*i
)->meterinfo
->min
;
851 if (val
> (*i
)->meterinfo
->max
) {
852 if ((*i
)->meterinfo
->max_unbound
)
853 (*i
)->meterinfo
->max
= val
;
855 val
= (*i
)->meterinfo
->max
;
858 if ((*i
)->meterinfo
->max
> (*i
)->meterinfo
->min
) {
859 float lval
= (val
- (*i
)->meterinfo
->min
) / ((*i
)->meterinfo
->max
- (*i
)->meterinfo
->min
) ;
860 (*i
)->meterinfo
->meter
->set (lval
);