X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Fmackie%2Fmackie_control_protocol.cc;h=2ea61cc9f0baf0b64ab0a71964f834e10b55c2a8;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=260fe9a26ee1aeb9a7de9f7f2a33b58a66b48560;hpb=6780b7eb541ad8406fcb8633920b2074a1908a28;p=ardour.git diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 260fe9a26e..2ea61cc9f0 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -52,6 +52,7 @@ #include "ardour/panner.h" #include "ardour/panner_shell.h" #include "ardour/profile.h" +#include "ardour/record_enable_control.h" #include "ardour/route.h" #include "ardour/route_group.h" #include "ardour/session.h" @@ -59,6 +60,7 @@ #include "ardour/track.h" #include "ardour/types.h" #include "ardour/audioengine.h" +#include "ardour/vca_manager.h" #include "mackie_control_protocol.h" @@ -81,7 +83,7 @@ using namespace Glib; using namespace ArdourSurface; using namespace Mackie; -#include "i18n.h" +#include "pbd/i18n.h" #include "pbd/abstract_ui.cc" // instantiate template @@ -116,7 +118,6 @@ MackieControlProtocol::MackieControlProtocol (Session& session) , _flip_mode (Normal) , _view_mode (Mixer) , _subview_mode (None) - , _pot_mode (Pan) , _current_selected_track (-1) , _modifier_state (0) , _ipmidi_base (MIDI::IPMIDIPort::lowest_ipmidi_port_default) @@ -137,9 +138,7 @@ MackieControlProtocol::MackieControlProtocol (Session& session) _last_bank[i] = 0; } - _last_bank[Mixer] = _current_selected_track; - - TrackSelectionChanged.connect (gui_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::gui_track_selection_changed, this, _1, true), this); + PresentationInfo::Change.connect (gui_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_presentation_info_changed, this), this); _instance = this; @@ -213,7 +212,6 @@ MackieControlProtocol::ping_devices () } // go to the previous track. -// Assume that get_sorted_routes().size() > route_table.size() void MackieControlProtocol::prev_track() { @@ -223,145 +221,128 @@ MackieControlProtocol::prev_track() } // go to the next track. -// Assume that get_sorted_routes().size() > route_table.size() void MackieControlProtocol::next_track() { - Sorted sorted = get_sorted_routes(); + Sorted sorted = get_sorted_stripables(); if (_current_initial_bank + n_strips() < sorted.size()) { switch_banks (_current_initial_bank + 1); } } bool -MackieControlProtocol::route_is_locked_to_strip (boost::shared_ptr r) const +MackieControlProtocol::stripable_is_locked_to_strip (boost::shared_ptr r) const { for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) { - if ((*si)->route_is_locked_to_strip (r)) { + if ((*si)->stripable_is_locked_to_strip (r)) { return true; } } return false; } -// predicate for sort call in get_sorted_routes -struct RouteByRemoteId +// predicate for sort call in get_sorted_stripables +struct StripableByPresentationOrder { - bool operator () (const boost::shared_ptr & a, const boost::shared_ptr & b) const + bool operator () (const boost::shared_ptr & a, const boost::shared_ptr & b) const { - return a->remote_control_id() < b->remote_control_id(); + return a->presentation_info().order() < b->presentation_info().order(); } - bool operator () (const Route & a, const Route & b) const + bool operator () (const Stripable & a, const Stripable & b) const { - return a.remote_control_id() < b.remote_control_id(); + return a.presentation_info().order() < b.presentation_info().order(); } - bool operator () (const Route * a, const Route * b) const + bool operator () (const Stripable * a, const Stripable * b) const { - return a->remote_control_id() < b->remote_control_id(); + return a->presentation_info().order() < b->presentation_info().order(); } }; MackieControlProtocol::Sorted -MackieControlProtocol::get_sorted_routes() +MackieControlProtocol::get_sorted_stripables() { Sorted sorted; - // fetch all routes - boost::shared_ptr routes = session->get_routes(); - set remote_ids; - - // routes with remote_id 0 should never be added - // TODO verify this with ardour devs - // remote_ids.insert (0); + // fetch all stripables + StripableList stripables; - // sort in remote_id order, and exclude master, control and hidden routes - // and any routes that are already set. + session->get_stripables (stripables); - for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it) { + // sort in presentation order, and exclude master, control and hidden stripables + // and any stripables that are already set. - boost::shared_ptr route = *it; + for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) { - if (remote_ids.find (route->remote_control_id()) != remote_ids.end()) { - continue; - } + boost::shared_ptr s = *it; - if (route->is_auditioner() || route->is_master() || route->is_monitor()) { + if (s->presentation_info().special()) { continue; } /* don't include locked routes */ - if (route_is_locked_to_strip(route)) { + if (stripable_is_locked_to_strip (s)) { continue; } switch (_view_mode) { case Mixer: - if (! is_hidden(route)) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (!s->presentation_info().hidden()) { + sorted.push_back (s); } break; case AudioTracks: - if (is_audio_track(route) && !is_hidden(route)) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (is_audio_track(s) && !s->presentation_info().hidden()) { + sorted.push_back (s); } break; case Busses: if (Profile->get_mixbus()) { #ifdef MIXBUS - if (route->mixbus()) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (s->mixbus()) { + sorted.push_back (s); } #endif } else { - if (!is_track(route) && !is_hidden(route)) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (!is_track(s) && !s->presentation_info().hidden()) { + sorted.push_back (s); } } break; case MidiTracks: - if (is_midi_track(route) && !is_hidden(route)) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (is_midi_track(s) && !s->presentation_info().hidden()) { + sorted.push_back (s); } break; case Plugins: break; case Auxes: // in ardour, for now aux and buss are same. for mixbus, "Busses" are mixbuses, "Auxes" are ardour buses #ifdef MIXBUS - if (!route->mixbus() && !is_track(route) && !is_hidden(route)) + if (!s->mixbus() && !is_track() && !s->presentation_info().hidden()) #else - if (!is_track(route) && !is_hidden(route)) + if (!is_track(s) && !s->presentation_info().hidden()) #endif { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + sorted.push_back (s); } break; case Hidden: // Show all the tracks we have hidden - if (is_hidden(route)) { + if (s->presentation_info().hidden()) { // maybe separate groups - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + sorted.push_back (s); } break; case Selected: // For example: a group (this is USER) - if (selected(route) && !is_hidden(route)) { - sorted.push_back (route); - remote_ids.insert (route->remote_control_id()); + if (s->presentation_info().selected() && !s->presentation_info().hidden()) { + sorted.push_back (s); } break; } - } - sort (sorted.begin(), sorted.end(), RouteByRemoteId()); + sort (sorted.begin(), sorted.end(), StripableByPresentationOrder()); return sorted; } @@ -393,60 +374,68 @@ MackieControlProtocol::switch_banks (uint32_t initial, bool force) return 0; } - Sorted sorted = get_sorted_routes(); + Sorted sorted = get_sorted_stripables(); uint32_t strip_cnt = n_strips (false); // do not include locked strips // in this count - if (initial >= sorted.size()) { + if (initial >= sorted.size() && !force) { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("bank target %1 exceeds route range %2\n", + _current_initial_bank, sorted.size())); /* too high, we can't get there */ return -1; } if (sorted.size() <= strip_cnt && _current_initial_bank == 0 && !force) { - /* no banking - not enough routes to fill all strips and we're + /* no banking - not enough stripables to fill all strips and we're * not at the first one. */ + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("less routes (%1) than strips (%2) and we're at the end already (%3)\n", + sorted.size(), strip_cnt, _current_initial_bank)); return -1; } _current_initial_bank = initial; _current_selected_track = -1; - // Map current bank of routes onto each surface(+strip) + // Map current bank of stripables onto each surface(+strip) if (_current_initial_bank < sorted.size()) { - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available routes %3 on %4 surfaces\n", + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available stripables %3 on %4 surfaces\n", _current_initial_bank, strip_cnt, sorted.size(), surfaces.size())); - // link routes to strips + // link stripables to strips Sorted::iterator r = sorted.begin() + _current_initial_bank; for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) { - vector > routes; + vector > stripables; uint32_t added = 0; - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface has %1 unlockedstrips\n", (*si)->n_strips (false))); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface has %1 unlocked strips\n", (*si)->n_strips (false))); for (; r != sorted.end() && added < (*si)->n_strips (false); ++r, ++added) { - routes.push_back (*r); + stripables.push_back (*r); } - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("give surface %1 routes\n", routes.size())); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("give surface %1 stripables\n", stripables.size())); - (*si)->map_routes (routes); + (*si)->map_stripables (stripables); } } else { + /* all strips need to be reset */ + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("clear all strips, bank target %1 is outside route range %2\n", + _current_initial_bank, sorted.size())); + for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) { + vector > stripables; + /* pass in an empty stripables list, so that all strips will be reset */ + (*si)->map_stripables (stripables); + } return -1; } - /* make sure selection is correct */ - - _gui_track_selection_changed (&_last_selected_routes, false, false); - /* current bank has not been saved */ session->set_dirty(); @@ -651,14 +640,10 @@ MackieControlProtocol::update_global_led (int id, LedState ls) void MackieControlProtocol::device_ready () { - /* this is not required to be called, but for devices which do - * handshaking, it can be called once the device has verified the - * connection. - */ - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device ready init (active=%1)\n", active())); update_surfaces (); - set_pot_mode (_pot_mode); + set_subview_mode (MackieControlProtocol::None, boost::shared_ptr()); + set_flip_mode (Normal); } // send messages to surface to set controls to correct values @@ -710,8 +695,10 @@ void MackieControlProtocol::connect_session_signals() { // receive routes added - session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_route_added, this, _1), this); - session->RouteAddedOrRemoved.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_route_added_or_removed, this), this); + session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this); + // receive VCAs added + session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_vca_added, this, _1), this); + // receive record state toggled session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_record_state_changed, this), this); // receive transport state changed @@ -724,12 +711,8 @@ MackieControlProtocol::connect_session_signals() session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), this); // make sure remote id changed signals reach here - // see also notify_route_added - Sorted sorted = get_sorted_routes(); - - for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) { - (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_remote_id_changed, this), this); - } + // see also notify_stripable_added + Sorted sorted = get_sorted_stripables(); } void @@ -874,7 +857,7 @@ MackieControlProtocol::create_surfaces () XMLNode* this_device = 0; XMLNodeList const& devices = configuration_state->children(); for (XMLNodeList::const_iterator d = devices.begin(); d != devices.end(); ++d) { - XMLProperty* prop = (*d)->property (X_("name")); + XMLProperty const * prop = (*d)->property (X_("name")); if (prop && prop->value() == _device_info.name()) { this_device = *d; break; @@ -972,7 +955,7 @@ MackieControlProtocol::close() { port_connection.disconnect (); session_connections.drop_connections (); - route_connections.drop_connections (); + stripable_connections.drop_connections (); periodic_connection.disconnect (); clear_surfaces(); @@ -1038,6 +1021,12 @@ MackieControlProtocol::get_state() return node; } +bool +MackieControlProtocol::profile_exists (string const & name) const +{ + return DeviceProfile::device_profiles.find (name) != DeviceProfile::device_profiles.end(); +} + int MackieControlProtocol::set_state (const XMLNode & node, int version) { @@ -1068,13 +1057,38 @@ MackieControlProtocol::set_state (const XMLNode & node, int version) if (prop->value().empty()) { string default_profile_name; - default_profile_name = Glib::get_user_name(); - default_profile_name += ' '; - default_profile_name += _device_info.name(); + /* start by looking for a user-edited profile for the current device name */ + + default_profile_name = DeviceProfile::name_when_edited (_device_info.name()); + + if (!profile_exists (default_profile_name)) { + + /* no user-edited profile for this device name, so try the user-edited default profile */ + + default_profile_name = DeviceProfile::name_when_edited (DeviceProfile::default_profile_name); + + if (!profile_exists (default_profile_name)) { + + /* no user-edited version, so just try the device name */ + + default_profile_name = _device_info.name(); + + if (!profile_exists (default_profile_name)) { + + /* no generic device specific profile, just try the fixed default */ + default_profile_name = DeviceProfile::default_profile_name; + } + } + } set_profile (default_profile_name); + } else { - set_profile (prop->value()); + if (profile_exists (prop->value())) { + set_profile (prop->value()); + } else { + set_profile (DeviceProfile::default_profile_name); + } } } @@ -1194,20 +1208,28 @@ MackieControlProtocol::update_timecode_display() void MackieControlProtocol::notify_parameter_changed (std::string const & p) { if (p == "punch-in") { - // no such button right now - // update_global_button (Button::PunchIn, session->config.get_punch_in()); + update_global_button (Button::Drop, session->config.get_punch_in() ? flashing : off); } else if (p == "punch-out") { - // no such button right now - // update_global_button (Button::PunchOut, session->config.get_punch_out()); + update_global_button (Button::Replace, session->config.get_punch_out() ? flashing : off); } else if (p == "clicking") { update_global_button (Button::Click, Config->get_clicking()); + } else if (p == "follow-edits") { + /* we can't respond to this at present, because "follow-edits" + * is a property of the (G)UI configuration object, to which we + * have no access. For now, this means that the lit state of + * this button (if there is one) won't reflect the setting. + */ + + //update_global_button (Button::Enter, session->config.get_follow_edits() ? on : off); + } else if (p == "external-sync") { + update_global_button (Button::Cancel, session->config.get_external_sync() ? on : off); } else { DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p)); } } void -MackieControlProtocol::notify_route_added_or_removed () +MackieControlProtocol::notify_stripable_removed () { Glib::Threads::Mutex::Lock lm (surfaces_lock); for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { @@ -1215,9 +1237,15 @@ MackieControlProtocol::notify_route_added_or_removed () } } -// RouteList is the set of routes that have just been added void -MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl) +MackieControlProtocol::notify_vca_added (ARDOUR::VCAList& vl) +{ + refresh_current_bank (); +} + +// RouteList is the set of Routes that have just been added +void +MackieControlProtocol::notify_routes_added (ARDOUR::RouteList & rl) { { Glib::Threads::Mutex::Lock lm (surfaces_lock); @@ -1242,13 +1270,6 @@ MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl) refresh_current_bank(); // otherwise route added, but current bank needs no updating - - // make sure remote id changes in the new route are handled - typedef ARDOUR::RouteList ARS; - - for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) { - (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_remote_id_changed, this), this); - } } void @@ -1276,7 +1297,7 @@ MackieControlProtocol::notify_solo_active_changed (bool active) } void -MackieControlProtocol::notify_remote_id_changed() +MackieControlProtocol::notify_presentation_info_changed () { { Glib::Threads::Mutex::Lock lm (surfaces_lock); @@ -1286,7 +1307,7 @@ MackieControlProtocol::notify_remote_id_changed() } } - Sorted sorted = get_sorted_routes(); + Sorted sorted = get_sorted_stripables(); uint32_t sz = n_strips(); // if a remote id has been moved off the end, we need to shift @@ -1329,11 +1350,6 @@ MackieControlProtocol::notify_transport_state_changed() update_global_button (Button::Rewind, session->transport_speed() < 0.0); update_global_button (Button::Ffwd, session->transport_speed() > 1.0); - /* turn off any LEDs for range buttons */ - - update_global_button (Button::Drop, off); - update_global_button (Button::Replace, off); - // sometimes a return to start leaves time code at old time _timecode_last = string (10, ' '); @@ -1614,7 +1630,7 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port) if (ioc & IO_IN) { - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("something happend on %1\n", port->name())); + // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("something happend on %1\n", port->name())); /* Devices using regular JACK MIDI ports will need to have the x-thread FIFO drained to avoid burning endless CPU. @@ -1631,7 +1647,7 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port) } } - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name())); + // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name())); framepos_t now = session->engine().sample_time(); port->parse (now); } @@ -1649,15 +1665,15 @@ MackieControlProtocol::clear_ports () } void -MackieControlProtocol::notify_subview_route_deleted () +MackieControlProtocol::notify_subview_stripable_deleted () { /* return to global/mixer view */ - _subview_route.reset (); + _subview_stripable.reset (); set_view_mode (Mixer); } bool -MackieControlProtocol::subview_mode_would_be_ok (SubViewMode mode, boost::shared_ptr r) +MackieControlProtocol::subview_mode_would_be_ok (SubViewMode mode, boost::shared_ptr r) { switch (mode) { case None: @@ -1681,6 +1697,11 @@ MackieControlProtocol::subview_mode_would_be_ok (SubViewMode mode, boost::shared return true; } break; + + case TrackView: + if (r) { + return true; + } } return false; @@ -1705,13 +1726,18 @@ MackieControlProtocol::redisplay_subview_mode () } int -MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr r) +MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr r) { - SubViewMode old_mode = _subview_mode; - boost::shared_ptr old_route = _subview_route; + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set subview mode %1 with stripable %2, current flip mode %3\n", sm, (r ? r->name() : string ("null")), _flip_mode)); + + if (_flip_mode != Normal) { + set_flip_mode (Normal); + } if (!subview_mode_would_be_ok (sm, r)) { + DEBUG_TRACE (DEBUG::MackieControl, "subview mode not OK\n"); + if (r) { Glib::Threads::Mutex::Lock lm (surfaces_lock); @@ -1730,6 +1756,8 @@ MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr old_stripable = _subview_stripable; - if (r) { - /* retain _subview_route even if it is reset to null implicitly */ - _subview_route = r; - } + _subview_mode = sm; + _subview_stripable = r; - if ((_subview_mode != old_mode) || (_subview_route != old_route)) { + if (_subview_stripable != old_stripable) { + subview_stripable_connections.drop_connections (); - if (r != old_route) { - subview_route_connections.drop_connections (); - if (_subview_route) { - _subview_route->DropReferences.connect (subview_route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_subview_route_deleted, this), this); - } + /* Catch the current subview stripable going away */ + if (_subview_stripable) { + _subview_stripable->DropReferences.connect (subview_stripable_connections, MISSING_INVALIDATOR, + boost::bind (&MackieControlProtocol::notify_subview_stripable_deleted, this), + this); } + } - /* subview mode did actually change */ - - redisplay_subview_mode (); - - if (_subview_mode != old_mode) { + redisplay_subview_mode (); - /* turn buttons related to vpot mode on or off as required */ + /* turn buttons related to vpot mode on or off as required */ - switch (_subview_mode) { - case MackieControlProtocol::None: - pot_mode_globals (); - break; - case MackieControlProtocol::EQ: - update_global_button (Button::Send, off); - update_global_button (Button::Plugin, off); - update_global_button (Button::Eq, on); - update_global_button (Button::Dyn, off); - update_global_button (Button::Track, off); - update_global_button (Button::Pan, off); - break; - case MackieControlProtocol::Dynamics: - update_global_button (Button::Send, off); - update_global_button (Button::Plugin, off); - update_global_button (Button::Eq, off); - update_global_button (Button::Dyn, on); - update_global_button (Button::Track, off); - update_global_button (Button::Pan, off); - break; - case MackieControlProtocol::Sends: - update_global_button (Button::Send, on); - update_global_button (Button::Plugin, off); - update_global_button (Button::Eq, off); - update_global_button (Button::Dyn, off); - update_global_button (Button::Track, off); - update_global_button (Button::Pan, off); - break; - } - } + switch (_subview_mode) { + case MackieControlProtocol::None: + update_global_button (Button::Send, off); + update_global_button (Button::Plugin, off); + update_global_button (Button::Eq, off); + update_global_button (Button::Dyn, off); + update_global_button (Button::Track, off); + update_global_button (Button::Pan, on); + break; + case MackieControlProtocol::EQ: + update_global_button (Button::Send, off); + update_global_button (Button::Plugin, off); + update_global_button (Button::Eq, on); + update_global_button (Button::Dyn, off); + update_global_button (Button::Track, off); + update_global_button (Button::Pan, off); + break; + case MackieControlProtocol::Dynamics: + update_global_button (Button::Send, off); + update_global_button (Button::Plugin, off); + update_global_button (Button::Eq, off); + update_global_button (Button::Dyn, on); + update_global_button (Button::Track, off); + update_global_button (Button::Pan, off); + break; + case MackieControlProtocol::Sends: + update_global_button (Button::Send, on); + update_global_button (Button::Plugin, off); + update_global_button (Button::Eq, off); + update_global_button (Button::Dyn, off); + update_global_button (Button::Track, off); + update_global_button (Button::Pan, off); + break; + case MackieControlProtocol::TrackView: + update_global_button (Button::Send, off); + update_global_button (Button::Plugin, off); + update_global_button (Button::Eq, off); + update_global_button (Button::Dyn, off); + update_global_button (Button::Track, on); + update_global_button (Button::Pan, off); + break; } return 0; @@ -1812,18 +1847,21 @@ MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr()); + set_subview_mode (None, boost::shared_ptr()); display_view_mode (); } @@ -1840,85 +1878,35 @@ MackieControlProtocol::display_view_mode () void MackieControlProtocol::set_flip_mode (FlipMode fm) { - if (_flip_mode != fm) { - if (fm == Normal) { - update_global_button (Button::Flip, off); - } else { - update_global_button (Button::Flip, on); - } - - Glib::Threads::Mutex::Lock lm (surfaces_lock); - - _flip_mode = fm; - - for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { - (*s)->update_flip_mode_display (); - } - } -} - -void -MackieControlProtocol::set_pot_mode (PotMode m) -{ - // maybe not in flip mode. - if (flip_mode()) { - return; + if (fm == Normal) { + update_global_button (Button::Flip, off); + } else { + update_global_button (Button::Flip, on); } - /* switch to a pot mode cancels any subview mode */ - - set_subview_mode (None, boost::shared_ptr()); + Glib::Threads::Mutex::Lock lm (surfaces_lock); - _pot_mode = m; + _flip_mode = fm; - { - Glib::Threads::Mutex::Lock lm (surfaces_lock); - - for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { - (*s)->update_potmode (); - - } + for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { + (*s)->update_flip_mode_display (); } - - pot_mode_globals (); -} - -void -MackieControlProtocol::pot_mode_globals () -{ - switch (_pot_mode) { - case Trim: - update_global_button (Button::Eq, off); - update_global_button (Button::Dyn, off); - update_global_button (Button::Track, on); - update_global_button (Button::Send, off); - update_global_button (Button::Plugin, off); - update_global_button (Button::Pan, off); - break; - case Pan: - update_global_button (Button::Eq, off); - update_global_button (Button::Dyn, off); - update_global_button (Button::Track, off); - update_global_button (Button::Send, off); - update_global_button (Button::Plugin, off); - update_global_button (Button::Pan, on); - }; } void MackieControlProtocol::set_master_on_surface_strip (uint32_t surface, uint32_t strip_number) { - force_special_route_to_strip (session->master_out(), surface, strip_number); + force_special_stripable_to_strip (session->master_out(), surface, strip_number); } void MackieControlProtocol::set_monitor_on_surface_strip (uint32_t surface, uint32_t strip_number) { - force_special_route_to_strip (session->monitor_out(), surface, strip_number); + force_special_stripable_to_strip (session->monitor_out(), surface, strip_number); } void -MackieControlProtocol::force_special_route_to_strip (boost::shared_ptr r, uint32_t surface, uint32_t strip_number) +MackieControlProtocol::force_special_stripable_to_strip (boost::shared_ptr r, uint32_t surface, uint32_t strip_number) { if (!r) { return; @@ -1930,81 +1918,19 @@ MackieControlProtocol::force_special_route_to_strip (boost::shared_ptr r, if ((*s)->number() == surface) { Strip* strip = (*s)->nth_strip (strip_number); if (strip) { - strip->set_route (session->master_out()); + strip->set_stripable (session->master_out()); strip->lock_controls (); } } } } -void -MackieControlProtocol::gui_track_selection_changed (ARDOUR::RouteNotificationListPtr rl, bool save_list) -{ - _gui_track_selection_changed (rl.get(), save_list, true); -} - -void -MackieControlProtocol::_gui_track_selection_changed (ARDOUR::RouteNotificationList* rl, bool save_list, bool gui_selection_did_change) -{ - /* We need to keep a list of the most recently selected routes around, - but we are not allowed to keep shared_ptr unless we want to - handle the complexities of route deletion. So instead, the GUI sends - us a notification using weak_ptr, which we keep a copy - of. For efficiency's sake, however, we convert the weak_ptr's into - shared_ptr before passing them to however many surfaces (and - thus strips) that we have. - */ - - StrongRouteNotificationList srl; - - for (ARDOUR::RouteNotificationList::const_iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr r = (*i).lock(); - if (r) { - srl.push_back (r); - } - } - - { - Glib::Threads::Mutex::Lock lm (surfaces_lock); - - for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { - (*s)->gui_selection_changed (srl); - } - } - - if (save_list) { - _last_selected_routes = *rl; - } - - if (gui_selection_did_change) { - - check_fader_automation_state (); - - /* note: this method is also called when we switch banks. - * But ... we don't allow bank switching when in subview mode. - * - * so .. we only have to care about subview mode if the - * GUI selection has changed. - * - * It is possible that first_selected_route() may return null if we - * are no longer displaying/mapping that route. In that case, - * we will exit subview mode. If first_selected_route() is - * null, and subview mode is not None, then the first call to - * set_subview_mode() will fail, and we will reset to None. - */ - - if (set_subview_mode (_subview_mode, first_selected_route())) { - set_subview_mode (None, boost::shared_ptr()); - } - } -} - void MackieControlProtocol::check_fader_automation_state () { fader_automation_connections.drop_connections (); - boost::shared_ptr r = first_selected_route (); + boost::shared_ptr r = first_selected_stripable (); if (!r) { update_global_button (Button::Read, off); @@ -2027,7 +1953,7 @@ MackieControlProtocol::check_fader_automation_state () void MackieControlProtocol::update_fader_automation_state () { - boost::shared_ptr r = first_selected_route (); + boost::shared_ptr r = first_selected_stripable (); if (!r) { update_global_button (Button::Read, off); @@ -2101,24 +2027,31 @@ MackieControlProtocol::remove_down_select_button (int surface, int strip) } void -MackieControlProtocol::select_range () +MackieControlProtocol::select_range (uint32_t pressed) { - RouteList routes; + StripableList stripables; - pull_route_range (_down_select_buttons, routes); + pull_stripable_range (_down_select_buttons, stripables, pressed); - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("select range: found %1 routes\n", routes.size())); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("select range: found %1 stripables, first = %2\n", stripables.size(), stripables.front()->name())); - if (!routes.empty()) { - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { + if (stripables.empty()) { + return; + } + + if (stripables.size() == 1 && ControlProtocol::last_selected().size() == 1 && stripables.front()->presentation_info().selected()) { + /* cancel selection for one and only selected stripable */ + ToggleStripableSelection (stripables.front()); + } else { + for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { - if (main_modifier_state() == MODIFIER_CONTROL) { - ToggleRouteSelection ((*r)->remote_control_id ()); + if (main_modifier_state() == MODIFIER_SHIFT) { + ToggleStripableSelection (*s); } else { - if (r == routes.begin()) { - SetRouteSelection ((*r)->remote_control_id()); + if (s == stripables.begin()) { + SetStripableSelection (*s); } else { - AddRouteToSelection ((*r)->remote_control_id()); + AddStripableToSelection (*s); } } } @@ -2160,10 +2093,10 @@ MackieControlProtocol::remove_down_button (AutomationType a, int surface, int st } MackieControlProtocol::ControlList -MackieControlProtocol::down_controls (AutomationType p) +MackieControlProtocol::down_controls (AutomationType p, uint32_t pressed) { ControlList controls; - RouteList routes; + StripableList stripables; DownButtonMap::iterator m = _down_buttons.find (p); @@ -2174,29 +2107,29 @@ MackieControlProtocol::down_controls (AutomationType p) DEBUG_TRACE (DEBUG::MackieControl, string_compose ("looking for down buttons for %1, got %2\n", p, m->second.size())); - pull_route_range (m->second, routes); + pull_stripable_range (m->second, stripables, pressed); switch (p) { case GainAutomation: - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { - controls.push_back ((*r)->gain_control()); + for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { + controls.push_back ((*s)->gain_control()); } break; case SoloAutomation: - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { - controls.push_back ((*r)->solo_control()); + for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { + controls.push_back ((*s)->solo_control()); } break; case MuteAutomation: - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { - controls.push_back ((*r)->mute_control()); + for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { + controls.push_back ((*s)->mute_control()); } break; case RecEnableAutomation: - for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) { - boost::shared_ptr trk = boost::dynamic_pointer_cast (*r); - if (trk) { - controls.push_back (trk->rec_enable_control()); + for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { + boost::shared_ptr ac = (*s)->rec_enable_control(); + if (ac) { + controls.push_back (ac); } } break; @@ -2217,7 +2150,7 @@ struct ButtonRangeSorter { }; void -MackieControlProtocol::pull_route_range (DownButtonList& down, RouteList& selected) +MackieControlProtocol::pull_stripable_range (DownButtonList& down, StripableList& selected, uint32_t pressed) { ButtonRangeSorter cmp; @@ -2267,13 +2200,19 @@ MackieControlProtocol::pull_route_range (DownButtonList& down, RouteList& select (*s)->number(), fs, ls)); for (uint32_t n = fs; n < ls; ++n) { - boost::shared_ptr r = (*s)->nth_strip (n)->route(); + Strip* strip = (*s)->nth_strip (n); + boost::shared_ptr r = strip->stripable(); if (r) { - selected.push_back (r); + if (global_index_locked (*strip) == pressed) { + selected.push_front (r); + } else { + selected.push_back (r); + } } } } } + } void @@ -2397,97 +2336,97 @@ MackieControlProtocol::connection_handler (boost::weak_ptr wp1, st } bool -MackieControlProtocol::is_track (boost::shared_ptr r) const +MackieControlProtocol::is_track (boost::shared_ptr r) const { return boost::dynamic_pointer_cast(r) != 0; } bool -MackieControlProtocol::is_audio_track (boost::shared_ptr r) const +MackieControlProtocol::is_audio_track (boost::shared_ptr r) const { return boost::dynamic_pointer_cast(r) != 0; } bool -MackieControlProtocol::is_midi_track (boost::shared_ptr r) const +MackieControlProtocol::is_midi_track (boost::shared_ptr r) const { return boost::dynamic_pointer_cast(r) != 0; } bool -MackieControlProtocol::selected (boost::shared_ptr r) const +MackieControlProtocol::is_mapped (boost::shared_ptr r) const { - const RouteNotificationList* rl = &_last_selected_routes; + Glib::Threads::Mutex::Lock lm (surfaces_lock); - for (ARDOUR::RouteNotificationList::const_iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr rt = (*i).lock(); - if (rt == r) { + for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) { + if ((*s)->stripable_is_mapped (r)) { return true; } } + return false; } -bool -MackieControlProtocol::is_hidden (boost::shared_ptr r) const +void +MackieControlProtocol::update_selected (boost::shared_ptr s, bool became_selected) { - if (!r) { - return false; - } - return (((r->remote_control_id()) >>31) != 0); -} + if (became_selected) { -bool -MackieControlProtocol::is_mapped (boost::shared_ptr r) const -{ - Glib::Threads::Mutex::Lock lm (surfaces_lock); + check_fader_automation_state (); - for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) { - if ((*s)->route_is_mapped (r)) { - return true; + /* It is possible that first_selected_route() may return null if we + * are no longer displaying/mapping that route. In that case, + * we will exit subview mode. If first_selected_route() is + * null, and subview mode is not None, then the first call to + * set_subview_mode() will fail, and we will reset to None. + */ + + if (set_subview_mode (_subview_mode, first_selected_stripable())) { + set_subview_mode (None, boost::shared_ptr()); } - } - return false; + } } -boost::shared_ptr -MackieControlProtocol::first_selected_route () const +boost::shared_ptr +MackieControlProtocol::first_selected_stripable () const { - if (_last_selected_routes.empty()) { - return boost::shared_ptr(); - } - - boost::shared_ptr r = _last_selected_routes.front().lock(); + boost::shared_ptr s = ControlProtocol::first_selected_stripable(); - if (r) { + if (s) { /* check it is on one of our surfaces */ - if (is_mapped (r)) { - return r; + if (is_mapped (s)) { + return s; } - /* route is not mapped. thus, the currently selected route is + /* stripable is not mapped. thus, the currently selected stripable is * not on the surfaces, and so from our perspective, there is - * no currently selected route. + * no currently selected stripable. */ - r.reset (); + s.reset (); } - return r; /* may be null */ + return s; /* may be null */ } -boost::shared_ptr -MackieControlProtocol::subview_route () const +boost::shared_ptr +MackieControlProtocol::subview_stripable () const { - return _subview_route; + return _subview_stripable; } uint32_t MackieControlProtocol::global_index (Strip& strip) { Glib::Threads::Mutex::Lock lm (surfaces_lock); + return global_index_locked (strip); +} + +uint32_t +MackieControlProtocol::global_index_locked (Strip& strip) +{ uint32_t global = 0; for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) { @@ -2514,7 +2453,7 @@ MackieControlProtocol::request_factory (uint32_t num_requests) void MackieControlProtocol::set_automation_state (AutoState as) { - boost::shared_ptr r = first_selected_route (); + boost::shared_ptr r = first_selected_stripable (); if (!r) { return;