summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/ardour.menus.in2
-rw-r--r--gtk2_ardour/plugin_pin_dialog.cc227
-rw-r--r--gtk2_ardour/plugin_pin_dialog.h55
-rw-r--r--gtk2_ardour/processor_box.cc104
-rw-r--r--gtk2_ardour/processor_box.h25
-rw-r--r--gtk2_ardour/wscript1
6 files changed, 413 insertions, 1 deletions
diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in
index aeb5de249f..0f296bce15 100644
--- a/gtk2_ardour/ardour.menus.in
+++ b/gtk2_ardour/ardour.menus.in
@@ -654,6 +654,8 @@
<menuitem action='deactivate_all'/>
<menuitem action='ab_plugins'/>
<separator/>
+ <menuitem action='manage-pins'/>
+ <separator/>
<menuitem action='edit'/>
<menuitem action='edit-generic'/>
</popup>
diff --git a/gtk2_ardour/plugin_pin_dialog.cc b/gtk2_ardour/plugin_pin_dialog.cc
new file mode 100644
index 0000000000..1e7259ba5c
--- /dev/null
+++ b/gtk2_ardour/plugin_pin_dialog.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2011 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 the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "gtkmm2ext/utils.h"
+
+#include "plugin_pin_dialog.h"
+#include "gui_thread.h"
+#include "ui_config.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+
+PluginPinDialog::PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert> pi)
+ : ArdourWindow (string_compose (_("Pin Configuration: %1"), pi->name ()))
+ , _pi (pi)
+{
+ assert (pi->owner ()); // Route
+
+ _pi->PluginIoReConfigure.connect (
+ _plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::plugin_reconfigured, this), gui_context()
+ );
+
+ _pi->PluginMapChanged.connect (
+ _plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::plugin_reconfigured, this), gui_context()
+ );
+
+ darea.signal_expose_event().connect (sigc::mem_fun (*this, &PluginPinDialog::darea_expose_event));
+
+ // TODO min. width depending on # of pins.
+ darea.set_size_request(600, 200);
+
+ VBox* vbox = manage (new VBox);
+ vbox->pack_start (darea, true, true);
+ add (*vbox);
+}
+
+PluginPinDialog::~PluginPinDialog()
+{
+}
+
+void
+PluginPinDialog::plugin_reconfigured ()
+{
+ darea.queue_draw ();
+}
+
+void
+PluginPinDialog::draw_io_pins (cairo_t* cr, double y0, double width, uint32_t n_total, uint32_t n_midi, bool input)
+{
+ double dir = input ? 1. : -1.;
+
+ for (uint32_t i = 0; i < n_total; ++i) {
+ double x0 = rint ((i + 1) * width / (1. + n_total)) - .5;
+ cairo_move_to (cr, x0, y0);
+ cairo_rel_line_to (cr, -5., -5. * dir);
+ cairo_rel_line_to (cr, 0., -25. * dir);
+ cairo_rel_line_to (cr, 10., 0.);
+ cairo_rel_line_to (cr, 0., 25. * dir);
+ cairo_close_path (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_stroke_preserve (cr);
+
+ if (i < n_midi) {
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ } else {
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ }
+ cairo_fill (cr);
+ }
+}
+
+double
+PluginPinDialog::pin_x_pos (uint32_t i, double x0, double width, uint32_t n_total, uint32_t n_midi, bool midi)
+{
+ if (!midi) { i += n_midi; }
+ return rint (x0 + (i + 1) * width / (1. + n_total)) - .5;
+}
+
+void
+PluginPinDialog::draw_plugin_pins (cairo_t* cr, double x0, double y0, double width, uint32_t n_total, uint32_t n_midi, bool input)
+{
+ // see also ProcessorEntry::PortIcon::on_expose_event
+ const double dxy = rint (max (6., 8. * UIConfiguration::instance().get_ui_scale()));
+
+ for (uint32_t i = 0; i < n_total; ++i) {
+ double x = rint (x0 + (i + 1) * width / (1. + n_total)) - .5;
+ cairo_rectangle (cr, x - dxy * .5, input ? y0 - dxy : y0, 1 + dxy, dxy);
+
+ if (i < n_midi) {
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ } else {
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ }
+
+ cairo_fill(cr);
+ }
+}
+
+void
+PluginPinDialog::draw_connection (cairo_t* cr, double x0, double x1, double y0, double y1, bool midi)
+{
+ cairo_move_to (cr, x0, y0);
+ cairo_curve_to (cr, x0, y0 + 10, x1, y1 - 10, x1, y1);
+ cairo_set_line_width (cr, 3.0);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ if (midi) {
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ } else {
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ }
+ cairo_stroke (cr);
+}
+
+bool
+PluginPinDialog::darea_expose_event (GdkEventExpose* ev)
+{
+ Gtk::Allocation a = darea.get_allocation();
+ double const width = a.get_width();
+ double const height = a.get_height();
+
+ cairo_t* cr = gdk_cairo_create (darea.get_window()->gobj());
+
+ cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
+ cairo_clip (cr);
+
+ Gdk::Color const bg = get_style()->get_bg (STATE_NORMAL);
+ cairo_set_source_rgb (cr, bg.get_red_p (), bg.get_green_p (), bg.get_blue_p ());
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_fill (cr);
+
+ ChanCount in, out; // actual configured i/o
+ _pi->configured_io (in, out);
+
+ ChanCount sinks = _pi->natural_input_streams ();
+ ChanCount sources = _pi->natural_output_streams ();
+ uint32_t plugins = _pi->get_count ();
+
+ /* layout sizes */
+ // i/o pins
+ double y_in = 40;
+ double y_out = height - 40;
+
+ // plugin box(es)
+ double yc = rint (height * .5);
+ double bxh2 = 18;
+ double bxw = rint ((width * .9) / ((plugins) + .2 * (plugins - 1)));
+ double bxw2 = rint (bxw * .5);
+
+ // i/o pins
+ const uint32_t pc_in = in.n_total();
+ const uint32_t pc_in_midi = in.n_midi();
+ const uint32_t pc_out = out.n_total();
+ const uint32_t pc_out_midi = out.n_midi();
+
+ cairo_set_line_width (cr, 1.0);
+ draw_io_pins (cr, y_in, width, pc_in, pc_in_midi, true);
+ draw_io_pins (cr, y_out, width, pc_out, pc_out_midi, false);
+
+ // draw midi-bypass (behind)
+ if (sources.n_midi() == 0 && pc_in_midi > 0 && pc_out_midi > 0) {
+ double x0 = rint (width / (1. + pc_in)) - .5;
+ double x1 = rint (width / (1. + pc_out)) - .5;
+ draw_connection (cr, x0, x1, y_in, y_out, true);
+ }
+
+ for (uint32_t i = 0; i < plugins; ++i) {
+ double x0 = rint ((i + .5) * width / (double)(plugins)) - .5;
+
+ draw_plugin_pins (cr, x0 - bxw2, yc - bxh2, bxw, sinks.n_total (), sinks.n_midi (), true);
+ draw_plugin_pins (cr, x0 - bxw2, yc + bxh2, bxw, sources.n_total (), sources.n_midi (), false);
+
+ cairo_set_source_rgb (cr, .3, .3, .3);
+ rounded_rectangle (cr, x0 - bxw2, yc - bxh2, bxw, 2 * bxh2, 7);
+ cairo_fill (cr);
+
+ const ChanMapping::Mappings in_map = _pi->input_map (i).mappings();
+ const ChanMapping::Mappings out_map = _pi->output_map (i).mappings();
+
+ for (ChanMapping::Mappings::const_iterator t = in_map.begin (); t != in_map.end (); ++t) {
+ bool is_midi = t->first == DataType::MIDI;
+ for (ChanMapping::TypeMapping::const_iterator c = (*t).second.begin (); c != (*t).second.end () ; ++c) {
+ uint32_t pn = (*c).first; // pin
+ uint32_t pb = (*c).second;
+ double c_x0 = pin_x_pos (pb, 0, width, pc_in, pc_in_midi, is_midi);
+ double c_x1 = pin_x_pos (pn, x0 - bxw2, bxw, sinks.n_total (), sinks.n_midi (), is_midi);
+ draw_connection (cr, c_x0, c_x1, y_in, yc - bxh2, is_midi);
+ }
+ }
+
+ for (ChanMapping::Mappings::const_iterator t = out_map.begin (); t != out_map.end (); ++t) {
+ bool is_midi = t->first == DataType::MIDI;
+ for (ChanMapping::TypeMapping::const_iterator c = (*t).second.begin (); c != (*t).second.end () ; ++c) {
+ uint32_t pn = (*c).first; // pin
+ uint32_t pb = (*c).second;
+ double c_x0 = pin_x_pos (pn, x0 - bxw2, bxw, sources.n_total (), sources.n_midi (), is_midi);
+ double c_x1 = pin_x_pos (pb, 0, width, pc_out, pc_out_midi, is_midi);
+ draw_connection (cr, c_x0, c_x1, yc + bxh2, y_out, is_midi);
+ }
+ }
+ }
+
+ cairo_destroy (cr);
+ return true;
+}
diff --git a/gtk2_ardour/plugin_pin_dialog.h b/gtk2_ardour/plugin_pin_dialog.h
new file mode 100644
index 0000000000..cb196a5bd0
--- /dev/null
+++ b/gtk2_ardour/plugin_pin_dialog.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * 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 the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __gtkardour_plugin_pin_dialog_h__
+#define __gtkardour_plugin_pin_dialog_h__
+
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/box.h>
+
+#include "pbd/stateful.h"
+#include "pbd/signals.h"
+
+#include "ardour/plugin_insert.h"
+#include "ardour/route.h"
+
+#include "ardour_window.h"
+
+class PluginPinDialog : public ArdourWindow
+{
+public:
+ PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert>);
+ ~PluginPinDialog ();
+
+private:
+ Gtk::DrawingArea darea;
+ bool darea_expose_event (GdkEventExpose* event);
+
+ void plugin_reconfigured ();
+
+ void draw_io_pins (cairo_t*, double, double, uint32_t, uint32_t, bool);
+ void draw_plugin_pins (cairo_t*, double, double, double, uint32_t, uint32_t, bool);
+ void draw_connection (cairo_t*, double, double, double, double, bool);
+
+ double pin_x_pos (uint32_t, double, double, uint32_t, uint32_t, bool);
+
+ PBD::ScopedConnectionList _plugin_connections;
+ boost::shared_ptr<ARDOUR::PluginInsert> _pi;
+};
+
+#endif
diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc
index 6f01633ce4..3b49b61aae 100644
--- a/gtk2_ardour/processor_box.cc
+++ b/gtk2_ardour/processor_box.cc
@@ -70,6 +70,7 @@
#include "luainstance.h"
#include "mixer_ui.h"
#include "mixer_strip.h"
+#include "plugin_pin_dialog.h"
#include "plugin_selector.h"
#include "plugin_ui.h"
#include "port_insert_ui.h"
@@ -106,6 +107,7 @@ RefPtr<Action> ProcessorBox::cut_action;
RefPtr<Action> ProcessorBox::copy_action;
RefPtr<Action> ProcessorBox::rename_action;
RefPtr<Action> ProcessorBox::delete_action;
+RefPtr<Action> ProcessorBox::manage_pins_action;
RefPtr<Action> ProcessorBox::edit_action;
RefPtr<Action> ProcessorBox::edit_generic_action;
RefPtr<ActionGroup> ProcessorBox::processor_box_actions;
@@ -1822,6 +1824,8 @@ ProcessorBox::show_processor_menu (int arg)
pi = boost::dynamic_pointer_cast<PluginInsert> (single_selection->processor ());
}
+ manage_pins_action->set_sensitive (pi != 0);
+
/* allow editing with an Ardour-generated UI for plugin inserts with editors */
edit_action->set_sensitive (pi && pi->plugin()->has_editor ());
@@ -2330,6 +2334,7 @@ ProcessorBox::redisplay_processors ()
_route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::add_processor_to_display));
_route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::maybe_add_processor_to_ui_list));
+ _route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::maybe_add_processor_pin_mgr));
setup_entry_positions ();
}
@@ -2386,6 +2391,31 @@ ProcessorBox::maybe_add_processor_to_ui_list (boost::weak_ptr<Processor> w)
}
void
+ProcessorBox::maybe_add_processor_pin_mgr (boost::weak_ptr<Processor> w)
+{
+ boost::shared_ptr<Processor> p = w.lock ();
+ if (!p || p->pinmgr_proxy ()) {
+ return;
+ }
+
+ PluginPinWindowProxy* wp = new PluginPinWindowProxy (
+ string_compose ("PM-%2-%3", _route->id(), p->id()), w);
+
+ const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
+ if (ui_xml) {
+ wp->set_state (*ui_xml, 0);
+ }
+
+ void* existing_ui = p->get_ui ();
+
+ if (existing_ui) {
+ wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
+ }
+
+ p->set_pingmgr_proxy (wp);
+ WM::Manager::instance().register_window (wp);
+}
+void
ProcessorBox::help_count_visible_prefader_processors (boost::weak_ptr<Processor> p, uint32_t* cnt, bool* amp_seen)
{
boost::shared_ptr<Processor> processor (p.lock ());
@@ -3229,6 +3259,10 @@ ProcessorBox::register_actions ()
myactions.register_action (processor_box_actions, X_("ab_plugins"), _("A/B Plugins"),
sigc::ptr_fun (ProcessorBox::rb_ab_plugins));
+ manage_pins_action = myactions.register_action (
+ processor_box_actions, X_("manage-pins"), _("Pin Management..."),
+ sigc::ptr_fun (ProcessorBox::rb_manage_pins));
+
/* show editors */
edit_action = myactions.register_action (
processor_box_actions, X_("edit"), _("Edit..."),
@@ -3262,6 +3296,15 @@ ProcessorBox::rb_ab_plugins ()
}
void
+ProcessorBox::rb_manage_pins ()
+{
+ if (_current_processor_box == 0) {
+ return;
+ }
+
+ _current_processor_box->for_selected_processors (&ProcessorBox::manage_pins);
+}
+void
ProcessorBox::rb_choose_plugin ()
{
if (_current_processor_box == 0) {
@@ -3491,6 +3534,20 @@ ProcessorBox::generic_edit_processor (boost::shared_ptr<Processor> processor)
}
void
+ProcessorBox::manage_pins (boost::shared_ptr<Processor> processor)
+{
+ if (!processor) {
+ return;
+ }
+ PluginPinWindowProxy* proxy = processor->pinmgr_proxy ();
+ if (proxy) {
+ proxy->get (true);
+ proxy->present();
+ }
+}
+
+
+void
ProcessorBox::route_property_changed (const PropertyChange& what_changed)
{
if (!what_changed.contains (ARDOUR::Properties::name)) {
@@ -3770,6 +3827,53 @@ ProcessorWindowProxy::show_the_right_window ()
toggle ();
}
+
+PluginPinWindowProxy::PluginPinWindowProxy(std::string const &name, boost::weak_ptr<ARDOUR::Processor> processor)
+ : WM::ProxyBase (name, string())
+ , _processor (processor)
+{
+ boost::shared_ptr<Processor> p = _processor.lock ();
+ if (!p) {
+ return;
+ }
+ p->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&PluginPinWindowProxy::processor_going_away, this), gui_context());
+}
+
+PluginPinWindowProxy::~PluginPinWindowProxy()
+{
+ _window = 0;
+}
+
+
+Gtk::Window*
+PluginPinWindowProxy::get (bool create)
+{
+ boost::shared_ptr<Processor> p = _processor.lock ();
+ boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (p);
+ if (!p || !pi) {
+ return 0;
+ }
+
+ if (!_window) {
+ if (!create) {
+ return 0;
+ }
+ _window = new PluginPinDialog (pi);
+ }
+
+ _window->show_all ();
+ return _window;
+}
+
+void
+PluginPinWindowProxy::processor_going_away ()
+{
+ delete _window;
+ _window = 0;
+ WM::Manager::instance().remove (this);
+ going_away_connection.disconnect();
+}
+
void
ProcessorBox::load_bindings ()
{
diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h
index 2df431139c..ef45b4c8b8 100644
--- a/gtk2_ardour/processor_box.h
+++ b/gtk2_ardour/processor_box.h
@@ -102,12 +102,31 @@ class ProcessorWindowProxy : public WM::ProxyBase
boost::weak_ptr<ARDOUR::Processor> _processor;
bool is_custom;
bool want_custom;
- bool _valid;
void processor_going_away ();
PBD::ScopedConnection going_away_connection;
};
+
+class PluginPinWindowProxy : public WM::ProxyBase
+{
+ public:
+ PluginPinWindowProxy (std::string const &, boost::weak_ptr<ARDOUR::Processor>);
+ ~PluginPinWindowProxy();
+
+ Gtk::Window* get (bool create = false);
+ ARDOUR::SessionHandlePtr* session_handle() { return 0; }
+
+ private:
+ ProcessorBox* _processor_box;
+ boost::weak_ptr<ARDOUR::Processor> _processor;
+
+ void processor_going_away ();
+ PBD::ScopedConnection going_away_connection;
+};
+
+
+
class ProcessorEntry : public Gtkmm2ext::DnDVBoxChild, public sigc::trackable
{
public:
@@ -344,6 +363,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
Gtk::Window* get_editor_window (boost::shared_ptr<ARDOUR::Processor>, bool);
Gtk::Window* get_generic_editor_window (boost::shared_ptr<ARDOUR::Processor>);
+ void manage_pins (boost::shared_ptr<ARDOUR::Processor>);
void edit_processor (boost::shared_ptr<ARDOUR::Processor>);
void generic_edit_processor (boost::shared_ptr<ARDOUR::Processor>);
@@ -462,6 +482,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
static Glib::RefPtr<Gtk::Action> paste_action;
static Glib::RefPtr<Gtk::Action> rename_action;
static Glib::RefPtr<Gtk::Action> delete_action;
+ static Glib::RefPtr<Gtk::Action> manage_pins_action;
static Glib::RefPtr<Gtk::Action> edit_action;
static Glib::RefPtr<Gtk::Action> edit_generic_action;
void paste_processor_state (const XMLNodeList&, boost::shared_ptr<ARDOUR::Processor>);
@@ -495,6 +516,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
static void rb_activate_all ();
static void rb_deactivate_all ();
static void rb_ab_plugins ();
+ static void rb_manage_pins ();
static void rb_edit ();
static void rb_edit_generic ();
@@ -508,6 +530,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
void set_processor_ui (boost::shared_ptr<ARDOUR::Processor>, Gtk::Window *);
void maybe_add_processor_to_ui_list (boost::weak_ptr<ARDOUR::Processor>);
+ void maybe_add_processor_pin_mgr (boost::weak_ptr<ARDOUR::Processor>);
bool one_processor_can_be_edited ();
bool processor_can_be_edited (boost::shared_ptr<ARDOUR::Processor>);
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 72e8120585..ac8f09c27e 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -176,6 +176,7 @@ gtk2_ardour_sources = [
'pingback.cc',
'playlist_selector.cc',
'plugin_eq_gui.cc',
+ 'plugin_pin_dialog.cc',
'plugin_selector.cc',
'plugin_ui.cc',
'port_group.cc',