+
+void
+MackieControlProtocol::add_down_button (AutomationType a, int surface, int strip)
+{
+ DownButtonMap::iterator m = _down_buttons.find (a);
+
+ if (m == _down_buttons.end()) {
+ _down_buttons[a] = DownButtonList();
+ }
+
+ _down_buttons[a].insert ((surface<<8)|(strip&0xf));
+}
+
+void
+MackieControlProtocol::remove_down_button (AutomationType a, int surface, int strip)
+{
+ DownButtonMap::iterator m = _down_buttons.find (a);
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("removing surface %1 strip %2 from down buttons for %3\n", surface, strip, (int) a));
+
+ if (m == _down_buttons.end()) {
+ return;
+ }
+
+ DownButtonList& l (m->second);
+ DownButtonList::iterator x = find (l.begin(), l.end(), (surface<<8)|(strip&0xf));
+
+ if (x != l.end()) {
+ l.erase (x);
+ } else {
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 not found in down buttons for %3\n",
+ surface, strip, (int) a));
+ }
+}
+
+MackieControlProtocol::ControlList
+MackieControlProtocol::down_controls (AutomationType p)
+{
+ ControlList controls;
+ RouteList routes;
+
+ DownButtonMap::iterator m = _down_buttons.find (p);
+
+ if (m == _down_buttons.end()) {
+ return controls;
+ }
+
+ 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);
+
+ switch (p) {
+ case GainAutomation:
+ for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) {
+ controls.push_back ((*r)->gain_control());
+ }
+ break;
+ case SoloAutomation:
+ for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) {
+ controls.push_back ((*r)->solo_control());
+ }
+ break;
+ case MuteAutomation:
+ for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) {
+ controls.push_back ((*r)->mute_control());
+ }
+ break;
+ case RecEnableAutomation:
+ for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) {
+ boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
+ if (trk) {
+ controls.push_back (trk->rec_enable_control());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return controls;
+
+}
+
+struct ButtonRangeSorter {
+ bool operator() (const uint32_t& a, const uint32_t& b) {
+ return (a>>8) < (b>>8) // a.surface < b.surface
+ ||
+ ((a>>8) == (b>>8) && (a&0xf) < (b&0xf)); // a.surface == b.surface && a.strip < b.strip
+ }
+};
+
+void
+MackieControlProtocol::pull_route_range (DownButtonList& down, RouteList& selected)
+{
+ ButtonRangeSorter cmp;
+
+ if (down.empty()) {
+ return;
+ }
+
+ list<uint32_t> ldown;
+ ldown.insert (ldown.end(), down.begin(), down.end());
+ ldown.sort (cmp);
+
+ uint32_t first = ldown.front();
+ uint32_t last = ldown.back ();
+
+ uint32_t first_surface = first>>8;
+ uint32_t first_strip = first&0xf;
+
+ uint32_t last_surface = last>>8;
+ uint32_t last_strip = last&0xf;
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("PRR %5 in list %1.%2 - %3.%4\n", first_surface, first_strip, last_surface, last_strip,
+ down.size()));
+
+ for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
+
+ if ((*s)->number() >= first_surface && (*s)->number() <= last_surface) {
+
+ uint32_t fs;
+ uint32_t ls;
+
+ if ((*s)->number() == first_surface) {
+ fs = first_strip;
+ } else {
+ fs = 0;
+ }
+
+ if ((*s)->number() == last_surface) {
+ ls = last_strip;
+ ls += 1;
+ } else {
+ ls = (*s)->n_strips ();
+ }
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("adding strips for surface %1 (%2 .. %3)\n",
+ (*s)->number(), fs, ls));
+
+ for (uint32_t n = fs; n < ls; ++n) {
+ boost::shared_ptr<Route> r = (*s)->nth_strip (n)->route();
+ if (r) {
+ selected.push_back (r);
+ }
+ }
+ }
+ }
+}
+
+void
+MackieControlProtocol::set_ipmidi_base (int16_t portnum)
+{
+ /* this will not be saved without a session save, so .. */
+
+ session->set_dirty ();
+
+ _ipmidi_base = portnum;
+
+ /* if the current device uses ipMIDI we need
+ to restart.
+ */
+
+ if (_active && _device_info.uses_ipmidi()) {
+ needs_ipmidi_restart = true;
+ }
+}
+
+void
+MackieControlProtocol::ipmidi_restart ()
+{
+ clear_ports ();
+ surfaces.clear ();
+ create_surfaces ();
+ switch_banks (_current_initial_bank, true);
+ needs_ipmidi_restart = false;
+}