diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index f06597253c..597e2a2fbe 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -165,7 +165,13 @@ GainMeterBase::set_io (boost::shared_ptr io) _io = io; - level_meter->set_meter (_io->peak_meter()); + if (!_io) { + level_meter->set_meter (0); + gain_slider->set_controllable (boost::shared_ptr()); + return; + } + + level_meter->set_meter (&_io->peak_meter()); gain_slider->set_controllable (_io->gain_control()); boost::shared_ptr r; @@ -836,6 +842,14 @@ GainMeter::set_io (boost::shared_ptr io) if (!r->is_hidden()) { fader_vbox->pack_start (gain_automation_state_button, false, false, 0); } + + } else { + + /* we're managing a non-Route IO (e.g. Send) */ + + gain_display_box.pack_end (peak_display, true, true); + hbox.pack_end (*level_meter, true, true); + fader_vbox->pack_start (gain_automation_state_button, false, false, 0); } } diff --git a/gtk2_ardour/level_meter.cc b/gtk2_ardour/level_meter.cc index 1f6cecb74d..f6d41c3312 100644 --- a/gtk2_ardour/level_meter.cc +++ b/gtk2_ardour/level_meter.cc @@ -80,12 +80,14 @@ LevelMeter::~LevelMeter () } void -LevelMeter::set_meter (PeakMeter& meter) +LevelMeter::set_meter (PeakMeter* meter) { _configuration_connection.disconnect(); - _meter = &meter; - _configuration_connection = _meter->ConfigurationChanged.connect( + _meter = meter; + if (_meter) { + _configuration_connection = _meter->ConfigurationChanged.connect( mem_fun(*this, &LevelMeter::configuration_changed)); + } } float @@ -94,6 +96,10 @@ LevelMeter::update_meters () vector::iterator i; uint32_t n; float peak, mpeak; + + if (!_meter) { + return 0.0f; + } for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) { if ((*i).packed) { @@ -149,8 +155,10 @@ LevelMeter::hide_all_meters () void LevelMeter::setup_meters (int len, int initial_width) { + hide_all_meters (); + if (!_meter) { - return; /* do it later */ + return; /* do it later or never */ } int32_t nmidi = _meter->input_streams().n_midi(); @@ -160,8 +168,6 @@ LevelMeter::setup_meters (int len, int initial_width) guint16 width; - hide_all_meters (); - if (nmeters == 0) { return; } diff --git a/gtk2_ardour/level_meter.h b/gtk2_ardour/level_meter.h index 100ce21353..a2bbd5f4a1 100644 --- a/gtk2_ardour/level_meter.h +++ b/gtk2_ardour/level_meter.h @@ -55,7 +55,7 @@ class LevelMeter : public Gtk::HBox LevelMeter (ARDOUR::Session&); ~LevelMeter (); - virtual void set_meter (ARDOUR::PeakMeter& meter); + virtual void set_meter (ARDOUR::PeakMeter* meter); void update_gain_sensitive (); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 8a00eb88a2..5a8442dc44 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -67,6 +67,8 @@ using namespace Gtk; using namespace Gtkmm2ext; using namespace std; +sigc::signal > MixerStrip::SwitchIO; + int MixerStrip::scrollbar_height = 0; #ifdef VARISPEED_IN_MIXER_STRIP @@ -88,8 +90,8 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer) , RouteUI (sess, _("Mute"), _("Solo"), _("Record")) ,_mixer(mx) , _mixer_owned (in_mixer) - , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer) - , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer) + , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), this, in_mixer) + , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), this, in_mixer) , gpm (sess) , panners (sess) , button_table (3, 2) @@ -117,8 +119,8 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr rt , RouteUI (sess, _("Mute"), _("Solo"), _("Record")) ,_mixer(mx) , _mixer_owned (in_mixer) - , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer) - , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer) + , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), this, in_mixer) + , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), this, in_mixer) , gpm (sess) , panners (sess) , button_table (3, 2) @@ -290,6 +292,12 @@ MixerStrip::init () rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false); rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release)); + /* ditto for this button and busses */ + + show_sends_button->set_name ("MixerRecordEnableButton"); + show_sends_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::show_sends_press), false); + show_sends_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::show_sends_release)); + name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false); group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false); @@ -309,6 +317,9 @@ MixerStrip::init () set_name ("AudioTrackStripBase"); add_events (Gdk::BUTTON_RELEASE_MASK); + + SwitchIO.connect (mem_fun (*this, &MixerStrip::switch_io)); + } MixerStrip::~MixerStrip () @@ -326,6 +337,10 @@ MixerStrip::set_route (boost::shared_ptr rt) button_table.remove (*rec_enable_button); } + if (show_sends_button->get_parent()) { + button_table.remove (*show_sends_button); + } + #ifdef VARISPEED_IN_MIXER_STRIP if (speed_frame->get_parent()) { button_table.remove (*speed_frame); @@ -384,6 +399,12 @@ MixerStrip::set_route (boost::shared_ptr rt) button_table.attach (*rec_enable_button, 0, 2, 2, 3); rec_enable_button->show(); + + } else if (!is_track()) { + /* bus */ + + button_table.attach (*show_sends_button, 0, 2, 2, 3); + show_sends_button->show(); } if (_route->phase_invert()) { @@ -562,6 +583,9 @@ MixerStrip::set_width (Width w, void* owner) if (rec_enable_button) { ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("Record")); } + if (show_sends_button) { + ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Sends")); + } ((Gtk::Label*)mute_button->get_child())->set_text (_("Mute")); ((Gtk::Label*)solo_button->get_child())->set_text (_("Solo")); @@ -593,6 +617,9 @@ MixerStrip::set_width (Width w, void* owner) if (rec_enable_button) { ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("Rec")); } + if (show_sends_button) { + ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Snd")); + } ((Gtk::Label*)mute_button->get_child())->set_text (_("M")); ((Gtk::Label*)solo_button->get_child())->set_text (_("S")); @@ -1462,3 +1489,24 @@ MixerStrip::meter_changed (void *src) set_width(_width, this); } +void +MixerStrip::switch_io (boost::shared_ptr target) +{ + boost::shared_ptr to_display; + + if (_route == target) { + /* don't change the display for the target */ + return; + } + + if (!target) { + to_display = _route; + } else { + to_display = _route->send_io_for (target); + } + + gain_meter().set_io (to_display); + gain_meter().setup_meters (); + panner_ui().set_io (to_display); + panner_ui().setup_pan (); +} diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index e2fa2e52d5..958bfc9422 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -88,6 +88,9 @@ class MixerStrip : public RouteUI, public Gtk::EventBox Width get_width() const { return _width; } void* width_owner() const { return _width_owner; } + GainMeter& gain_meter() { return gpm; } + PannerUI& panner_ui() { return panners; } + void fast_update (); void set_embedded (bool); @@ -98,6 +101,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox sigc::signal WidthChanged; #endif + static sigc::signal > SwitchIO; + protected: friend class Mixer_UI; void set_packed (bool yn); @@ -257,6 +262,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void engine_running(); void engine_stopped(); + void switch_io (boost::shared_ptr); + static int scrollbar_height; }; diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index c8c933348b..3ffec0ab05 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -133,7 +133,7 @@ PannerUI::PannerUI (Session& s) void PannerUI::set_io (boost::shared_ptr io) { - if (!io->panner()) { + if (io && !io->panner()) { cerr << "PannerUI::set_io IO has no panners" << endl; return; } @@ -148,15 +148,16 @@ PannerUI::set_io (boost::shared_ptr io) _io = io; - connections.push_back (_io->panner()->Changed.connect ( - mem_fun(*this, &PannerUI::panner_changed))); - connections.push_back (_io->panner()->LinkStateChanged.connect ( - mem_fun(*this, &PannerUI::update_pan_linkage))); - connections.push_back (_io->panner()->StateChanged.connect ( - mem_fun(*this, &PannerUI::update_pan_state))); - delete panner; panner = 0; + + if (!_io) { + return; + } + + connections.push_back (_io->panner()->Changed.connect (mem_fun(*this, &PannerUI::panner_changed))); + connections.push_back (_io->panner()->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage))); + connections.push_back (_io->panner()->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state))); setup_pan (); @@ -338,7 +339,7 @@ PannerUI::update_pan_state () void PannerUI::setup_pan () { - if (!_io->panner()) { + if (!_io || !_io->panner()) { return; } diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index 027d9df51e..f850582fec 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -59,6 +59,7 @@ #include "io_selector.h" #include "keyboard.h" #include "mixer_ui.h" +#include "mixer_strip.h" #include "plugin_selector.h" #include "plugin_ui.h" #include "processor_box.h" @@ -89,8 +90,9 @@ Gdk::Color* ProcessorBox::active_processor_color; Gdk::Color* ProcessorBox::inactive_processor_color; ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, - RouteRedirectSelection & rsel, bool owner_is_mixer) + RouteRedirectSelection & rsel, MixerStrip* parent, bool owner_is_mixer) : _session(sess) + , _parent_strip (parent) , _owner_is_mixer (owner_is_mixer) , _placement(pcmnt) , _plugin_selector(plugsel) @@ -1193,12 +1195,10 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) return; } - boost::shared_ptr send = boost::dynamic_pointer_cast (processor); - +#ifdef OLD_SEND_EDITING SendUIWindow *send_ui; if (send->get_gui() == 0) { - send_ui = new SendUIWindow (send, _session); WindowTitle title(Glib::get_application_name()); @@ -1212,6 +1212,12 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) } gidget = send_ui; +#else + if (_parent_strip) { + _parent_strip->gain_meter().set_io (send->io()); + _parent_strip->panner_ui().set_io (send->io()); + } +#endif } else if ((retrn = boost::dynamic_pointer_cast (processor)) != 0) { diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index a003ed8c5d..d53d05fe23 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -52,6 +52,7 @@ class MotionController; class PluginSelector; class PluginUIWindow; class RouteRedirectSelection; +class MixerStrip; namespace ARDOUR { class Connection; @@ -68,7 +69,7 @@ namespace ARDOUR { class ProcessorBox : public Gtk::HBox, public PluginInterestedObject { public: - ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false); + ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, MixerStrip* parent, bool owner_is_mixer = false); ~ProcessorBox (); void set_route (boost::shared_ptr); @@ -90,6 +91,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject private: boost::shared_ptr _route; ARDOUR::Session & _session; + MixerStrip* _parent_strip; // null if in RouteParamsUI bool _owner_is_mixer; bool ab_direction; std::vector connections; diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index 33a99f6955..5c709d80bf 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -231,8 +231,8 @@ RouteParams_UI::setup_processor_boxes() cleanup_processor_boxes(); // construct new redirect boxes - pre_insert_box = new ProcessorBox(PreFader, *session, *_plugin_selector, _rr_selection); - post_insert_box = new ProcessorBox(PostFader, *session, *_plugin_selector, _rr_selection); + pre_insert_box = new ProcessorBox(PreFader, *session, *_plugin_selector, _rr_selection, 0); + post_insert_box = new ProcessorBox(PostFader, *session, *_plugin_selector, _rr_selection, 0); pre_insert_box->set_route (_route); post_insert_box->set_route (_route); diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 40d0ae8da5..d050bc97fe 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -38,6 +38,7 @@ #include "gui_thread.h" #include "ardour_dialog.h" #include "latency_gui.h" +#include "mixer_strip.h" #include "automation_time_axis.h" #include "ardour/route.h" @@ -84,6 +85,7 @@ RouteUI::~RouteUI() delete solo_menu; delete mute_menu; delete remote_control_menu; + delete sends_menu; } void @@ -94,6 +96,7 @@ RouteUI::init () mute_menu = 0; solo_menu = 0; remote_control_menu = 0; + sends_menu = 0; ignore_toggle = false; wait_for_release = false; route_active_menu_item = 0; @@ -118,6 +121,11 @@ RouteUI::init () rec_enable_button->set_self_managed (true); UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), ""); + show_sends_button = manage (new BindableToggleButton ("")); + show_sends_button->set_name ("ShowSendsButton"); + show_sends_button->set_self_managed (true); + UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), ""); + _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute)); } @@ -497,6 +505,83 @@ RouteUI::rec_enable_release (GdkEventButton* ev) return true; } +void +RouteUI::build_sends_menu () +{ + using namespace Menu_Helpers; + + sends_menu = new Menu; + sends_menu->set_name ("ArdourContextMenu"); + MenuList& items = sends_menu->items(); + + items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track))); + items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero))); + items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity))); +} + +void +RouteUI::set_sends_gain_from_track () +{ +} + +void +RouteUI::set_sends_gain_to_zero () +{ +} + +void +RouteUI::set_sends_gain_to_unity () +{ +} + +bool +RouteUI::show_sends_press(GdkEventButton* ev) +{ + if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) { + return true; + } + + if (!ignore_toggle && !is_track() && show_sends_button) { + + if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + + // do nothing on midi bind event + return false; + + } else if (Keyboard::is_context_menu_event (ev)) { + + if (sends_menu == 0) { + build_sends_menu (); + } + + sends_menu->popup (0, ev->time); + + } else { + + /* change button state */ + + show_sends_button->set_active (!show_sends_button->get_active()); + + if (show_sends_button->get_active()) { + /* show sends to this bus */ + MixerStrip::SwitchIO (_route); + } else { + /* everybody back to normal */ + MixerStrip::SwitchIO (boost::shared_ptr()); + } + + } + } + + return true; +} + +bool +RouteUI::show_sends_release (GdkEventButton* ev) +{ + return true; +} + void RouteUI::solo_changed(void* src) { diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index 4ec6fd3ce8..5a1933997d 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -81,7 +81,8 @@ class RouteUI : public virtual AxisView BindableToggleButton* mute_button; BindableToggleButton* solo_button; - BindableToggleButton* rec_enable_button; + BindableToggleButton* rec_enable_button; /* audio tracks */ + BindableToggleButton* show_sends_button; /* busses */ virtual std::string solo_button_name () const { return "SoloButton"; } virtual std::string safe_solo_button_name () const { return "SafeSoloButton"; } @@ -89,6 +90,7 @@ class RouteUI : public virtual AxisView Gtk::Menu* mute_menu; Gtk::Menu* solo_menu; Gtk::Menu* remote_control_menu; + Gtk::Menu* sends_menu; XMLNode *xml_node; void ensure_xml_node (); @@ -101,6 +103,13 @@ class RouteUI : public virtual AxisView bool solo_release(GdkEventButton*); bool rec_enable_press(GdkEventButton*); bool rec_enable_release(GdkEventButton*); + bool show_sends_press(GdkEventButton*); + bool show_sends_release(GdkEventButton*); + + void build_sends_menu (); + void set_sends_gain_from_track (); + void set_sends_gain_to_zero (); + void set_sends_gain_to_unity (); void solo_changed(void*); void solo_changed_so_update_mute (); diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 5c7d8d0f0f..23e4f576df 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -141,6 +141,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent int disconnect_inputs (void *src); int disconnect_outputs (void *src); + bool connected_to (boost::shared_ptr) const; + nframes_t signal_latency() const { return _own_latency; } nframes_t output_latency() const; nframes_t input_latency() const; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index c498b1f04e..10aec0446e 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -91,7 +91,6 @@ class Route : public IO /* these are the core of the API of a Route. see the protected sections as well */ - virtual int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input); @@ -181,6 +180,8 @@ class Route : public IO boost::shared_ptr control_outs() const { return _control_outs; } boost::shared_ptr main_outs() const { return _main_outs; } + + boost::shared_ptr send_io_for (boost::shared_ptr target) const; /** A record of the stream configuration at some point in the processor list. * Used to return where and why an processor list configuration request failed. @@ -248,7 +249,7 @@ class Route : public IO int listen_via (boost::shared_ptr, const std::string& name); void drop_listen (boost::shared_ptr); - bool feeds (boost::shared_ptr); + bool feeds (boost::shared_ptr); std::set > fed_by; struct ToggleControllable : public PBD::Controllable { @@ -314,7 +315,7 @@ class Route : public IO nframes_t _initial_delay; nframes_t _roll_delay; ProcessorList _processors; - Glib::RWLock _processor_lock; + mutable Glib::RWLock _processor_lock; boost::shared_ptr _main_outs; boost::shared_ptr _control_outs; // XXX to be removed/generalized by listen points RouteGroup *_edit_group; diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 52c2aa48cc..ba3d70c184 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1596,25 +1596,28 @@ IO::get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out, int IO::create_ports (const XMLNode& node) { - ChanCount in; - ChanCount out; - boost::shared_ptr ic; - boost::shared_ptr oc; + if (pending_state_node) { - no_panner_reset = true; - - get_port_counts (*pending_state_node, in, out, ic, oc); - - if (ensure_io (in, out, true, this)) { - error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg; - return -1; + ChanCount in; + ChanCount out; + boost::shared_ptr ic; + boost::shared_ptr oc; + + no_panner_reset = true; + + get_port_counts (*pending_state_node, in, out, ic, oc); + + if (ensure_io (in, out, true, this)) { + error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg; + return -1; + } + + /* XXX use ic and oc if relevant */ + + no_panner_reset = false; } - /* XXX use ic and oc if relevant */ - - no_panner_reset = false; set_deferred_state (); - return 0; } @@ -2663,3 +2666,22 @@ IO::increment_output_offset (nframes_t n) _output_offset += n; } +bool +IO::connected_to (boost::shared_ptr other) const +{ + uint32_t i, j; + + uint32_t no = n_outputs().n_total(); + uint32_t ni = other->n_inputs ().n_total(); + + for (i = 0; i < no; ++i) { + for (j = 0; j < ni; ++j) { + if (output(i)->connected_to (other->input(j)->name())) { + return true; + } + } + } + + return false; +} + diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 228a140d05..7fb063eae0 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -2112,39 +2112,21 @@ Route::set_comment (string cmt, void *src) } bool -Route::feeds (boost::shared_ptr other) +Route::feeds (boost::shared_ptr other) { - uint32_t i, j; - - IO& self = *this; - uint32_t no = self.n_outputs().n_total(); - uint32_t ni = other->n_inputs ().n_total(); - - for (i = 0; i < no; ++i) { - for (j = 0; j < ni; ++j) { - if (self.output(i)->connected_to (other->input(j)->name())) { - return true; - } - } + if (connected_to (other)) { + return true; } /* check IOProcessors which may also interconnect Routes */ for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) { - boost::shared_ptr proc = boost::dynamic_pointer_cast(*r); - - if (!proc) { - continue; - } - - no = proc->io()->n_outputs().n_total(); - - for (i = 0; i < no; ++i) { - for (j = 0; j < ni; ++j) { - if (proc->io()->output(i)->connected_to (other->input (j)->name())) { - return true; - } + boost::shared_ptr proc; + + if ((proc = boost::dynamic_pointer_cast(*r)) != 0) { + if (proc->io()->connected_to (other)) { + return true; } } } @@ -2700,3 +2682,21 @@ Route::set_name (const string& str) return ret; } + +boost::shared_ptr +Route::send_io_for (boost::shared_ptr target) const +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + + for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr send; + + if ((send = boost::dynamic_pointer_cast(*i)) != 0) { + if (send->io()->connected_to (target)) { + return send->io(); + } + } + } + + return boost::shared_ptr(); +}