X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fgeneric_pluginui.cc;h=30be93c1406857a73ffaba3760c59b298ddf8292;hb=d8425b4a0fc1a875a3f1fdff62e222386ce3f1b4;hp=6199f81236aae8ab55d443ffde09fb9e6a7bac72;hpb=3975355a5f7f2d795a369b091972051a50b9f331;p=ardour.git diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 6199f81236..30be93c140 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -41,10 +41,6 @@ #include "ardour/plugin.h" #include "ardour/plugin_insert.h" -#include "ardour/ladspa_plugin.h" -#ifdef HAVE_SLV2 -#include "ardour/lv2_plugin.h" -#endif #include "ardour/session.h" #include @@ -78,7 +74,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol set_border_width (10); //set_homogeneous (false); - pack_start (main_contents, false, false); + pack_start (main_contents, true, true); settings_box.set_homogeneous (false); HBox* constraint_hbox = manage (new HBox); @@ -92,9 +88,10 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol set_latency_label (); smaller_hbox->pack_start (latency_button, false, false, 10); - smaller_hbox->pack_start (preset_combo, false, false); + smaller_hbox->pack_start (_preset_box, false, false); + smaller_hbox->pack_start (add_button, false, false); smaller_hbox->pack_start (save_button, false, false); - smaller_hbox->pack_start (edit_button, false, false); + smaller_hbox->pack_start (delete_button, false, false); smaller_hbox->pack_start (bypass_button, false, true); constraint_hbox->set_spacing (5); @@ -102,7 +99,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol VBox* v1_box = manage (new VBox); VBox* v2_box = manage (new VBox); - pack_end (plugin_analysis_expander, true, true); + pack_end (plugin_analysis_expander, false, false); v1_box->pack_start (*smaller_hbox, false, true); v2_box->pack_start (focus_button, false, true); @@ -114,7 +111,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol main_contents.pack_start (*constraint_hbox, false, false); - if ( is_scrollable ) { + if (is_scrollable ) { scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); scroller.set_name ("PluginEditor"); scroller_view.set_name("PluginEditor"); @@ -123,15 +120,19 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol main_contents.pack_start (scroller, true, true); - } - else { + } else { main_contents.pack_start (hpacker, false, false); } 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()); + if (!pi->active()) { + bypass_button.set_active_state (Gtkmm2ext::Active); + } else { + bypass_button.unset_active_state (); + } + prefheight = 0; build (); } @@ -142,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; @@ -156,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; @@ -181,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); @@ -195,6 +244,7 @@ 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) { @@ -208,24 +258,6 @@ GenericPluginUI::build () 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; - } - } - boost::shared_ptr c = boost::dynamic_pointer_cast( insert->control(Evoral::Parameter(PluginAutomation, 0, i))); @@ -236,12 +268,12 @@ GenericPluginUI::build () } if (cui->controller || cui->clickbox || cui->combo) { - - box->pack_start (*cui, false, false); - + // 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; @@ -264,33 +296,93 @@ GenericPluginUI::build () 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 + // 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; + } - if (output_row == output_rows) { - output_row = 0; - if (++output_col == output_cols) { - output_cols += 2; - output_table.resize (output_rows, output_cols); - } - } + // cerr << "label: " << label << " sim: " << fixed << setprecision(3) << similarity_scores[i] << " num: " << numbers_in_labels[i] << endl; + previous_label = label; + } - output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, - FILL|EXPAND, FILL); + + // 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) { - output_row++; - */ + 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); } - /* 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; - } + box->pack_start (*cui, false, false); + } + + if (is_scrollable) { + prefheight = 30 * i; } if (box->children().empty()) { @@ -304,6 +396,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); } @@ -325,7 +418,7 @@ GenericPluginUI::ControlUI::ControlUI () below). be sure to include a descender. */ - set_size_request_to_display_given_text (automate_button, _("Mgnual"), 15, 10); + set_size_request_to_display_given_text (automate_button, _("Mgnual"), 15, 10); ignore_change = 0; display = 0; @@ -385,9 +478,6 @@ GenericPluginUI::ControlUI* GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr mcontrol) { ControlUI* control_ui = 0; - if (!mcontrol) { - return control_ui; - } Plugin::ParameterDescriptor desc; @@ -395,66 +485,48 @@ 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)) { - - boost::shared_ptr lp; -#ifdef HAVE_SLV2 - 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); - - if (defaults && defaults->count > 0) { + if (plugin->parameter_is_input(port_index)) { - 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 (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::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); + /* Build a combo box */ - update_control_display(control_ui); + control_ui->combo_map = plugin->get_scale_points (port_index); - lrdf_free_setting_values(defaults); - return control_ui; + if (control_ui->combo_map) { + std::vector labels; + for ( + ARDOUR::Plugin::ScalePoints::const_iterator i = control_ui->combo_map->begin(); + i != control_ui->combo_map->end(); + ++i) { + + labels.push_back(i->first); } -#ifdef HAVE_SLV2 - } 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); + 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); - 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 (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::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); + update_control_display(control_ui); - update_control_display(control_ui); - - slv2_scale_points_free(points); - return control_ui; - } -#endif + return control_ui; } if (desc.toggled) { @@ -473,39 +545,32 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrautomate_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()); - + mcontrol->alist()->automation_state_changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed, this, control_ui), gui_context()); + if (plugin->get_parameter (port_index) > 0.5){ control_ui->button->set_active(true); } - automation_state_changed (control_ui); + 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. */ - Adjustment* adj = control_ui->controller->adjustment(); - - adj->set_lower (desc.lower); - adj->set_upper (desc.upper); - - control_ui->logarithmic = desc.logarithmic; + Adjustment* adj = control_ui->controller->adjustment(); + boost::shared_ptr pc = boost::dynamic_pointer_cast (control_ui->control); - if (control_ui->logarithmic) { - if (adj->get_lower() == 0.0) { - adj->set_lower (adj->get_upper()/10000); - } - adj->set_upper (log(adj->get_upper())); - adj->set_lower (log(adj->get_lower())); - } + adj->set_lower (pc->user_to_ui (desc.lower)); + adj->set_upper (pc->user_to_ui (desc.upper)); adj->set_step_increment (desc.step); adj->set_page_increment (desc.largestep); @@ -521,23 +586,14 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcontroller->set_name (X_("PluginSlider")); control_ui->controller->set_style (BarController::LeftToRight); control_ui->controller->set_use_parent (true); - control_ui->controller->set_logarithmic (control_ui->logarithmic); + control_ui->controller->set_logarithmic (desc.logarithmic); 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) { - double val = plugin->get_parameter (port_index); - if (isnan (val) || val <= 0.0) { - adj->set_value (0.0); - } else { - adj->set_value (log(val)); - } - } else{ - adj->set_value(plugin->get_parameter(port_index)); - } + adj->set_value (pc->plugin_to_ui (plugin->get_parameter (port_index))); /* XXX memory leak: SliderController not destroyed by ControlUI destructor, and manage() reports object hierarchy @@ -556,7 +612,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrChanged.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + 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); @@ -608,7 +664,9 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrChanged.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + if (mcontrol) { + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); + } return control_ui; } @@ -671,7 +729,7 @@ 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; @@ -690,9 +748,8 @@ GenericPluginUI::update_control_display (ControlUI* cui) 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->combo_map) { + for (ARDOUR::Plugin::ScalePoints::iterator it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) { if (it->second == val) { cui->combo->set_active_text(it->first); break; @@ -734,23 +791,12 @@ GenericPluginUI::control_port_toggled (ControlUI* cui) void GenericPluginUI::control_combo_changed (ControlUI* cui) { - if (!cui->ignore_change) { + if (!cui->ignore_change && cui->combo_map) { 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->combo_map)[value]); } } -void -GenericPluginUI::processor_active_changed (boost::weak_ptr weak_processor) -{ - ENSURE_GUI_THREAD (*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*) { @@ -768,11 +814,11 @@ 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; } @@ -780,7 +826,7 @@ 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); @@ -810,60 +856,4 @@ GenericPluginUI::output_update () } } -vector -GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) -{ - vector enums; - boost::shared_ptr lp; -#ifdef HAVE_SLV2 - 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_SLV2 - } 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; -} - -