diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index aca08444df..59e3c996a3 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -11,6 +11,7 @@ + diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index dd7a48e74d..b112576a5b 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -419,7 +419,7 @@ ARDOUR_UI::setup_transport () auto_box->pack_start (auto_return_button, false, false); transport_tearoff_hbox.pack_start (*auto_box, false, false); - transport_tearoff_hbox.pack_start (*clock_box, false, false); + transport_tearoff_hbox.pack_start (*clock_box, true, true); time_info_box = manage (new TimeInfoBox); transport_tearoff_hbox.pack_start (*time_info_box, false, false); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index d53972afc3..f3860812f2 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1247,6 +1247,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD boost::shared_ptr get_nth_selected_audio_track (int nth) const; boost::shared_ptr get_nth_selected_midi_track (int nth) const; + void toggle_midi_input_active (bool flip_others); + ARDOUR::InterThreadInfo* current_interthread_info; AnalysisWindow* analysis_window; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index e274170982..a8b9f0da0c 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -623,6 +623,9 @@ Editor::register_actions () Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); tact->set_active (true); + ActionManager::register_action (editor_actions, X_("toggle-midi-input-active"), _("Toggle MIDI Input Active for Editor-Selected Tracks/Busses"), + sigc::bind (sigc::mem_fun (*this, &Editor::toggle_midi_input_active), false)); + ActionManager::add_action_group (rl_actions); ActionManager::add_action_group (ruler_actions); ActionManager::add_action_group (zoom_actions); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 0aac921afd..ac402981a8 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -6828,3 +6828,26 @@ Editor::uncombine_regions () commit_reversible_command (); } +void +Editor::toggle_midi_input_active (bool flip_others) +{ + bool onoff; + boost::shared_ptr rl (new RouteList); + + for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + RouteTimeAxisView *rtav = dynamic_cast(*i); + + if (!rtav) { + continue; + } + + boost::shared_ptr mt = rtav->midi_track(); + + if (mt) { + rl->push_back (rtav->route()); + onoff = !mt->input_active(); + } + } + + _session->set_exclusive_input_active (rl, onoff, flip_others); +} diff --git a/gtk2_ardour/mixer.bindings b/gtk2_ardour/mixer.bindings index 25d4cfb077..bd5ec90458 100644 --- a/gtk2_ardour/mixer.bindings +++ b/gtk2_ardour/mixer.bindings @@ -3,6 +3,7 @@ + diff --git a/gtk2_ardour/mixer_actor.cc b/gtk2_ardour/mixer_actor.cc index 6a60fd0bf1..d7a1149a4b 100644 --- a/gtk2_ardour/mixer_actor.cc +++ b/gtk2_ardour/mixer_actor.cc @@ -71,6 +71,9 @@ MixerActor::register_actions () myactions.register_action ("Mixer", "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &MixerActor::scroll_left)); myactions.register_action ("Mixer", "scroll-right", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &MixerActor::scroll_right)); + + myactions.register_action ("Mixer", "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"), + sigc::bind (sigc::mem_fun (*this, &MixerActor::toggle_midi_input_active), false)); } void @@ -261,3 +264,4 @@ MixerActor::ab_plugins () } } } + diff --git a/gtk2_ardour/mixer_actor.h b/gtk2_ardour/mixer_actor.h index 85c7bc1cf8..0b856d338c 100644 --- a/gtk2_ardour/mixer_actor.h +++ b/gtk2_ardour/mixer_actor.h @@ -63,10 +63,14 @@ class MixerActor : virtual public sigc::trackable void toggle_processors (); void ab_plugins (); + /* these actions need access to a Session, do defer to + a derived class + */ + virtual void toggle_midi_input_active (bool flip_others) = 0; + /* these actions don't apply to the selection, so defer to a derived class. */ - virtual void scroll_left () {} virtual void scroll_right () {} }; diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index c4410438f9..398edf1997 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -1915,22 +1915,12 @@ MixerStrip::input_active_button_release (GdkEventButton* ev) return true; } - if (mt->input_active()) { - if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { - /* turn all other tracks using this input off */ - _session->set_exclusive_input_active (mt, false); - } else { - mt->set_input_active (false); - } + boost::shared_ptr rl (new RouteList); - } else { - if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { - /* turn all other tracks using this input on */ - _session->set_exclusive_input_active (mt, true); - } else { - mt->set_input_active (true); - } - } + rl->push_back (route()); + + _session->set_exclusive_input_active (rl, !mt->input_active(), + Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))); return true; } diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 468cdf2244..18ad28d774 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -38,6 +38,7 @@ #include #include "ardour/debug.h" +#include "ardour/midi_track.h" #include "ardour/plugin_manager.h" #include "ardour/route_group.h" #include "ardour/session.h" @@ -1888,7 +1889,7 @@ Mixer_UI::set_route_targets_for_operation () return; } - /* try to get mixer strip at mouse */ + /* nothing selected ... try to get mixer strip at mouse */ int x, y; get_pointer (x, y); @@ -1908,3 +1909,23 @@ Mixer_UI::monitor_section_going_away () _monitor_section->set_session (0); } } + +void +Mixer_UI::toggle_midi_input_active (bool flip_others) +{ + boost::shared_ptr rl (new RouteList); + bool onoff; + + set_route_targets_for_operation (); + + for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) { + boost::shared_ptr mt = (*r)->midi_track(); + + if (mt) { + rl->push_back ((*r)->route()); + onoff = !mt->input_active(); + } + } + + _session->set_exclusive_input_active (rl, onoff, flip_others); +} diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 624181356e..2946d0ae59 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -129,6 +129,7 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR bool strip_scroller_button_release (GdkEventButton*); void scroll_left (); void scroll_right (); + void toggle_midi_input_active (bool flip_others); void add_strips (ARDOUR::RouteList&); void remove_strip (MixerStrip *); diff --git a/gtk2_ardour/mnemonic-us.bindings.in b/gtk2_ardour/mnemonic-us.bindings.in index cb50b05242..a10f59d95a 100644 --- a/gtk2_ardour/mnemonic-us.bindings.in +++ b/gtk2_ardour/mnemonic-us.bindings.in @@ -157,6 +157,7 @@ This mode provides many different operations on both regions and control points, @eep|Region/insert-region-from-region-list|i|insert from region list @select|Editor/invert-selection|<@TERTIARY@>i|invert selection @sess|Editor/addExistingAudioFiles|<@PRIMARY@>i|import audio files +@sess|Editor/toggle-midi-input-active|<@SECONDARY@>i|toggle selected track(s) MIDI input @mmode|MouseMode/set-mouse-mode-object|o|object mode @sess|Main/Open|<@PRIMARY@>o|open an existing session @sess|Main/Recent|<@PRIMARY@><@TERTIARY@>o|open a recent session diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 521054dfdf..d86b919111 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -251,7 +251,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi boost::shared_ptr route_by_id (PBD::ID); boost::shared_ptr route_by_remote_id (uint32_t id); boost::shared_ptr track_by_diskstream_id (PBD::ID); - void routes_using_input_from (const std::string& str, RouteList& rl); + void routes_using_input_from (const std::string& str, RouteList& rl); bool route_name_unique (std::string) const; bool route_name_internal (std::string) const; @@ -616,8 +616,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void set_listen (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_record_enabled (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_solo_isolated (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); - void set_exclusive_input_active (boost::shared_ptr rt, bool others_on); void set_monitoring (boost::shared_ptr, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); + void set_exclusive_input_active (boost::shared_ptr rt, bool onoff, bool flip_others=false); PBD::Signal1 SoloActive; PBD::Signal0 SoloChanged; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 180a6070fe..440ba026ae 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -2686,44 +2686,68 @@ Session::io_name_is_legal (const std::string& name) } void -Session::set_exclusive_input_active (boost::shared_ptr rt, bool /*others_on*/) +Session::set_exclusive_input_active (boost::shared_ptr rl, bool onoff, bool flip_others) { - RouteList rl; + RouteList rl2; vector connections; - PortSet& ps (rt->input()->ports()); + /* if we are passed only a single route and we're not told to turn + * others off, then just do the simple thing. + */ - for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) { - p->get_connections (connections); - } - - for (vector::iterator s = connections.begin(); s != connections.end(); ++s) { - routes_using_input_from (*s, rl); - } - - /* scan all relevant routes to see if others are on or off */ - - bool others_are_already_on = false; - - for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) { - if ((*r) != rt) { - boost::shared_ptr mt = boost::dynamic_pointer_cast (*r); - if (mt) { - if (mt->input_active()) { - others_are_already_on = true; - break; - } - } + if (flip_others == false && rl->size() == 1) { + boost::shared_ptr mt = boost::dynamic_pointer_cast (rl->front()); + if (mt) { + mt->set_input_active (onoff); + return; } } - /* globally reverse other routes */ + for (RouteList::iterator rt = rl->begin(); rt != rl->end(); ++rt) { + + PortSet& ps ((*rt)->input()->ports()); + + for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) { + p->get_connections (connections); + } + + for (vector::iterator s = connections.begin(); s != connections.end(); ++s) { + routes_using_input_from (*s, rl2); + } + + /* scan all relevant routes to see if others are on or off */ + + bool others_are_already_on = false; + + for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) { - for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) { - if ((*r) != rt) { boost::shared_ptr mt = boost::dynamic_pointer_cast (*r); - if (mt) { - mt->set_input_active (!others_are_already_on); + + if (!mt) { + continue; + } + + if ((*r) != (*rt)) { + if (mt->input_active()) { + others_are_already_on = true; + } + } else { + /* this one needs changing */ + mt->set_input_active (onoff); + } + } + + if (flip_others) { + + /* globally reverse other routes */ + + for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) { + if ((*r) != (*rt)) { + boost::shared_ptr mt = boost::dynamic_pointer_cast (*r); + if (mt) { + mt->set_input_active (!others_are_already_on); + } + } } } } @@ -2732,7 +2756,7 @@ Session::set_exclusive_input_active (boost::shared_ptr rt, bool /*others_ void Session::routes_using_input_from (const string& str, RouteList& rl) { - boost::shared_ptr r = routes.reader (); + boost::shared_ptr r = routes.reader(); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->input()->connected_to (str)) {