X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fgeneric_pluginui.cc;h=971dfc0e9ba7638426afa281f1808b6607d3973f;hb=d1f45e9b3d6a7e272e5563cc50175dfb6d904361;hp=842fc15cdb66369e6100c18364f7c7b957db46ac;hpb=54d9f2f2d83af1f0f44579fe2ebf090e68259938;p=ardour.git diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 842fc15cdb..971dfc0e9b 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +17,10 @@ */ +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif + #include #include #include @@ -37,10 +41,7 @@ #include "ardour/plugin.h" #include "ardour/plugin_insert.h" -#include "ardour/ladspa_plugin.h" -#ifdef HAVE_LV2 -#include "ardour/lv2_plugin.h" -#endif +#include "ardour/session.h" #include @@ -58,7 +59,6 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtkmm2ext; using namespace Gtk; -using namespace sigc; GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrollable) : PlugUIBase (pi), @@ -74,30 +74,36 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol set_border_width (10); //set_homogeneous (false); - pack1(main_contents); + pack_start (main_contents, true, true); settings_box.set_homogeneous (false); HBox* constraint_hbox = manage (new HBox); HBox* smaller_hbox = manage (new HBox); + smaller_hbox->set_spacing (4); Label* combo_label = manage (new Label (_("Presets"))); combo_label->set_use_markup (true); - Label* latency_label = manage (new Label (_("Latency"))); - latency_label->set_use_markup (true); + latency_button.add (latency_label); + latency_button.signal_clicked().connect (sigc::mem_fun (*this, &PlugUIBase::latency_button_clicked)); + set_latency_label (); - smaller_hbox->pack_start (*latency_label, false, false, 10); - smaller_hbox->pack_start (latency_gui, false, false, 10); - smaller_hbox->pack_start (preset_combo, false, false); + smaller_hbox->pack_start (latency_button, false, false, 10); + smaller_hbox->pack_start (_preset_combo, false, false); + smaller_hbox->pack_start (_preset_modified, false, false); + smaller_hbox->pack_start (add_button, false, false); smaller_hbox->pack_start (save_button, false, false); + smaller_hbox->pack_start (delete_button, false, false); smaller_hbox->pack_start (bypass_button, false, true); constraint_hbox->set_spacing (5); constraint_hbox->set_homogeneous (false); - + VBox* v1_box = manage (new VBox); VBox* v2_box = manage (new VBox); - constraint_hbox->pack_start (eqgui_toggle, false, false); - add2(plugin_eq_bin); + pack_end (plugin_analysis_expander, false, false); + if (!plugin->get_docs().empty()) { + pack_end (description_expander, false, false); + } v1_box->pack_start (*smaller_hbox, false, true); v2_box->pack_start (focus_button, false, true); @@ -108,26 +114,25 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol constraint_hbox->pack_end (*v1_box, false, false); main_contents.pack_start (*constraint_hbox, false, false); - - if ( is_scrollable ) { - scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + + if (is_scrollable ) { + scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); scroller.set_name ("PluginEditor"); scroller_view.set_name("PluginEditor"); scroller_view.add (hpacker); scroller.add (scroller_view); - + main_contents.pack_start (scroller, true, true); - } - else { + } else { main_contents.pack_start (hpacker, false, false); } - pi->ActiveChanged.connect (bind(mem_fun(*this, &GenericPluginUI::processor_active_changed), - boost::weak_ptr(pi))); - + pi->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&GenericPluginUI::processor_active_changed, this, boost::weak_ptr(pi)), gui_context()); + bypass_button.set_active (!pi->active()); + prefheight = 0; build (); } @@ -138,9 +143,57 @@ GenericPluginUI::~GenericPluginUI () } } +// Some functions for calculating the 'similarity' of two plugin +// control labels. + +static int get_number(string label) { +static const char *digits = "0123456789"; +int value = -1; + + std::size_t first_digit_pos = label.find_first_of(digits); + if (first_digit_pos != string::npos) { + // found some digits: there's a number in there somewhere + stringstream s; + s << label.substr(first_digit_pos); + s >> value; + } + return value; +} + +static int match_or_digit(char c1, char c2) { + return c1 == c2 || (isdigit(c1) && isdigit(c2)); +} + +static std::size_t matching_chars_at_head(const string s1, const string s2) { +std::size_t length, n = 0; + + length = min(s1.length(), s2.length()); + while (n < length) { + if (!match_or_digit(s1[n], s2[n])) + break; + n++; + } + return n; +} + +static std::size_t matching_chars_at_tail(const string s1, const string s2) { +std::size_t s1pos, s2pos, n = 0; + + s1pos = s1.length(); + s2pos = s2.length(); + while (s1pos-- > 0 && s2pos-- > 0) { + if (!match_or_digit(s1[s1pos], s2[s2pos]) ) + break; + n++; + } + return n; +} + +static const guint32 min_controls_per_column = 17, max_controls_per_column = 24; +static const float default_similarity_threshold = 0.3; + void GenericPluginUI::build () - { guint32 i = 0; guint32 x = 0; @@ -152,7 +205,6 @@ GenericPluginUI::build () int output_rows, output_cols; int button_rows, button_cols; - prefheight = 30; hpacker.set_spacing (10); output_rows = initial_output_rows; @@ -177,6 +229,7 @@ GenericPluginUI::build () bt_frame = manage (new Frame); bt_frame->set_name ("BaseFrame"); + bt_frame->set_label (_("Switches")); bt_frame->add (button_table); hpacker.pack_start(*bt_frame, true, true); @@ -191,53 +244,45 @@ GenericPluginUI::build () hpacker.pack_start(*frame, true, true); /* find all ports. build control elements for all appropriate control ports */ + std::vector cui_controls_list; for (i = 0; i < plugin->parameter_count(); ++i) { if (plugin->parameter_is_control (i)) { - + /* Don't show latency control ports */ if (plugin->describe_parameter (Evoral::Parameter(PluginAutomation, 0, i)) == X_("latency")) { continue; } - ControlUI* cui; - - /* if we are scrollable, just use one long column */ - - if (!is_scrollable) { - if (x++ > 20){ - frame = manage (new Frame); - frame->set_name ("BaseFrame"); - box = manage (new VBox); - - box->set_border_width (5); - box->set_spacing (1); - - frame->add (*box); - hpacker.pack_start(*frame,true,true); - - x = 1; - } + if (plugin->describe_parameter (Evoral::Parameter(PluginAutomation, 0, i)) == X_("hidden")) { + continue; } + ControlUI* cui; + boost::shared_ptr c = boost::dynamic_pointer_cast( - insert->data().control(Evoral::Parameter(PluginAutomation, 0, i))); + insert->control(Evoral::Parameter(PluginAutomation, 0, i))); if ((cui = build_control_ui (i, c)) == 0) { error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg; continue; } - - if (cui->controller || cui->clickbox || cui->combo) { - box->pack_start (*cui, false, false); + const std::string param_docs = plugin->get_parameter_docs(i); + if (!param_docs.empty()) { + ARDOUR_UI::instance()->set_tip(cui, param_docs.c_str()); + } + if (cui->controller || cui->clickbox || cui->combo) { + // Get all of the controls into a list, so that + // we can lay them out a bit more nicely later. + cui_controls_list.push_back(cui); } else if (cui->button) { - if (button_row == button_rows) { + if (!is_scrollable && button_row == button_rows) { button_row = 0; if (++button_col == button_cols) { button_cols += 2; @@ -245,48 +290,108 @@ GenericPluginUI::build () } } - button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1, + button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1, FILL|EXPAND, FILL); button_row++; } else if (cui->display) { - output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, + output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, FILL|EXPAND, FILL); - - // TODO: The meters should be divided into multiple rows - + + // TODO: The meters should be divided into multiple rows + if (++output_col == output_cols) { output_cols ++; output_table.resize (output_rows, output_cols); } - - /* old code, which divides meters into - * columns first, rows later. New code divides into one row - - if (output_row == output_rows) { - output_row = 0; - if (++output_col == output_cols) { - output_cols += 2; - output_table.resize (output_rows, output_cols); - } - } - - output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, - FILL|EXPAND, FILL); - - output_row++; - */ } - - /* HACK: ideally the preferred height would be queried from - the complete hpacker, but I can't seem to get that - information in time, so this is an estimation - */ + } + } - prefheight += 30; + // Iterate over the list of controls to find which adjacent controls + // are similar enough to be grouped together. + + string label, previous_label = ""; + int numbers_in_labels[cui_controls_list.size()]; + + float similarity_scores[cui_controls_list.size()]; + float most_similar = 0.0, least_similar = 1.0; + + i = 0; + for (vector::iterator cuip = cui_controls_list.begin(); cuip != cui_controls_list.end(); ++cuip, ++i) { + label = (*cuip)->label.get_text(); + numbers_in_labels[i] = get_number(label); + + if (i > 0) { + // A hand-wavy calculation of how similar this control's + // label is to the previous. + similarity_scores[i] = + (float) ( + ( matching_chars_at_head(label, previous_label) + + matching_chars_at_tail(label, previous_label) + + 1 + ) + ) / (label.length() + previous_label.length()); + if (numbers_in_labels[i] >= 0) { + similarity_scores[i] += (numbers_in_labels[i] == numbers_in_labels[i-1]); + } + least_similar = min(least_similar, similarity_scores[i]); + most_similar = max(most_similar, similarity_scores[i]); + } else { + similarity_scores[0] = 1.0; + } - } + // cerr << "label: " << label << " sim: " << fixed << setprecision(3) << similarity_scores[i] << " num: " << numbers_in_labels[i] << endl; + previous_label = label; + } + + + // cerr << "most similar: " << most_similar << ", least similar: " << least_similar << endl; + float similarity_threshold; + + if (most_similar > 1.0) { + similarity_threshold = default_similarity_threshold; + } else { + similarity_threshold = most_similar - (1 - default_similarity_threshold); + } + + // Now iterate over the list of controls to display them, placing an + // HSeparator between controls of less than a certain similarity, and + // starting a new column when necessary. + + i = 0; + for (vector::iterator cuip = cui_controls_list.begin(); cuip != cui_controls_list.end(); ++cuip, ++i) { + + ControlUI* cui = *cuip; + + if (!is_scrollable) { + x++; + } + + if (x > max_controls_per_column || similarity_scores[i] <= similarity_threshold) { + if (x > min_controls_per_column) { + frame = manage (new Frame); + frame->set_name ("BaseFrame"); + frame->set_label (_("Controls")); + box = manage (new VBox); + box->set_border_width (5); + box->set_spacing (1); + frame->add (*box); + hpacker.pack_start(*frame, true, true); + x = 0; + } else { + HSeparator *split = new HSeparator(); + split->set_size_request(-1, 5); + box->pack_start(*split, false, false, 0); + } + + } + box->pack_start (*cui, false, false); + } + + if (is_scrollable) { + prefheight = 30 * i; } if (box->children().empty()) { @@ -300,6 +405,7 @@ GenericPluginUI::build () if (!output_table.children().empty()) { frame = manage (new Frame); frame->set_name ("BaseFrame"); + frame->set_label(_("Meters")); frame->add (output_table); hpacker.pack_end (*frame, true, true); } @@ -311,17 +417,17 @@ GenericPluginUI::build () } GenericPluginUI::ControlUI::ControlUI () - : automate_button (X_("")) // force creation of a label + : automate_button (X_("")) // force creation of a label { automate_button.set_name ("PluginAutomateButton"); - ARDOUR_UI::instance()->tooltips().set_tip (automate_button, _("Automation control")); + ARDOUR_UI::instance()->set_tip (automate_button, _("Automation control")); /* XXX translators: use a string here that will be at least as long as the longest automation label (see ::automation_state_changed() below). be sure to include a descender. */ - set_size_request_to_display_given_text (*automate_button.get_child(), _("Mgnual"), 5, 5); + set_size_request_to_display_given_text (automate_button, _("Mgnual"), 15, 10); ignore_change = 0; display = 0; @@ -330,7 +436,7 @@ GenericPluginUI::ControlUI::ControlUI () meterinfo = 0; } -GenericPluginUI::ControlUI::~ControlUI() +GenericPluginUI::ControlUI::~ControlUI() { if (meterinfo) { delete meterinfo->meter; @@ -345,10 +451,9 @@ GenericPluginUI::automation_state_changed (ControlUI* cui) // don't lock to avoid deadlock because we're triggered by // AutomationControl::Changed() while the automation lock is taken - switch (insert->get_parameter_automation_state (cui->parameter(), false) - & (Off|Play|Touch|Write)) { - case Off: - cui->automate_button.set_label (_("Manual")); + switch (insert->get_parameter_automation_state (cui->parameter()) & (ARDOUR::Off|Play|Touch|Write)) { + case ARDOUR::Off: + cui->automate_button.set_label (S_("Automation|Manual")); break; case Play: cui->automate_button.set_label (_("Play")); @@ -366,9 +471,25 @@ GenericPluginUI::automation_state_changed (ControlUI* cui) } -static void integer_printer (char buf[32], Adjustment &adj, void *arg) +bool +GenericPluginUI::integer_printer (char buf[32], Adjustment &adj, ControlUI* cui) { - snprintf (buf, 32, "%.0f", adj.get_value()); + float const v = adj.get_value (); + + if (cui->scale_points) { + Plugin::ScalePoints::const_iterator i = cui->scale_points->begin (); + while (i != cui->scale_points->end() && i->second != v) { + ++i; + } + + if (i != cui->scale_points->end ()) { + snprintf (buf, 32, "%s", i->first.c_str()); + return true; + } + } + + snprintf (buf, 32, "%.0f", v); + return true; } void @@ -380,9 +501,7 @@ GenericPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param) GenericPluginUI::ControlUI* GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr mcontrol) { - ControlUI* control_ui = NULL; - if (!mcontrol) - return control_ui; + ControlUI* control_ui = 0; Plugin::ParameterDescriptor desc; @@ -390,140 +509,126 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcombo = 0; - control_ui->combo_map = 0; control_ui->control = mcontrol; control_ui->update_pending = false; control_ui->label.set_text (desc.label); control_ui->label.set_alignment (0.0, 0.5); control_ui->label.set_name ("PluginParameterLabel"); + control_ui->port_index = port_index; control_ui->set_spacing (5); Gtk::Requisition req (control_ui->automate_button.size_request()); - if (plugin->parameter_is_input (port_index)) { + if (plugin->parameter_is_input(port_index)) { - boost::shared_ptr lp; -#ifdef HAVE_LV2 - boost::shared_ptr lv2p; -#endif - if ((lp = boost::dynamic_pointer_cast(plugin)) != 0) { - - // FIXME: not all plugins have a numeric unique ID - uint32_t id = atol (lp->unique_id().c_str()); - lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index); + /* See if there any named values for our input value */ + control_ui->scale_points = plugin->get_scale_points (port_index); + + /* If this parameter is an integer, work out the number of distinct values + it can take on (assuming that lower and upper values are allowed). + */ + int const steps = desc.integer_step ? (desc.upper - desc.lower + 1) / desc.step : 0; + + if (control_ui->scale_points && ((steps && int (control_ui->scale_points->size()) == steps) || desc.enumeration)) { - if (defaults && defaults->count > 0) { - - control_ui->combo = new Gtk::ComboBoxText; - //control_ui->combo->set_value_in_list(true, false); - set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); - control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui)); - control_ui->pack_start(control_ui->label, true, true); - control_ui->pack_start(*control_ui->combo, false, true); + /* Either: + * a) There is a label for each possible value of this input, or + * b) This port is marked as being an enumeration. + */ + + std::vector labels; + for ( + ARDOUR::Plugin::ScalePoints::const_iterator i = control_ui->scale_points->begin(); + i != control_ui->scale_points->end(); + ++i) { - update_control_display(control_ui); - - lrdf_free_setting_values(defaults); - return control_ui; + labels.push_back(i->first); } -#ifdef HAVE_LV2 - } else if ((lv2p = boost::dynamic_pointer_cast(plugin)) != 0) { + control_ui->combo = new Gtk::ComboBoxText(); + set_popdown_strings(*control_ui->combo, labels); + control_ui->combo->signal_changed().connect( + sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed), + control_ui)); + mcontrol->Changed.connect(control_connections, invalidator(*this), + boost::bind(&GenericPluginUI::ui_parameter_changed, + this, control_ui), + gui_context()); + control_ui->pack_start(control_ui->label, true, true); + control_ui->pack_start(*control_ui->combo, false, true); - SLV2Port port = lv2p->slv2_port(port_index); - SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port); + update_control_display(control_ui); - if (points) { - control_ui->combo = new Gtk::ComboBoxText; - //control_ui->combo->set_value_in_list(true, false); - set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); - control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui)); - control_ui->pack_start(control_ui->label, true, true); - control_ui->pack_start(*control_ui->combo, false, true); - - update_control_display(control_ui); - - slv2_scale_points_free(points); - return control_ui; - } -#endif + return control_ui; } - + if (desc.toggled) { /* Build a button */ - + control_ui->button = manage (new ToggleButton ()); control_ui->button->set_name ("PluginEditorButton"); control_ui->button->set_size_request (20, 20); control_ui->pack_start (control_ui->label, true, true); control_ui->pack_start (*control_ui->button, false, true); - // control_ui->pack_start (control_ui->automate_button, false, false); + control_ui->pack_start (control_ui->automate_button, false, false); + + control_ui->button->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_port_toggled), control_ui)); + control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::astate_clicked), control_ui, (uint32_t) port_index)); + + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::toggle_parameter_changed, this, control_ui), gui_context()); + mcontrol->alist()->automation_state_changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed, this, control_ui), gui_context()); - control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::control_port_toggled), control_ui)); - mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::toggle_parameter_changed), control_ui)); - if (plugin->get_parameter (port_index) > 0.5){ control_ui->button->set_active(true); } - + + automation_state_changed (control_ui); + return control_ui; } /* create the controller */ - control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), mcontrol); + if (mcontrol) { + control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), mcontrol); + } + /* XXX this code is not right yet, because it doesn't handle the absence of bounds in any sensible fashion. */ -//#if 0 - control_ui->controller->adjustment()->set_lower (desc.lower); - control_ui->controller->adjustment()->set_upper (desc.upper); + Adjustment* adj = control_ui->controller->adjustment(); + boost::shared_ptr pc = boost::dynamic_pointer_cast (control_ui->control); - control_ui->logarithmic = false; // just disable it for now - /* - control_ui->logarithmic = desc.logarithmic; - if (control_ui->logarithmic) { - if (control_ui->controller->adjustment()->get_lower() == 0.0) { - control_ui->controller->adjustment()->set_lower (control_ui->controller->adjustment()->get_upper()/10000); - } - control_ui->controller->adjustment()->set_upper (log(control_ui->controller->adjustment()->get_upper())); - control_ui->controller->adjustment()->set_lower (log(control_ui->controller->adjustment()->get_lower())); - }*/ - - - control_ui->controller->adjustment()->set_step_increment (desc.step); - control_ui->controller->adjustment()->set_page_increment (desc.largestep); -//#endif + adj->set_lower (pc->internal_to_interface (desc.lower)); + adj->set_upper (pc->internal_to_interface (desc.upper)); + + adj->set_step_increment (desc.step); + adj->set_page_increment (desc.largestep); if (desc.integer_step) { - control_ui->clickbox = new ClickBox (control_ui->controller->adjustment(), "PluginUIClickBox"); + control_ui->clickbox = new ClickBox (adj, "PluginUIClickBox"); Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2); - control_ui->clickbox->set_print_func (integer_printer, 0); + control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::integer_printer), control_ui)); } else { - //sigc::slot pslot = sigc::bind (mem_fun(*this, &GenericPluginUI::print_parameter), (uint32_t) port_index); + //sigc::slot pslot = sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::print_parameter), (uint32_t) port_index); control_ui->controller->set_size_request (200, req.height); control_ui->controller->set_name (X_("PluginSlider")); control_ui->controller->set_style (BarController::LeftToRight); control_ui->controller->set_use_parent (true); + control_ui->controller->set_logarithmic (desc.logarithmic); - control_ui->controller->StartGesture.connect (bind (mem_fun(*this, &GenericPluginUI::start_touch), control_ui)); - control_ui->controller->StopGesture.connect (bind (mem_fun(*this, &GenericPluginUI::stop_touch), control_ui)); - - } + control_ui->controller->StartGesture.connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::start_touch), control_ui)); + control_ui->controller->StopGesture.connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::stop_touch), control_ui)); - if (control_ui->logarithmic) { - control_ui->controller->adjustment()->set_value(log(plugin->get_parameter(port_index))); - } else{ - control_ui->controller->adjustment()->set_value(plugin->get_parameter(port_index)); } + adj->set_value (pc->internal_to_interface (plugin->get_parameter (port_index))); + /* XXX memory leak: SliderController not destroyed by ControlUI destructor, and manage() reports object hierarchy ambiguity. @@ -537,13 +642,14 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrpack_start (control_ui->automate_button, false, false); - control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &GenericPluginUI::astate_clicked), control_ui, (uint32_t) port_index)); + control_ui->automate_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::astate_clicked), control_ui, (uint32_t) port_index)); automation_state_changed (control_ui); - mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui)); - mcontrol->alist()->automation_state_changed.connect - (bind (mem_fun(*this, &GenericPluginUI::automation_state_changed), control_ui)); + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); + mcontrol->alist()->automation_state_changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed, this, control_ui), gui_context()); + + input_controls.push_back (control_ui); } else if (plugin->parameter_is_output (port_index)) { @@ -555,7 +661,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrdisplay_label->set_name ("ParameterValueDisplay"); control_ui->display->add (*control_ui->display_label); - Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->display, "-99,99", 2, 2); + Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->display, "-888.8g", 2, 6); control_ui->display->show_all (); @@ -564,8 +670,18 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrmeterinfo = info; - - info->meter = new FastMeter (5, 5, FastMeter::Vertical); + + info->meter = new FastMeter ( + 5, 5, FastMeter::Vertical, 0, + 0x0000aaff, + 0x008800ff, 0x008800ff, + 0x00ff00ff, 0x00ff00ff, + 0xcccc00ff, 0xcccc00ff, + 0xffaa00ff, 0xffaa00ff, + 0xff0000ff, + ARDOUR_UI::config()->canvasvar_MeterBackgroundBot.get(), + ARDOUR_UI::config()->canvasvar_MeterBackgroundTop.get() + ); info->min_unbound = desc.min_unbound; info->max_unbound = desc.max_unbound; @@ -575,61 +691,66 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrvbox = manage (new VBox); control_ui->hbox = manage (new HBox); - + + control_ui->hbox->set_spacing(1); + control_ui->vbox->set_spacing(3); + control_ui->label.set_angle(90); control_ui->hbox->pack_start (control_ui->label, false, false); control_ui->hbox->pack_start (*info->meter, false, false); control_ui->vbox->pack_start (*control_ui->hbox, false, false); - + control_ui->vbox->pack_start (*control_ui->display, false, false); control_ui->pack_start (*control_ui->vbox); control_ui->meterinfo->meter->show_all(); control_ui->meterinfo->packed = true; - + output_controls.push_back (control_ui); } - - mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui)); - + + if (mcontrol) { + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); + } + return control_ui; } void GenericPluginUI::start_touch (GenericPluginUI::ControlUI* cui) { - cui->control->start_touch (); + cui->control->start_touch (cui->control->session().transport_frame()); } void GenericPluginUI::stop_touch (GenericPluginUI::ControlUI* cui) { - cui->control->stop_touch (); + cui->control->stop_touch (false, cui->control->session().transport_frame()); } void -GenericPluginUI::astate_clicked (ControlUI* cui, uint32_t port) +GenericPluginUI::astate_clicked (ControlUI* cui, uint32_t /*port*/) { using namespace Menu_Helpers; if (automation_menu == 0) { automation_menu = manage (new Menu); automation_menu->set_name ("ArdourContextMenu"); - } + } MenuList& items (automation_menu->items()); items.clear (); - items.push_back (MenuElem (_("Manual"), - bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Off, cui))); + items.push_back (MenuElem (S_("Automation|Manual"), + sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) ARDOUR::Off, cui))); items.push_back (MenuElem (_("Play"), - bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Play, cui))); + sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Play, cui))); items.push_back (MenuElem (_("Write"), - bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Write, cui))); + sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Write, cui))); items.push_back (MenuElem (_("Touch"), - bind (mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Touch, cui))); + sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::set_automation_state), (AutoState) Touch, cui))); automation_menu->popup (1, gtk_get_current_event_time()); } @@ -644,7 +765,7 @@ void GenericPluginUI::toggle_parameter_changed (ControlUI* cui) { float val = cui->control->get_value(); - + if (!cui->ignore_change) { if (val > 0.5) { cui->button->set_active (true); @@ -655,28 +776,27 @@ GenericPluginUI::toggle_parameter_changed (ControlUI* cui) } void -GenericPluginUI::parameter_changed (ControlUI* cui) +GenericPluginUI::ui_parameter_changed (ControlUI* cui) { if (!cui->update_pending) { cui->update_pending = true; - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &GenericPluginUI::update_control_display), cui)); + Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&GenericPluginUI::update_control_display, this, cui)); } } void -GenericPluginUI::update_control_display (ControlUI* cui) +GenericPluginUI::update_control_display (ControlUI* cui) { /* XXX how do we handle logarithmic stuff here ? */ - + cui->update_pending = false; float val = cui->control->get_value(); cui->ignore_change++; - if (cui->combo) { - std::map::iterator it; - for (it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) { + if (cui->combo && cui->scale_points) { + for (ARDOUR::Plugin::ScalePoints::iterator it = cui->scale_points->begin(); it != cui->scale_points->end(); ++it) { if (it->second == val) { cui->combo->set_active_text(it->first); break; @@ -718,40 +838,34 @@ GenericPluginUI::control_port_toggled (ControlUI* cui) void GenericPluginUI::control_combo_changed (ControlUI* cui) { - if (!cui->ignore_change) { + if (!cui->ignore_change && cui->scale_points) { string value = cui->combo->get_active_text(); - std::map mapping = *cui->combo_map; - insert->automation_control(cui->parameter())->set_value(mapping[value]); + insert->automation_control (cui->parameter())->set_value ((*cui->scale_points)[value]); } } -void -GenericPluginUI::processor_active_changed (boost::weak_ptr weak_processor) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &GenericPluginUI::processor_active_changed), weak_processor)); - - boost::shared_ptr processor = weak_processor.lock(); - - bypass_button.set_active (!processor || !processor->active()); -} - bool -GenericPluginUI::start_updating (GdkEventAny* ignored) +GenericPluginUI::start_updating (GdkEventAny*) { if (output_controls.size() > 0 ) { screen_update_connection.disconnect(); - screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect - (mem_fun(*this, &GenericPluginUI::output_update)); + screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect + (sigc::mem_fun(*this, &GenericPluginUI::output_update)); } return false; } bool -GenericPluginUI::stop_updating (GdkEventAny* ignored) +GenericPluginUI::stop_updating (GdkEventAny*) { + for (vector::iterator i = input_controls.begin(); i != input_controls.end(); ++i) { + (*i)->controller->stop_updating (); + } + if (output_controls.size() > 0 ) { screen_update_connection.disconnect(); } + return false; } @@ -759,14 +873,14 @@ void GenericPluginUI::output_update () { for (vector::iterator i = output_controls.begin(); i != output_controls.end(); ++i) { - float val = plugin->get_parameter ((*i)->parameter().id()); + float val = plugin->get_parameter ((*i)->port_index); char buf[32]; snprintf (buf, sizeof(buf), "%.2f", val); (*i)->display_label->set_text (buf); /* autoscaling for the meter */ if ((*i)->meterinfo && (*i)->meterinfo->packed) { - + if (val < (*i)->meterinfo->min) { if ((*i)->meterinfo->min_unbound) (*i)->meterinfo->min = val; @@ -780,7 +894,7 @@ GenericPluginUI::output_update () else val = (*i)->meterinfo->max; } - + if ((*i)->meterinfo->max > (*i)->meterinfo->min ) { float lval = (val - (*i)->meterinfo->min) / ((*i)->meterinfo->max - (*i)->meterinfo->min) ; (*i)->meterinfo->meter->set (lval ); @@ -789,60 +903,4 @@ GenericPluginUI::output_update () } } -vector -GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) -{ - vector enums; - boost::shared_ptr lp; -#ifdef HAVE_LV2 - boost::shared_ptr lv2p; -#endif - - if ((lp = boost::dynamic_pointer_cast(plugin)) != 0) { - // all LADPSA plugins have a numeric unique ID - uint32_t id = atol (lp->unique_id().c_str()); - - cui->combo_map = new std::map; - lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index); - if (defaults) { - for (uint32_t i = 0; i < defaults->count; ++i) { - enums.push_back(defaults->items[i].label); - pair newpair; - newpair.first = defaults->items[i].label; - newpair.second = defaults->items[i].value; - cui->combo_map->insert(newpair); - } - - lrdf_free_setting_values(defaults); - } - -#ifdef HAVE_LV2 - } else if ((lv2p = boost::dynamic_pointer_cast(plugin)) != 0) { - - SLV2Port port = lv2p->slv2_port(port_index); - SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port); - cui->combo_map = new std::map; - - for (unsigned i=0; i < slv2_scale_points_size(points); ++i) { - SLV2ScalePoint p = slv2_scale_points_get_at(points, i); - SLV2Value label = slv2_scale_point_get_label(p); - SLV2Value value = slv2_scale_point_get_value(p); - if (label && (slv2_value_is_float(value) || slv2_value_is_int(value))) { - enums.push_back(slv2_value_as_string(label)); - pair newpair; - newpair.first = slv2_value_as_string(label); - newpair.second = slv2_value_as_float(value); - cui->combo_map->insert(newpair); - } - } - - slv2_scale_points_free(points); -#endif - } - - - return enums; -} - -