use new Session API to deal with transport state
[ardour.git] / libs / surfaces / us2400 / us2400_control_protocol.cc
1 /*
2  * Copyright (C) 2017 Ben Loftis <ben@harrisonconsoles.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <fcntl.h>
20 #include <iostream>
21 #include <algorithm>
22 #include <cmath>
23 #include <sstream>
24 #include <vector>
25 #include <iomanip>
26
27 #include <inttypes.h>
28 #include <float.h>
29 #include <sys/time.h>
30 #include <errno.h>
31
32 #include <boost/shared_array.hpp>
33 #include <glibmm/miscutils.h>
34
35 #include "midi++/types.h"
36 #include "midi++/port.h"
37 #include "pbd/pthread_utils.h"
38 #include "pbd/error.h"
39 #include "pbd/memento_command.h"
40 #include "pbd/convert.h"
41
42 #include "ardour/audio_track.h"
43 #include "ardour/automation_control.h"
44 #include "ardour/async_midi_port.h"
45 #include "ardour/dB.h"
46 #include "ardour/debug.h"
47 #include "ardour/location.h"
48 #include "ardour/meter.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/profile.h"
53 #include "ardour/record_enable_control.h"
54 #include "ardour/route.h"
55 #include "ardour/route_group.h"
56 #include "ardour/session.h"
57 #include "ardour/tempo.h"
58 #include "ardour/track.h"
59 #include "ardour/types.h"
60 #include "ardour/audioengine.h"
61 #include "ardour/vca_manager.h"
62
63 #include "us2400_control_protocol.h"
64
65 #include "midi_byte_array.h"
66 #include "us2400_control_exception.h"
67 #include "device_profile.h"
68 #include "surface_port.h"
69 #include "surface.h"
70 #include "strip.h"
71 #include "control_group.h"
72 #include "meter.h"
73 #include "button.h"
74 #include "fader.h"
75 #include "pot.h"
76
77 using namespace ARDOUR;
78 using namespace std;
79 using namespace PBD;
80 using namespace Glib;
81 using namespace ArdourSurface;
82 using namespace US2400;
83
84 #include "pbd/i18n.h"
85
86 #include "pbd/abstract_ui.cc" // instantiate template
87
88 const int US2400Protocol::MODIFIER_OPTION = 0x1;
89 const int US2400Protocol::MODIFIER_CONTROL = 0x2;
90 const int US2400Protocol::MODIFIER_SHIFT = 0x4;
91 const int US2400Protocol::MODIFIER_CMDALT = 0x8;
92 const int US2400Protocol::MODIFIER_ZOOM = 0x10;
93 const int US2400Protocol::MODIFIER_SCRUB = 0x20;
94 const int US2400Protocol::MODIFIER_MARKER = 0x40;
95 const int US2400Protocol::MODIFIER_DROP = 0x80; //US2400 Drop as a modifier for In/out
96 const int US2400Protocol::MAIN_MODIFIER_MASK = (US2400Protocol::MODIFIER_OPTION|
97                                                        US2400Protocol::MODIFIER_CONTROL|
98                                                        US2400Protocol::MODIFIER_SHIFT|
99                                                        US2400Protocol::MODIFIER_CMDALT);
100
101 US2400Protocol* US2400Protocol::_instance = 0;
102
103 bool US2400Protocol::probe()
104 {
105         return true;
106 }
107
108 US2400Protocol::US2400Protocol (Session& session)
109         : ControlProtocol (session, X_("Tascam US-2400"))
110         , AbstractUI<US2400ControlUIRequest> (name())
111         , _current_initial_bank (0)
112         , _sample_last (0)
113         , _timecode_type (ARDOUR::AnyTime::BBT)
114         , _gui (0)
115         , _scrub_mode (false)
116         , _view_mode (Mixer)
117         , _subview_mode (None)
118         , _modifier_state (0)
119         , _metering_active (true)
120         , _initialized (false)
121         , configuration_state (0)
122         , state_version (0)
123         , marker_modifier_consumed_by_button (false)
124         , nudge_modifier_consumed_by_button (false)
125 {
126         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::US2400Protocol\n");
127
128 //      DeviceInfo::reload_device_info ();
129         DeviceProfile::reload_device_profiles ();
130
131         for (int i = 0; i < 9; i++) {
132                 _last_bank[i] = 0;
133         }
134
135         PresentationInfo::Change.connect (gui_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_presentation_info_changed, this, _1), this);
136
137         _instance = this;
138
139         build_button_map ();
140 }
141
142 US2400Protocol::~US2400Protocol()
143 {
144         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol init\n");
145
146         for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
147                 (*si)->reset ();
148         }
149
150         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol drop_connections ()\n");
151         drop_connections ();
152
153         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol tear_down_gui ()\n");
154         tear_down_gui ();
155
156         delete configuration_state;
157
158         /* stop event loop */
159         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol BaseUI::quit ()\n");
160         BaseUI::quit ();
161
162         try {
163                 DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol close()\n");
164                 close();
165         }
166         catch (exception & e) {
167                 cout << "~US2400Protocol caught " << e.what() << endl;
168         }
169         catch (...) {
170                 cout << "~US2400Protocol caught unknown" << endl;
171         }
172
173         _instance = 0;
174
175         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::~US2400Protocol done\n");
176 }
177
178 void
179 US2400Protocol::thread_init ()
180 {
181         pthread_set_name (event_loop_name().c_str());
182
183         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
184         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
185
186         set_thread_priority ();
187 }
188
189 // go to the previous track.
190 void
191 US2400Protocol::prev_track()
192 {
193         if (_current_initial_bank >= 1) {
194                 switch_banks (_current_initial_bank - 1);
195         }
196 }
197
198 // go to the next track.
199 void
200 US2400Protocol::next_track()
201 {
202         Sorted sorted = get_sorted_stripables();
203         if (_current_initial_bank + n_strips() < sorted.size()) {
204                 switch_banks (_current_initial_bank + 1);
205         }
206 }
207
208 bool
209 US2400Protocol::stripable_is_locked_to_strip (boost::shared_ptr<Stripable> r) const
210 {
211         for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
212                 if ((*si)->stripable_is_locked_to_strip (r)) {
213                         return true;
214                 }
215         }
216         return false;
217 }
218
219 // predicate for sort call in get_sorted_stripables
220 struct StripableByPresentationOrder
221 {
222         bool operator () (const boost::shared_ptr<Stripable> & a, const boost::shared_ptr<Stripable> & b) const
223         {
224                 return a->presentation_info().order() < b->presentation_info().order();
225         }
226
227         bool operator () (const Stripable & a, const Stripable & b) const
228         {
229                 return a.presentation_info().order() < b.presentation_info().order();
230         }
231
232         bool operator () (const Stripable * a, const Stripable * b) const
233         {
234                 return a->presentation_info().order() < b->presentation_info().order();
235         }
236 };
237
238 US2400Protocol::Sorted
239 US2400Protocol::get_sorted_stripables()
240 {
241         Sorted sorted;
242
243         // fetch all stripables
244         StripableList stripables;
245
246         session->get_stripables (stripables);
247
248         // sort in presentation order, and exclude master, control and hidden stripables
249         // and any stripables that are already set.
250
251         for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
252
253                 boost::shared_ptr<Stripable> s = *it;
254
255                 if (s->presentation_info().special()) {
256                         continue;
257                 }
258
259                 /* don't include locked routes */
260
261                 if (stripable_is_locked_to_strip (s)) {
262                         continue;
263                 }
264
265                 switch (_view_mode) {
266                 case Mixer:
267 #ifdef MIXBUS
268                         if (!s->presentation_info().hidden() && !s->mixbus()) {
269 #else
270                         if (!s->presentation_info().hidden()) {
271 #endif
272                                 sorted.push_back (s);
273                         }
274                         break;
275                 case Busses:
276 #ifdef MIXBUS
277                         if (s->mixbus()) {
278                                 sorted.push_back (s);
279                         }
280                         break;
281 #else
282                         if (!is_track(s) && !s->presentation_info().hidden()) {
283                                 sorted.push_back (s);
284                         }
285                         break;
286 #endif
287                 }
288         }
289
290         sort (sorted.begin(), sorted.end(), StripableByPresentationOrder());
291         return sorted;
292 }
293
294 void
295 US2400Protocol::refresh_current_bank()
296 {
297         switch_banks (_current_initial_bank, true);
298 }
299
300 uint32_t
301 US2400Protocol::n_strips (bool with_locked_strips) const
302 {
303         uint32_t strip_count = 0;
304
305         for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
306                 strip_count += (*si)->n_strips (with_locked_strips);
307         }
308
309         return strip_count;
310 }
311
312 int
313 US2400Protocol::switch_banks (uint32_t initial, bool force)
314 {
315         DEBUG_TRACE (DEBUG::US2400, string_compose ("switch banking to start at %1 force ? %2 current = %3\n", initial, force, _current_initial_bank));
316
317         if (initial == _current_initial_bank && !force) {
318                 /* everything is as it should be */
319                 return 0;
320         }
321
322         Sorted sorted = get_sorted_stripables();
323         uint32_t strip_cnt = n_strips (false); // do not include locked strips
324                                                // in this count
325
326         if (initial >= sorted.size() && !force) {
327                 DEBUG_TRACE (DEBUG::US2400, string_compose ("bank target %1 exceeds route range %2\n",
328                                                                    _current_initial_bank, sorted.size()));
329                 /* too high, we can't get there */
330                 return -1;
331         }
332
333         if (sorted.size() <= strip_cnt && _current_initial_bank == 0 && !force) {
334                 /* no banking - not enough stripables to fill all strips and we're
335                  * not at the first one.
336                  */
337                 DEBUG_TRACE (DEBUG::US2400, string_compose ("less routes (%1) than strips (%2) and we're at the end already (%3)\n",
338                                                                    sorted.size(), strip_cnt, _current_initial_bank));
339                 return -1;
340         }
341
342         _current_initial_bank = initial;
343
344         // Map current bank of stripables onto each surface(+strip)
345
346         if (_current_initial_bank < sorted.size()) {
347
348                 DEBUG_TRACE (DEBUG::US2400, string_compose ("switch to %1, %2, available stripables %3 on %4 surfaces\n",
349                                                                    _current_initial_bank, strip_cnt, sorted.size(),
350                                                                    surfaces.size()));
351
352                 // link stripables to strips
353
354                 Sorted::iterator r = sorted.begin() + _current_initial_bank;
355
356                 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
357                         vector<boost::shared_ptr<Stripable> > stripables;
358                         uint32_t added = 0;
359
360                         DEBUG_TRACE (DEBUG::US2400, string_compose ("surface has %1 unlocked strips\n", (*si)->n_strips (false)));
361
362                         for (; r != sorted.end() && added < (*si)->n_strips (false); ++r, ++added) {
363                                 stripables.push_back (*r);
364                         }
365
366                         DEBUG_TRACE (DEBUG::US2400, string_compose ("give surface #%1 %2 stripables\n", (*si)->number(), stripables.size()));
367
368                         (*si)->map_stripables (stripables);
369                 }
370
371         } else {
372                 /* all strips need to be reset */
373                 DEBUG_TRACE (DEBUG::US2400, string_compose ("clear all strips, bank target %1  is outside route range %2\n",
374                                                                    _current_initial_bank, sorted.size()));
375                 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
376                         vector<boost::shared_ptr<Stripable> > stripables;
377                         /* pass in an empty stripables list, so that all strips will be reset */
378                         (*si)->map_stripables (stripables);
379                 }
380                 return -1;
381         }
382
383         /* current bank has not been saved */
384         session->set_dirty();
385
386         return 0;
387 }
388
389 int
390 US2400Protocol::set_active (bool yn)
391 {
392         DEBUG_TRACE (DEBUG::US2400, string_compose("US2400Protocol::set_active init with yn: '%1'\n", yn));
393
394         if (yn == active()) {
395                 return 0;
396         }
397
398         if (yn) {
399
400                 /* start event loop */
401
402                 BaseUI::run ();
403
404                 connect_session_signals ();
405
406                 if (!_device_info.name().empty()) {
407                         set_device (_device_info.name(), true);
408                 }
409
410                 /* set up periodic task for timecode display and metering and automation
411                  */
412
413                 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (10); // milliseconds
414                 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &US2400Protocol::periodic));
415                 periodic_timeout->attach (main_loop()->get_context());
416
417                 /* periodic task used to update strip displays */
418
419                 Glib::RefPtr<Glib::TimeoutSource> redisplay_timeout = Glib::TimeoutSource::create (10); // milliseconds
420                 redisplay_connection = redisplay_timeout->connect (sigc::mem_fun (*this, &US2400Protocol::redisplay));
421                 redisplay_timeout->attach (main_loop()->get_context());
422
423         } else {
424
425                 BaseUI::quit ();
426                 close ();
427
428         }
429
430         ControlProtocol::set_active (yn);
431
432         DEBUG_TRACE (DEBUG::US2400, string_compose("US2400Protocol::set_active done with yn: '%1'\n", yn));
433
434         return 0;
435 }
436
437 bool
438 US2400Protocol::hui_heartbeat ()
439 {
440         Glib::Threads::Mutex::Lock lm (surfaces_lock);
441
442         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
443                 (*s)->hui_heartbeat ();
444         }
445
446         return true;
447 }
448
449 bool
450 US2400Protocol::periodic ()
451 {
452         if (!active()) {
453                 return false;
454         }
455
456         if (!_initialized) {
457                 initialize();
458         }
459
460         ARDOUR::microseconds_t now_usecs = ARDOUR::get_microseconds ();
461
462         {
463                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
464
465                 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
466                         (*s)->periodic (now_usecs);
467                 }
468         }
469
470         return true;
471 }
472
473 bool
474 US2400Protocol::redisplay ()
475 {
476         return true;
477 }
478
479 void
480 US2400Protocol::update_timecode_beats_led()
481 {
482 }
483
484 void
485 US2400Protocol::update_global_button (int id, LedState ls)
486 {
487         boost::shared_ptr<Surface> surface;
488
489         {
490                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
491
492                 if (surfaces.empty()) {
493                         return;
494                 }
495
496                 if (!_device_info.has_global_controls()) {
497                         return;
498                 }
499                 // surface needs to be master surface
500                 surface = _master_surface;
501         }
502
503         map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
504         if (x != surface->controls_by_device_independent_id.end()) {
505                 Button * button = dynamic_cast<Button*> (x->second);
506                 surface->write (button->set_state (ls));
507         } else {
508                 DEBUG_TRACE (DEBUG::US2400, string_compose ("Button %1 not found\n", id));
509         }
510 }
511
512 void
513 US2400Protocol::update_global_led (int id, LedState ls)
514 {
515         Glib::Threads::Mutex::Lock lm (surfaces_lock);
516
517         if (surfaces.empty()) {
518                 return;
519         }
520
521         if (!_device_info.has_global_controls()) {
522                 return;
523         }
524         boost::shared_ptr<Surface> surface = _master_surface;
525
526         map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
527
528         if (x != surface->controls_by_device_independent_id.end()) {
529                 Led * led = dynamic_cast<Led*> (x->second);
530                 DEBUG_TRACE (DEBUG::US2400, "Writing LedState\n");
531                 surface->write (led->set_state (ls));
532         } else {
533                 DEBUG_TRACE (DEBUG::US2400, string_compose ("Led %1 not found\n", id));
534         }
535 }
536
537 void
538 US2400Protocol::device_ready ()
539 {
540         DEBUG_TRACE (DEBUG::US2400, string_compose ("device ready init (active=%1)\n", active()));
541
542         //this gets called every time a new surface appears; we have to do this to reset the banking etc
543         //particularly when the user is setting it up the first time; we can't guarantee the order that they will be connected
544         
545         update_surfaces ();
546
547         set_subview_mode (US2400Protocol::None, first_selected_stripable());
548 }
549
550 // send messages to surface to set controls to correct values
551 void
552 US2400Protocol::update_surfaces()
553 {
554         DEBUG_TRACE (DEBUG::US2400, string_compose ("US2400Protocol::update_surfaces() init (active=%1)\n", active()));
555         if (!active()) {
556                 return;
557         }
558
559         // do the initial bank switch to connect signals
560         // _current_initial_bank is initialised by set_state
561         (void) switch_banks (_current_initial_bank, true);
562
563         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::update_surfaces() finished\n");
564 }
565
566 void
567 US2400Protocol::initialize()
568 {
569         {
570                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
571
572                 if (surfaces.empty()) {
573                         return;
574                 }
575
576                 if (!_master_surface->active ()) {
577                         return;
578                 }
579
580         }
581
582         update_global_button (Button::Send, on);
583         update_global_button (Button::Send, off);
584
585         update_global_button (Button::Scrub, on);
586         update_global_button (Button::Scrub, off);
587
588         notify_solo_active_changed(false);
589
590         update_global_button (Button::Pan, off);
591         update_global_button (Button::Pan, on);
592
593         update_global_button (Button::Flip, on);
594         update_global_button (Button::Flip, off);
595
596         update_global_button (Button::MstrSelect, on);
597         update_global_button (Button::MstrSelect, off);
598
599         notify_transport_state_changed();
600
601         _initialized = true;
602 }
603
604 void
605 US2400Protocol::connect_session_signals()
606 {
607         // receive routes added
608         session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_routes_added, this, _1), this);
609         // receive VCAs added
610         session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_vca_added, this, _1), this);
611
612         // receive record state toggled
613         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_record_state_changed, this), this);
614         // receive transport state changed
615         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_transport_state_changed, this), this);
616         session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_loop_state_changed, this), this);
617         // receive punch-in and punch-out
618         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_parameter_changed, this, _1), this);
619         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_parameter_changed, this, _1), this);
620         // receive rude solo changed
621         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::notify_solo_active_changed, this, _1), this);
622
623         // make sure remote id changed signals reach here
624         // see also notify_stripable_added
625         Sorted sorted = get_sorted_stripables();
626 }
627
628 void
629 US2400Protocol::set_profile (const string& profile_name)
630 {
631         map<string,DeviceProfile>::iterator d = DeviceProfile::device_profiles.find (profile_name);
632
633         if (d == DeviceProfile::device_profiles.end()) {
634                 _device_profile = DeviceProfile (profile_name);
635                 return;
636         }
637
638         _device_profile = d->second;
639 }
640
641 int
642 US2400Protocol::set_device_info (const string& device_name)
643 {
644 return 0;
645 }
646
647 int
648 US2400Protocol::set_device (const string& device_name, bool force)
649 {
650         if (device_name == device_info().name() && !force) {
651                 /* already using that device, nothing to do */
652                 return 0;
653         }
654         /* get state from the current setup, and make sure it is stored in
655            the configuration_states node so that if we switch back to this device,
656            we will have its state available.
657         */
658
659         {
660                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
661                 if (!surfaces.empty()) {
662                         update_configuration_state ();
663                 }
664         }
665
666         if (set_device_info (device_name)) {
667                 return -1;
668         }
669
670         clear_surfaces ();
671         port_connection.disconnect ();
672         hui_connection.disconnect ();
673
674         if (_device_info.device_type() == DeviceInfo::HUI) {
675                 Glib::RefPtr<Glib::TimeoutSource> hui_timeout = Glib::TimeoutSource::create (1000); // milliseconds
676                 hui_connection = hui_timeout->connect (sigc::mem_fun (*this, &US2400Protocol::hui_heartbeat));
677                 hui_timeout->attach (main_loop()->get_context());
678         }
679
680         /* notice that the handler for this will execute in our event
681            loop, not in the thread where the
682            PortConnectedOrDisconnected signal is emitted.
683         */
684         ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&US2400Protocol::connection_handler, this, _1, _2, _3, _4, _5), this);
685
686         if (create_surfaces ()) {
687                 return -1;
688         }
689
690         DeviceChanged ();
691
692         return 0;
693 }
694
695 int
696 US2400Protocol::create_surfaces ()
697 {
698         string device_name;
699         surface_type_t stype = st_mcu; // type not yet determined
700
701         DEBUG_TRACE (DEBUG::US2400, string_compose ("Create %1 surfaces for %2\n", 1 + _device_info.extenders(), _device_info.name()));
702
703         _input_bundle.reset (new ARDOUR::Bundle (_("US2400 Control In"), true));
704         _output_bundle.reset (new ARDOUR::Bundle (_("US2400 Control Out"), false));
705
706         for (uint32_t n = 0; n < 1 + _device_info.extenders(); ++n) {
707                 bool is_master = false;
708
709                 if (n == _device_info.master_position()) {
710                         is_master = true;
711                 }
712
713                 device_name = string_compose (X_("US-2400 Control %1"), n+1);
714
715                 DEBUG_TRACE (DEBUG::US2400, string_compose ("Port Name for surface %1 is %2\n", n, device_name));
716
717                 boost::shared_ptr<Surface> surface;
718
719                 if (n ==0) {
720                         stype = st_mcu;
721                 } else if (n ==1) {
722                         stype = st_ext;   //ch8..16
723                 } else if (n ==2) {
724                         stype = st_ext;   //ch17..24
725                 } else if (n ==3) {
726                         stype = st_joy;   //joystick
727                 } else if (n ==4) {
728                         stype = st_knb;   //chan knobs ???
729                 }
730                 try {
731                         surface.reset (new Surface (*this, device_name, n, stype));
732                 } catch (...) {
733                         return -1;
734                 }
735
736                 if (is_master) {
737                         _master_surface = surface;
738                 }
739
740                 if (configuration_state) {
741                         XMLNode* this_device = 0;
742                         XMLNodeList const& devices = configuration_state->children();
743                         for (XMLNodeList::const_iterator d = devices.begin(); d != devices.end(); ++d) {
744                                 XMLProperty const * prop = (*d)->property (X_("name"));
745                                 if (prop && prop->value() == _device_info.name()) {
746                                         this_device = *d;
747                                         break;
748                                 }
749                         }
750                         if (this_device) {
751                                 XMLNode* snode = this_device->child (X_("Surfaces"));
752                                 if (snode) {
753                                         surface->set_state (*snode, state_version);
754                                 }
755                         }
756                 }
757
758                 {
759                         Glib::Threads::Mutex::Lock lm (surfaces_lock);
760                         surfaces.push_back (surface);
761                 }
762
763                 if ( n <=3 ) {   //ports 5&6 are not really used by us2400
764
765                         _input_bundle->add_channel (
766                                 surface->port().input_port().name(),
767                                 ARDOUR::DataType::MIDI,
768                                 session->engine().make_port_name_non_relative (surface->port().input_port().name())
769                                 );
770
771                         _output_bundle->add_channel (
772                                 surface->port().output_port().name(),
773                                 ARDOUR::DataType::MIDI,
774                                 session->engine().make_port_name_non_relative (surface->port().output_port().name())
775                                 );
776                 }
777
778                 MIDI::Port& input_port (surface->port().input_port());
779                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (&input_port);
780
781                 if (asp) {
782
783                         /* async MIDI port */
784
785                         asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &US2400Protocol::midi_input_handler), &input_port));
786                         asp->xthread().attach (main_loop()->get_context());
787
788                 }
789         }
790
791         Glib::Threads::Mutex::Lock lm (surfaces_lock);
792         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
793                 (*s)->port().reconnect ();
794         }
795
796         session->BundleAddedOrRemoved ();
797
798         assert (_master_surface);
799
800         return 0;
801 }
802
803 void
804 US2400Protocol::close()
805 {
806         port_connection.disconnect ();
807         session_connections.drop_connections ();
808         stripable_connections.drop_connections ();
809         periodic_connection.disconnect ();
810
811         clear_surfaces();
812 }
813
814 /** Ensure that the configuration_state XML node contains an up-to-date
815  *  copy of the state node the current device. If configuration_state already
816  *  contains a state node for the device, it will deleted and replaced.
817  */
818 void
819 US2400Protocol::update_configuration_state ()
820 {
821         /* CALLER MUST HOLD SURFACES LOCK */
822
823         if (!configuration_state) {
824                 configuration_state = new XMLNode (X_("Configurations"));
825         }
826
827         XMLNode* devnode = new XMLNode (X_("Configuration"));
828         devnode->set_property (X_("name"), _device_info.name());
829
830         configuration_state->remove_nodes_and_delete (X_("name"), _device_info.name());
831         configuration_state->add_child_nocopy (*devnode);
832
833         XMLNode* snode = new XMLNode (X_("Surfaces"));
834
835         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
836                 snode->add_child_nocopy ((*s)->get_state());
837         }
838
839         devnode->add_child_nocopy (*snode);
840 }
841
842 XMLNode&
843 US2400Protocol::get_state()
844 {
845         XMLNode& node (ControlProtocol::get_state());
846
847         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::get_state init\n");
848
849         // add current bank
850         node.set_property (X_("bank"), _current_initial_bank);
851
852         node.set_property (X_("device-profile"), _device_profile.name());
853         node.set_property (X_("device-name"), _device_info.name());
854
855         {
856                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
857                 update_configuration_state ();
858         }
859
860         /* force a copy of the _surfaces_state node, because we want to retain ownership */
861         node.add_child_copy (*configuration_state);
862
863         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::get_state done\n");
864
865         return node;
866 }
867
868 bool
869 US2400Protocol::profile_exists (string const & name) const
870 {
871         return DeviceProfile::device_profiles.find (name) != DeviceProfile::device_profiles.end();
872 }
873
874 int
875 US2400Protocol::set_state (const XMLNode & node, int version)
876 {
877         DEBUG_TRACE (DEBUG::US2400, string_compose ("US2400Protocol::set_state: active %1\n", active()));
878
879         if (ControlProtocol::set_state (node, version)) {
880                 return -1;
881         }
882
883         uint32_t bank = 0;
884         // fetch current bank
885         node.get_property (X_("bank"), bank);
886
887         std::string device_name;
888         if (node.get_property (X_("device-name"), device_name)) {
889                 set_device_info (device_name);
890         }
891
892         std::string device_profile_name;
893         if (node.get_property (X_("device-profile"), device_profile_name)) {
894                 if (device_profile_name.empty()) {
895                         string default_profile_name;
896
897                         /* start by looking for a user-edited profile for the current device name */
898
899                         default_profile_name = DeviceProfile::name_when_edited (_device_info.name());
900
901                         if (!profile_exists (default_profile_name)) {
902
903                                 /* no user-edited profile for this device name, so try the user-edited default profile */
904
905                                 default_profile_name = DeviceProfile::name_when_edited (DeviceProfile::default_profile_name);
906
907                                 if (!profile_exists (default_profile_name)) {
908
909                                         /* no user-edited version, so just try the device name */
910
911                                         default_profile_name = _device_info.name();
912
913                                         if (!profile_exists (default_profile_name)) {
914
915                                                 /* no generic device specific profile, just try the fixed default */
916                                                 default_profile_name = DeviceProfile::default_profile_name;
917                                         }
918                                 }
919                         }
920
921                         set_profile (default_profile_name);
922
923                 } else {
924                         if (profile_exists (device_profile_name)) {
925                                 set_profile (device_profile_name);
926                         } else {
927                                 set_profile (DeviceProfile::default_profile_name);
928                         }
929                 }
930         }
931
932         XMLNode* dnode = node.child (X_("Configurations"));
933
934         delete configuration_state;
935         configuration_state = 0;
936
937         if (dnode) {
938                 configuration_state = new XMLNode (*dnode);
939                 state_version = version;
940         }
941
942         (void) switch_banks (bank, true);
943
944         DEBUG_TRACE (DEBUG::US2400, "US2400Protocol::set_state done\n");
945
946         return 0;
947 }
948
949 ///////////////////////////////////////////
950 // Session signals
951 ///////////////////////////////////////////
952
953 void US2400Protocol::notify_parameter_changed (std::string const & p)
954 {
955 }
956
957 void
958 US2400Protocol::notify_stripable_removed ()
959 {
960         Glib::Threads::Mutex::Lock lm (surfaces_lock);
961         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
962                 (*s)->master_monitor_may_have_changed ();
963         }
964 }
965
966 void
967 US2400Protocol::notify_vca_added (ARDOUR::VCAList& vl)
968 {
969         refresh_current_bank ();
970 }
971
972 // RouteList is the set of Routes that have just been added
973 void
974 US2400Protocol::notify_routes_added (ARDOUR::RouteList & rl)
975 {
976         {
977                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
978
979                 if (surfaces.empty()) {
980                         return;
981                 }
982         }
983
984         /* special case: single route, and it is the monitor or master out */
985
986         if (rl.size() == 1 && (rl.front()->is_monitor() || rl.front()->is_master())) {
987                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
988                 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
989                         (*s)->master_monitor_may_have_changed ();
990                 }
991         }
992
993         // currently assigned banks are less than the full set of
994         // strips, so activate the new strip now.
995
996         refresh_current_bank();
997
998         // otherwise route added, but current bank needs no updating
999 }
1000
1001 void
1002 US2400Protocol::notify_solo_active_changed (bool active)
1003 {
1004         boost::shared_ptr<Surface> surface;
1005
1006         {
1007                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1008
1009                 if (surfaces.empty()) {
1010                         return;
1011                 }
1012
1013                 surface = _master_surface;
1014         }
1015
1016         map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Led::RudeSolo);
1017         if (x != surface->controls_by_device_independent_id.end()) {
1018                 Led* rude_solo = dynamic_cast<Led*> (x->second);
1019                 if (rude_solo) {
1020                         surface->write (rude_solo->set_state (active ? flashing : off));
1021                 }
1022         }
1023 }
1024
1025 void
1026 US2400Protocol::notify_presentation_info_changed (PBD::PropertyChange const & what_changed)
1027 {
1028         PBD::PropertyChange order_or_hidden;
1029
1030         order_or_hidden.add (Properties::hidden);
1031         order_or_hidden.add (Properties::order);
1032
1033         if (!what_changed.contains (order_or_hidden)) {
1034                 return;
1035         }
1036
1037         {
1038                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1039
1040                 if (surfaces.empty()) {
1041                         return;
1042                 }
1043         }
1044
1045         refresh_current_bank();
1046 }
1047
1048 ///////////////////////////////////////////
1049 // Transport signals
1050 ///////////////////////////////////////////
1051
1052 void
1053 US2400Protocol::notify_loop_state_changed()
1054 {
1055 }
1056
1057 void
1058 US2400Protocol::notify_transport_state_changed()
1059 {
1060         if (!_device_info.has_global_controls()) {
1061                 return;
1062         }
1063
1064         // switch various play and stop buttons on / off
1065         update_global_button (Button::Play, session->transport_speed() == 1.0);
1066         update_global_button (Button::Stop, session->transport_stopped_or_stopping ());
1067         update_global_button (Button::Rewind, session->transport_speed() < 0.0);
1068         update_global_button (Button::Ffwd, session->transport_speed() > 1.0);
1069
1070         // sometimes a return to start leaves time code at old time
1071         _timecode_last = string (10, ' ');
1072
1073         notify_metering_state_changed ();
1074 }
1075
1076 void
1077 US2400Protocol::notify_metering_state_changed()
1078 {
1079         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1080
1081         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1082                 (*s)->notify_metering_state_changed ();
1083         }
1084 }
1085
1086 void
1087 US2400Protocol::notify_record_state_changed ()
1088 {
1089         if (!_device_info.has_global_controls()) {
1090                 return;
1091         }
1092
1093         boost::shared_ptr<Surface> surface;
1094
1095         {
1096                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1097                 if (surfaces.empty()) {
1098                         return;
1099                 }
1100                 surface = _master_surface;
1101         }
1102
1103         /* rec is a tristate */
1104
1105         map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Button::Record);
1106         if (x != surface->controls_by_device_independent_id.end()) {
1107                 Button * rec = dynamic_cast<Button*> (x->second);
1108                 if (rec) {
1109                         LedState ls;
1110
1111                         switch (session->record_status()) {
1112                         case Session::Disabled:
1113                                 DEBUG_TRACE (DEBUG::US2400, "record state changed to disabled, LED off\n");
1114                                 ls = off;
1115                                 break;
1116                         case Session::Recording:
1117                                 DEBUG_TRACE (DEBUG::US2400, "record state changed to recording, LED on\n");
1118                                 ls = on;
1119                                 break;
1120                         case Session::Enabled:
1121                                 DEBUG_TRACE (DEBUG::US2400, "record state changed to enabled, LED flashing\n");
1122                                 ls = flashing;
1123                                 break;
1124                         }
1125
1126                         surface->write (rec->set_state (ls));
1127                 }
1128         }
1129 }
1130
1131 list<boost::shared_ptr<ARDOUR::Bundle> >
1132 US2400Protocol::bundles ()
1133 {
1134         list<boost::shared_ptr<ARDOUR::Bundle> > b;
1135
1136         if (_input_bundle) {
1137                 b.push_back (_input_bundle);
1138                 b.push_back (_output_bundle);
1139         }
1140
1141         return b;
1142 }
1143
1144 void
1145 US2400Protocol::do_request (US2400ControlUIRequest* req)
1146 {
1147         DEBUG_TRACE (DEBUG::US2400, string_compose ("doing request type %1\n", req->type));
1148         if (req->type == CallSlot) {
1149
1150                 call_slot (MISSING_INVALIDATOR, req->the_slot);
1151
1152         } else if (req->type == Quit) {
1153
1154                 stop ();
1155         }
1156 }
1157
1158 int
1159 US2400Protocol::stop ()
1160 {
1161         BaseUI::quit ();
1162
1163         return 0;
1164 }
1165
1166 void
1167 US2400Protocol::update_led (Surface& surface, Button& button, US2400::LedState ls)
1168 {
1169         if (ls != none) {
1170                 surface.port().write (button.set_state (ls));
1171         }
1172 }
1173
1174 void
1175 US2400Protocol::build_button_map ()
1176 {
1177         /* this maps our device-independent button codes to the methods that handle them.
1178          */
1179
1180 #define DEFINE_BUTTON_HANDLER(b,p,r) button_map.insert (pair<Button::ID,ButtonHandlers> ((b), ButtonHandlers ((p),(r))));
1181
1182         DEFINE_BUTTON_HANDLER (Button::Solo, &US2400Protocol::clearsolo_press, &US2400Protocol::clearsolo_release);  // ClearSolo button == Option+Solo lands here.
1183
1184         DEFINE_BUTTON_HANDLER (Button::Send, &US2400Protocol::send_press, &US2400Protocol::send_release);
1185         DEFINE_BUTTON_HANDLER (Button::Pan, &US2400Protocol::pan_press, &US2400Protocol::pan_release);
1186         DEFINE_BUTTON_HANDLER (Button::Left, &US2400Protocol::left_press, &US2400Protocol::left_release);
1187         DEFINE_BUTTON_HANDLER (Button::Right, &US2400Protocol::right_press, &US2400Protocol::right_release);
1188         DEFINE_BUTTON_HANDLER (Button::Flip, &US2400Protocol::flip_press, &US2400Protocol::flip_release);
1189         DEFINE_BUTTON_HANDLER (Button::MstrSelect, &US2400Protocol::mstr_press, &US2400Protocol::mstr_release);
1190 //      DEFINE_BUTTON_HANDLER (Button::F1, &US2400Protocol::F1_press, &US2400Protocol::F1_release);
1191 //      DEFINE_BUTTON_HANDLER (Button::F2, &US2400Protocol::F2_press, &US2400Protocol::F2_release);
1192 //      DEFINE_BUTTON_HANDLER (Button::F3, &US2400Protocol::F3_press, &US2400Protocol::F3_release);
1193 //      DEFINE_BUTTON_HANDLER (Button::F4, &US2400Protocol::F4_press, &US2400Protocol::F4_release);
1194 //      DEFINE_BUTTON_HANDLER (Button::F5, &US2400Protocol::F5_press, &US2400Protocol::F5_release);
1195 //      DEFINE_BUTTON_HANDLER (Button::F6, &US2400Protocol::F6_press, &US2400Protocol::F6_release);
1196         DEFINE_BUTTON_HANDLER (Button::Shift, &US2400Protocol::shift_press, &US2400Protocol::shift_release);
1197         DEFINE_BUTTON_HANDLER (Button::Option, &US2400Protocol::option_press, &US2400Protocol::option_release);
1198         DEFINE_BUTTON_HANDLER (Button::Drop, &US2400Protocol::drop_press, &US2400Protocol::drop_release);
1199         DEFINE_BUTTON_HANDLER (Button::Rewind, &US2400Protocol::rewind_press, &US2400Protocol::rewind_release);
1200         DEFINE_BUTTON_HANDLER (Button::Ffwd, &US2400Protocol::ffwd_press, &US2400Protocol::ffwd_release);
1201         DEFINE_BUTTON_HANDLER (Button::Stop, &US2400Protocol::stop_press, &US2400Protocol::stop_release);
1202         DEFINE_BUTTON_HANDLER (Button::Play, &US2400Protocol::play_press, &US2400Protocol::play_release);
1203         DEFINE_BUTTON_HANDLER (Button::Record, &US2400Protocol::record_press, &US2400Protocol::record_release);
1204         DEFINE_BUTTON_HANDLER (Button::Scrub, &US2400Protocol::scrub_press, &US2400Protocol::scrub_release);
1205         DEFINE_BUTTON_HANDLER (Button::MasterFaderTouch, &US2400Protocol::master_fader_touch_press, &US2400Protocol::master_fader_touch_release);
1206 }
1207
1208 void
1209 US2400Protocol::handle_button_event (Surface& surface, Button& button, ButtonState bs)
1210 {
1211         Button::ID button_id = button.bid();
1212
1213         if  (bs != press && bs != release) {
1214                 update_led (surface, button, none);
1215                 return;
1216         }
1217
1218         DEBUG_TRACE (DEBUG::US2400, string_compose ("Handling %1 for button %2 (%3)\n", (bs == press ? "press" : "release"), button.id(),
1219                                                            Button::id_to_name (button.bid())));
1220
1221         /* check profile first */
1222
1223         string action = _device_profile.get_button_action (button.bid(), _modifier_state);
1224
1225         DEBUG_TRACE (DEBUG::US2400, string_compose ("device profile returned [%1] for that button\n", action));
1226
1227         if (!action.empty()) {
1228
1229                 if (action.find ('/') != string::npos) { /* good chance that this is really an action */
1230
1231                         DEBUG_TRACE (DEBUG::US2400, string_compose ("Looked up action for button %1 with modifier %2, got [%3]\n",
1232                                                                            button.bid(), _modifier_state, action));
1233
1234                         /* if there is a bound action for this button, and this is a press event,
1235                            carry out the action. If its a release event, do nothing since we
1236                            don't bind to them at all but don't want any other handling to
1237                            occur either.
1238                         */
1239                         if (bs == press) {
1240                                 update_led (surface, button, on);
1241                                 DEBUG_TRACE (DEBUG::US2400, string_compose ("executing action %1\n", action));
1242                                 access_action (action);
1243                         } else {
1244                                 update_led (surface, button, off);
1245                         }
1246                         return;
1247
1248                 } else {
1249
1250                         /* "action" is more likely to be a button name. We use this to
1251                          * allow remapping buttons to different (builtin) functionality
1252                          * associated with an existing button. This is similar to the
1253                          * way that (for example) Nuendo moves the "Shift" function to
1254                          * the "Enter" key of the MCU Pro.
1255                          */
1256
1257                         int bid = Button::name_to_id (action);
1258
1259                         if (bid < 0) {
1260                                 DEBUG_TRACE (DEBUG::US2400, string_compose ("apparent button name %1 not found\n", action));
1261                                 return;
1262                         }
1263
1264                         button_id = (Button::ID) bid;
1265                         DEBUG_TRACE (DEBUG::US2400, string_compose ("handling button %1 as if it was %2 (%3)\n", Button::id_to_name (button.bid()), button_id, Button::id_to_name (button_id)));
1266                 }
1267         }
1268
1269         /* Now that we have the correct (maybe remapped) button ID, do these
1270          * checks on it.
1271          */
1272
1273         /* lookup using the device-INDEPENDENT button ID */
1274
1275         DEBUG_TRACE (DEBUG::US2400, string_compose ("now looking up button ID %1\n", button_id));
1276
1277         ButtonMap::iterator b = button_map.find (button_id);
1278
1279         if (b != button_map.end()) {
1280
1281                 ButtonHandlers& bh (b->second);
1282
1283                 DEBUG_TRACE (DEBUG::US2400, string_compose ("button found in map, now invoking %1\n", (bs == press ? "press" : "release")));
1284
1285                 switch  (bs) {
1286                 case press:
1287                         surface.write (button.set_state ((this->*(bh.press)) (button)));
1288                         break;
1289                 case release:
1290                         surface.write (button.set_state ((this->*(bh.release)) (button)));
1291                         break;
1292                 default:
1293                         break;
1294                 }
1295         } else {
1296                 DEBUG_TRACE (DEBUG::US2400, string_compose ("no button handlers for button ID %1 (device ID %2)\n",
1297                                                                    button.bid(), button.id()));
1298                 error << string_compose ("no button handlers for button ID %1 (device ID %2)\n",
1299                                          button.bid(), button.id()) << endmsg;
1300         }
1301 }
1302
1303 bool
1304 US2400Protocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
1305 {
1306         if (ioc & ~IO_IN) {
1307                 DEBUG_TRACE (DEBUG::US2400, "MIDI port closed\n");
1308                 return false;
1309         }
1310
1311         if (ioc & IO_IN) {
1312
1313                 // DEBUG_TRACE (DEBUG::US2400, string_compose ("something happend on  %1\n", port->name()));
1314
1315                 /* Devices using regular JACK MIDI ports will need to have
1316                    the x-thread FIFO drained to avoid burning endless CPU.
1317                 */
1318
1319                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
1320                 if (asp) {
1321                         asp->clear ();
1322                 }
1323
1324                 // DEBUG_TRACE (DEBUG::US2400, string_compose ("data available on %1\n", port->name()));
1325                 samplepos_t now = session->engine().sample_time();
1326                 port->parse (now);
1327         }
1328
1329         return true;
1330 }
1331
1332 void
1333 US2400Protocol::clear_ports ()
1334 {
1335         if (_input_bundle) {
1336                 _input_bundle->remove_channels ();
1337                 _output_bundle->remove_channels ();
1338         }
1339 }
1340
1341 void
1342 US2400Protocol::notify_subview_stripable_deleted ()
1343 {
1344         /* return to global/mixer view */
1345         _subview_stripable.reset ();
1346         set_view_mode (Mixer);
1347 }
1348
1349 bool
1350 US2400Protocol::subview_mode_would_be_ok (SubViewMode mode, boost::shared_ptr<Stripable> r)
1351 {
1352         switch (mode) {
1353         case None:
1354                 return true;
1355                 break;
1356
1357         case TrackView:
1358                 if (r) {
1359                         return true;
1360                 }
1361         }
1362
1363         return false;
1364 }
1365
1366 bool
1367 US2400Protocol::redisplay_subview_mode ()
1368 {
1369         Surfaces copy; /* can't hold surfaces lock while calling Strip::subview_mode_changed */
1370
1371         {
1372                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1373                 copy = surfaces;
1374         }
1375
1376         for (Surfaces::iterator s = copy.begin(); s != copy.end(); ++s) {
1377                 (*s)->subview_mode_changed ();
1378         }
1379
1380         /* don't call this again from a timeout */
1381         return false;
1382 }
1383
1384 int
1385 US2400Protocol::set_subview_mode (SubViewMode sm, boost::shared_ptr<Stripable> r)
1386 {
1387         if (!subview_mode_would_be_ok (sm, r)) {
1388
1389                 DEBUG_TRACE (DEBUG::US2400, "subview mode not OK\n");
1390
1391                 if (r) {
1392
1393                         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1394
1395                         if (!surfaces.empty()) {
1396
1397                                 string msg;
1398
1399                                 switch (sm) {
1400                                 case TrackView:
1401                                         msg = _("no track view possible");
1402                                 default:
1403                                         break;
1404                                 }
1405                         }
1406                 }
1407
1408                 return -1;
1409         }
1410
1411         boost::shared_ptr<Stripable> old_stripable = _subview_stripable;
1412
1413         _subview_mode = sm;
1414         _subview_stripable = r;
1415
1416         if (_subview_stripable != old_stripable) {
1417                 subview_stripable_connections.drop_connections ();
1418
1419                 /* Catch the current subview stripable going away */
1420                 if (_subview_stripable) {
1421                         _subview_stripable->DropReferences.connect (subview_stripable_connections, MISSING_INVALIDATOR,
1422                                                                     boost::bind (&US2400Protocol::notify_subview_stripable_deleted, this),
1423                                                                     this);
1424                 }
1425         }
1426
1427         redisplay_subview_mode ();
1428
1429         /* turn buttons related to vpot mode on or off as required */
1430
1431         switch (_subview_mode) {
1432         case US2400Protocol::None:
1433                 update_global_button (Button::Send, off);
1434                 update_global_button (Button::Pan, on);
1435                 break;
1436         case US2400Protocol::TrackView:
1437                 update_global_button (Button::Send, off);
1438                 update_global_button (Button::Pan, off);
1439                 break;
1440         }
1441
1442         return 0;
1443 }
1444
1445 void
1446 US2400Protocol::set_view_mode (ViewMode m)
1447 {
1448         ViewMode old_view_mode = _view_mode;
1449
1450         _view_mode = m;
1451         _last_bank[old_view_mode] = _current_initial_bank;
1452
1453         if (switch_banks(_last_bank[m], true)) {
1454                 _view_mode = old_view_mode;
1455                 return;
1456         }
1457
1458         /* leave subview mode, whatever it was */
1459         set_subview_mode (None, boost::shared_ptr<Stripable>());
1460 }
1461
1462 void
1463 US2400Protocol::display_view_mode ()
1464 {
1465
1466 }
1467
1468 void
1469 US2400Protocol::set_master_on_surface_strip (uint32_t surface, uint32_t strip_number)
1470 {
1471         force_special_stripable_to_strip (session->master_out(), surface, strip_number);
1472 }
1473
1474 void
1475 US2400Protocol::set_monitor_on_surface_strip (uint32_t surface, uint32_t strip_number)
1476 {
1477         force_special_stripable_to_strip (session->monitor_out(), surface, strip_number);
1478 }
1479
1480 void
1481 US2400Protocol::force_special_stripable_to_strip (boost::shared_ptr<Stripable> r, uint32_t surface, uint32_t strip_number)
1482 {
1483         if (!r) {
1484                 return;
1485         }
1486
1487         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1488
1489         for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1490                 if ((*s)->number() == surface) {
1491                         Strip* strip = (*s)->nth_strip (strip_number);
1492                         if (strip) {
1493                                 strip->set_stripable (session->master_out());
1494                                 strip->lock_controls ();
1495                         }
1496                 }
1497         }
1498 }
1499
1500 void
1501 US2400Protocol::check_fader_automation_state ()
1502 {
1503 }
1504
1505 void
1506 US2400Protocol::update_fader_automation_state ()
1507 {
1508 }
1509
1510 samplepos_t
1511 US2400Protocol::transport_sample() const
1512 {
1513         return session->transport_sample();
1514 }
1515
1516 void
1517 US2400Protocol::add_down_select_button (int surface, int strip)
1518 {
1519         _down_select_buttons.insert ((surface<<8)|(strip&0xf));
1520 }
1521
1522 void
1523 US2400Protocol::remove_down_select_button (int surface, int strip)
1524 {
1525         DownButtonList::iterator x = find (_down_select_buttons.begin(), _down_select_buttons.end(), (uint32_t) (surface<<8)|(strip&0xf));
1526         DEBUG_TRACE (DEBUG::US2400, string_compose ("removing surface %1 strip %2 from down select buttons\n", surface, strip));
1527         if (x != _down_select_buttons.end()) {
1528                 _down_select_buttons.erase (x);
1529         } else {
1530                 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface %1 strip %2 not found in down select buttons\n",
1531                                                                    surface, strip));
1532         }
1533 }
1534
1535 void
1536 US2400Protocol::select_range (uint32_t pressed)
1537 {
1538         StripableList stripables;
1539
1540         pull_stripable_range (_down_select_buttons, stripables, pressed);
1541
1542         DEBUG_TRACE (DEBUG::US2400, string_compose ("select range: found %1 stripables, first = %2\n", stripables.size(),
1543                                                            (stripables.empty() ? "null" : stripables.front()->name())));
1544
1545         if (stripables.empty()) {
1546                 return;
1547         }
1548
1549         if (stripables.size() == 1 && ControlProtocol::last_selected().size() == 1 && stripables.front()->is_selected()) {
1550                 /* cancel selection for one and only selected stripable */
1551                 ToggleStripableSelection (stripables.front());
1552         } else {
1553                 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1554
1555                         if (main_modifier_state() == MODIFIER_SHIFT) {
1556                                 ToggleStripableSelection (*s);
1557                         } else {
1558                                 if (s == stripables.begin()) {
1559                                         SetStripableSelection (*s);
1560                                 } else {
1561                                         AddStripableToSelection (*s);
1562                                 }
1563                         }
1564                 }
1565         }
1566 }
1567
1568 void
1569 US2400Protocol::add_down_button (AutomationType a, int surface, int strip)
1570 {
1571         DownButtonMap::iterator m = _down_buttons.find (a);
1572
1573         if (m == _down_buttons.end()) {
1574                 _down_buttons[a] = DownButtonList();
1575         }
1576
1577         _down_buttons[a].insert ((surface<<8)|(strip&0xf));
1578 }
1579
1580 void
1581 US2400Protocol::remove_down_button (AutomationType a, int surface, int strip)
1582 {
1583         DownButtonMap::iterator m = _down_buttons.find (a);
1584
1585         DEBUG_TRACE (DEBUG::US2400, string_compose ("removing surface %1 strip %2 from down buttons for %3\n", surface, strip, (int) a));
1586
1587         if (m == _down_buttons.end()) {
1588                 return;
1589         }
1590
1591         DownButtonList& l (m->second);
1592         DownButtonList::iterator x = find (l.begin(), l.end(), (surface<<8)|(strip&0xf));
1593
1594         if (x != l.end()) {
1595                 l.erase (x);
1596         } else {
1597                 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface %1 strip %2 not found in down buttons for %3\n",
1598                                                                    surface, strip, (int) a));
1599         }
1600 }
1601
1602 US2400Protocol::ControlList
1603 US2400Protocol::down_controls (AutomationType p, uint32_t pressed)
1604 {
1605         ControlList controls;
1606         StripableList stripables;
1607
1608         DownButtonMap::iterator m = _down_buttons.find (p);
1609
1610         if (m == _down_buttons.end()) {
1611                 return controls;
1612         }
1613
1614         DEBUG_TRACE (DEBUG::US2400, string_compose ("looking for down buttons for %1, got %2\n",
1615                                                            p, m->second.size()));
1616
1617         pull_stripable_range (m->second, stripables, pressed);
1618
1619         switch (p) {
1620         case GainAutomation:
1621                 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1622                         controls.push_back ((*s)->gain_control());
1623                 }
1624                 break;
1625         case SoloAutomation:
1626                 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1627                         controls.push_back ((*s)->solo_control());
1628                 }
1629                 break;
1630         case MuteAutomation:
1631                 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1632                         controls.push_back ((*s)->mute_control());
1633                 }
1634                 break;
1635         case RecEnableAutomation:
1636                 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1637                         boost::shared_ptr<AutomationControl> ac = (*s)->rec_enable_control();
1638                         if (ac) {
1639                                 controls.push_back (ac);
1640                         }
1641                 }
1642                 break;
1643         default:
1644                 break;
1645         }
1646
1647         return controls;
1648
1649 }
1650
1651 struct ButtonRangeSorter {
1652     bool operator() (const uint32_t& a, const uint32_t& b) {
1653             return (a>>8) < (b>>8) // a.surface < b.surface
1654                     ||
1655                     ((a>>8) == (b>>8) && (a&0xf) < (b&0xf)); // a.surface == b.surface && a.strip < b.strip
1656     }
1657 };
1658
1659 void
1660 US2400Protocol::pull_stripable_range (DownButtonList& down, StripableList& selected, uint32_t pressed)
1661 {
1662         ButtonRangeSorter cmp;
1663
1664         if (down.empty()) {
1665                 return;
1666         }
1667
1668         list<uint32_t> ldown;
1669         ldown.insert (ldown.end(), down.begin(), down.end());
1670         ldown.sort (cmp);
1671
1672         uint32_t first = ldown.front();
1673         uint32_t last = ldown.back ();
1674
1675         uint32_t first_surface = first>>8;
1676         uint32_t first_strip = first&0xf;
1677
1678         uint32_t last_surface = last>>8;
1679         uint32_t last_strip = last&0xf;
1680
1681         DEBUG_TRACE (DEBUG::US2400, string_compose ("PRR %5 in list %1.%2 - %3.%4\n", first_surface, first_strip, last_surface, last_strip,
1682                                                            down.size()));
1683
1684         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1685
1686         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1687
1688                 if ((*s)->number() >= first_surface && (*s)->number() <= last_surface) {
1689
1690                         uint32_t fs;
1691                         uint32_t ls;
1692
1693                         if ((*s)->number() == first_surface) {
1694                                 fs = first_strip;
1695                         } else {
1696                                 fs = 0;
1697                         }
1698
1699                         if ((*s)->number() == last_surface) {
1700                                 ls = last_strip;
1701                                 ls += 1;
1702                         } else {
1703                                 ls = (*s)->n_strips ();
1704                         }
1705
1706                         DEBUG_TRACE (DEBUG::US2400, string_compose ("adding strips for surface %1 (%2 .. %3)\n",
1707                                                                            (*s)->number(), fs, ls));
1708
1709                         for (uint32_t n = fs; n < ls; ++n) {
1710                                 Strip* strip = (*s)->nth_strip (n);
1711                                 boost::shared_ptr<Stripable> r = strip->stripable();
1712                                 if (r) {
1713                                         if (global_index_locked (*strip) == pressed) {
1714                                                 selected.push_front (r);
1715                                         } else {
1716                                                 selected.push_back (r);
1717                                         }
1718                                 }
1719                         }
1720                 }
1721         }
1722
1723 }
1724
1725 void
1726 US2400Protocol::clear_surfaces ()
1727 {
1728         clear_ports ();
1729
1730         {
1731                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1732                 _master_surface.reset ();
1733                 surfaces.clear ();
1734         }
1735 }
1736
1737 void
1738 US2400Protocol::set_touch_sensitivity (int sensitivity)
1739 {
1740         sensitivity = min (9, sensitivity);
1741         sensitivity = max (0, sensitivity);
1742
1743         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1744
1745         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1746                 (*s)->set_touch_sensitivity (sensitivity);
1747         }
1748 }
1749
1750 void
1751 US2400Protocol::recalibrate_faders ()
1752 {
1753         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1754
1755         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1756                 (*s)->recalibrate_faders ();
1757         }
1758 }
1759
1760 void
1761 US2400Protocol::toggle_backlight ()
1762 {
1763         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1764
1765         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1766                 (*s)->toggle_backlight ();
1767         }
1768 }
1769
1770 boost::shared_ptr<Surface>
1771 US2400Protocol::get_surface_by_raw_pointer (void* ptr) const
1772 {
1773         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1774
1775         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1776                 if ((*s).get() == (Surface*) ptr) {
1777                         return *s;
1778                 }
1779         }
1780
1781         return boost::shared_ptr<Surface> ();
1782 }
1783
1784 boost::shared_ptr<Surface>
1785 US2400Protocol::nth_surface (uint32_t n) const
1786 {
1787         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1788
1789         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s, --n) {
1790                 if (n == 0) {
1791                         return *s;
1792                 }
1793         }
1794
1795         return boost::shared_ptr<Surface> ();
1796 }
1797
1798 void
1799 US2400Protocol::connection_handler (boost::weak_ptr<ARDOUR::Port> wp1, std::string name1, boost::weak_ptr<ARDOUR::Port> wp2, std::string name2, bool yn)
1800 {
1801         Surfaces scopy;
1802         {
1803                 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1804                 scopy = surfaces;
1805         }
1806
1807         for (Surfaces::const_iterator s = scopy.begin(); s != scopy.end(); ++s) {
1808                 if ((*s)->connection_handler (wp1, name1, wp2, name2, yn)) {
1809                         ConnectionChange (*s);
1810                         break;
1811                 }
1812         }
1813 }
1814
1815 bool
1816 US2400Protocol::is_track (boost::shared_ptr<Stripable> r) const
1817 {
1818         return boost::dynamic_pointer_cast<Track>(r) != 0;
1819 }
1820
1821 bool
1822 US2400Protocol::is_audio_track (boost::shared_ptr<Stripable> r) const
1823 {
1824         return boost::dynamic_pointer_cast<AudioTrack>(r) != 0;
1825 }
1826
1827 bool
1828 US2400Protocol::is_midi_track (boost::shared_ptr<Stripable> r) const
1829 {
1830         return boost::dynamic_pointer_cast<MidiTrack>(r) != 0;
1831 }
1832
1833 bool
1834 US2400Protocol::is_mapped (boost::shared_ptr<Stripable> r) const
1835 {
1836         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1837
1838         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1839                 if ((*s)->stripable_is_mapped (r)) {
1840                         return true;
1841                 }
1842         }
1843
1844         return false;
1845 }
1846
1847 void
1848 US2400Protocol::stripable_selection_changed ()
1849 {
1850         //this function is called after the stripable selection is "stable", so this is the place to check surface selection state
1851         for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
1852                 (*si)->update_strip_selection ();
1853         }
1854
1855         //first check for the dedicated Master strip
1856         boost::shared_ptr<Stripable> s = ControlProtocol::first_selected_stripable();
1857         if (s && s->is_master()) {
1858                 update_global_button(Button::MstrSelect, on);  //NOTE:  surface does not respond to this
1859         } else {
1860                 update_global_button(Button::MstrSelect, off);
1861
1862                 //not the master;  now check for other strips ( this will only allow a selection if the strip is mapped on our surface )
1863                 s = first_selected_stripable ();
1864         }
1865         
1866         if (s) {
1867                 check_fader_automation_state ();
1868
1869                 /* It is possible that first_selected_route() may return null if we
1870                  * are no longer displaying/mapping that route. In that case,
1871                  * we will exit subview mode. If first_selected_route() is
1872                  * null, and subview mode is not None, then the first call to
1873                  * set_subview_mode() will fail, and we will reset to None.
1874                  */
1875
1876                 if (set_subview_mode (TrackView, s)) {
1877                         set_subview_mode (None, boost::shared_ptr<Stripable>());
1878                 }
1879
1880         } else
1881                 set_subview_mode (None, boost::shared_ptr<Stripable>());
1882 }
1883
1884 boost::shared_ptr<Stripable>
1885 US2400Protocol::first_selected_stripable () const
1886 {
1887         boost::shared_ptr<Stripable> s = ControlProtocol::first_selected_stripable();
1888
1889         if (s) {
1890                 /* check it is on one of our surfaces */
1891
1892                 if (is_mapped (s)) {
1893                         return s;
1894                 }
1895
1896                 /* stripable is not mapped. thus, the currently selected stripable is
1897                  * not on the surfaces, and so from our perspective, there is
1898                  * no currently selected stripable.
1899                  */
1900
1901                 s.reset ();
1902         }
1903
1904         return s; /* may be null */
1905 }
1906
1907 boost::shared_ptr<Stripable>
1908 US2400Protocol::subview_stripable () const
1909 {
1910         return _subview_stripable;
1911 }
1912
1913 uint32_t
1914 US2400Protocol::global_index (Strip& strip)
1915 {
1916         Glib::Threads::Mutex::Lock lm (surfaces_lock);
1917         return global_index_locked (strip);
1918 }
1919
1920 uint32_t
1921 US2400Protocol::global_index_locked (Strip& strip)
1922 {
1923         uint32_t global = 0;
1924
1925         for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1926                 if ((*s).get() == strip.surface()) {
1927                         return global + strip.index();
1928                 }
1929                 global += (*s)->n_strips ();
1930         }
1931
1932         return global;
1933 }
1934
1935 void*
1936 US2400Protocol::request_factory (uint32_t num_requests)
1937 {
1938         /* AbstractUI<T>::request_buffer_factory() is a template method only
1939            instantiated in this source module. To provide something visible for
1940            use in the interface/descriptor, we have this static method that is
1941            template-free.
1942         */
1943         return request_buffer_factory (num_requests);
1944 }
1945
1946 void
1947 US2400Protocol::set_automation_state (AutoState as)
1948 {
1949         boost::shared_ptr<Stripable> r = first_selected_stripable ();
1950
1951         if (!r) {
1952                 return;
1953         }
1954
1955         boost::shared_ptr<AutomationControl> ac = r->gain_control();
1956
1957         if (!ac) {
1958                 return;
1959         }
1960
1961         ac->set_automation_state (as);
1962 }