1 /*
2 * Copyright (C) 2006-2007 John Anderson
3 * Copyright (C) 2007-2010 David Robillard <d@drobilla.net>
4 * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2015-2016 Len Ovens <len@ovenwerks.net>
7 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
8 * Copyright (C) 2016-2018 Ben Loftis <ben@harrisonconsoles.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25 #include <fcntl.h>
26 #include <iostream>
27 #include <algorithm>
28 #include <cmath>
29 #include <sstream>
30 #include <vector>
31 #include <iomanip>
32
33 #include <inttypes.h>
34 #include <float.h>
35 #include <sys/time.h>
36 #include <errno.h>
37
38 #include <boost/shared_array.hpp>
39 #include <glibmm/miscutils.h>
40
41 #include "midi++/types.h"
42 #include "midi++/port.h"
43 #include "midi++/ipmidi_port.h"
44 #include "pbd/pthread_utils.h"
45 #include "pbd/error.h"
46 #include "pbd/memento_command.h"
47 #include "pbd/convert.h"
48
49 #include "ardour/audio_track.h"
50 #include "ardour/automation_control.h"
51 #include "ardour/async_midi_port.h"
52 #include "ardour/dB.h"
53 #include "ardour/debug.h"
54 #include "ardour/location.h"
55 #include "ardour/meter.h"
56 #include "ardour/midi_track.h"
57 #include "ardour/panner.h"
58 #include "ardour/panner_shell.h"
59 #include "ardour/profile.h"
60 #include "ardour/record_enable_control.h"
61 #include "ardour/route.h"
62 #include "ardour/route_group.h"
63 #include "ardour/session.h"
64 #include "ardour/tempo.h"
65 #include "ardour/track.h"
66 #include "ardour/types.h"
67 #include "ardour/audioengine.h"
68 #include "ardour/vca_manager.h"
69
70 #include "mackie_control_protocol.h"
71
72 #include "midi_byte_array.h"
73 #include "mackie_control_exception.h"
74 #include "device_profile.h"
75 #include "subview.h"
76 #include "surface_port.h"
77 #include "surface.h"
78 #include "strip.h"
79 #include "control_group.h"
80 #include "meter.h"
81 #include "button.h"
82 #include "fader.h"
83 #include "pot.h"
84
85 #ifndef G_SOURCE_FUNC
86 #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
87 #endif
88
89 using namespace ARDOUR;
90 using namespace std;
91 using namespace PBD;
92 using namespace Glib;
93 using namespace ArdourSurface;
94 using namespace Mackie;
95
96 #include "pbd/i18n.h"
97
98 #include "pbd/abstract_ui.cc" // instantiate template
99
100 const int MackieControlProtocol::MODIFIER_OPTION = 0x1;
101 const int MackieControlProtocol::MODIFIER_CONTROL = 0x2;
102 const int MackieControlProtocol::MODIFIER_SHIFT = 0x4;
103 const int MackieControlProtocol::MODIFIER_CMDALT = 0x8;
104 const int MackieControlProtocol::MODIFIER_ZOOM = 0x10;
105 const int MackieControlProtocol::MODIFIER_SCRUB = 0x20;
106 const int MackieControlProtocol::MODIFIER_MARKER = 0x40;
107 const int MackieControlProtocol::MODIFIER_NUDGE = 0x80;
108 const int MackieControlProtocol::MAIN_MODIFIER_MASK = (MackieControlProtocol::MODIFIER_OPTION|
109 MackieControlProtocol::MODIFIER_CONTROL|
110 MackieControlProtocol::MODIFIER_SHIFT|
111 MackieControlProtocol::MODIFIER_CMDALT);
112
113 MackieControlProtocol* MackieControlProtocol::_instance = 0;
114
probe()115 bool MackieControlProtocol::probe()
116 {
117 return true;
118 }
119
MackieControlProtocol(Session & session)120 MackieControlProtocol::MackieControlProtocol (Session& session)
121 : ControlProtocol (session, X_("Mackie"))
122 , AbstractUI<MackieControlUIRequest> (name())
123 , _current_initial_bank (0)
124 , _sample_last (0)
125 , _timecode_type (ARDOUR::AnyTime::BBT)
126 , _gui (0)
127 , _scrub_mode (false)
128 , _flip_mode (Normal)
129 , _view_mode (Mixer)
130 , _current_selected_track (-1)
131 , _modifier_state (0)
132 , _ipmidi_base (MIDI::IPMIDIPort::lowest_ipmidi_port_default)
133 , needs_ipmidi_restart (false)
134 , _metering_active (true)
135 , _initialized (false)
136 , configuration_state (0)
137 , state_version (0)
138 , marker_modifier_consumed_by_button (false)
139 , nudge_modifier_consumed_by_button (false)
140 {
141 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
142
143 _subview = Mackie::SubviewFactory::instance()->create_subview(Subview::None, *this, boost::shared_ptr<Stripable>());
144
145 DeviceInfo::reload_device_info ();
146 DeviceProfile::reload_device_profiles ();
147
148 for (int i = 0; i < 9; i++) {
149 _last_bank[i] = 0;
150 }
151
152 PresentationInfo::Change.connect (gui_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_presentation_info_changed, this, _1), this);
153
154 _instance = this;
155
156 build_button_map ();
157 }
158
~MackieControlProtocol()159 MackieControlProtocol::~MackieControlProtocol()
160 {
161 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol init\n");
162
163 for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
164 (*si)->reset ();
165 }
166
167 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol drop_connections ()\n");
168 drop_connections ();
169
170 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol tear_down_gui ()\n");
171 tear_down_gui ();
172
173 delete configuration_state;
174
175 /* stop event loop */
176 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol BaseUI::quit ()\n");
177 BaseUI::quit ();
178
179 try {
180 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol close()\n");
181 close();
182 }
183 catch (exception & e) {
184 cout << "~MackieControlProtocol caught " << e.what() << endl;
185 }
186 catch (...) {
187 cout << "~MackieControlProtocol caught unknown" << endl;
188 }
189
190 _instance = 0;
191
192 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol done\n");
193 }
194
195 void
thread_init()196 MackieControlProtocol::thread_init ()
197 {
198 pthread_set_name (event_loop_name().c_str());
199
200 PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
201 ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
202
203 set_thread_priority ();
204 }
205
206 void
ping_devices()207 MackieControlProtocol::ping_devices ()
208 {
209 /* should not be called if surfaces are not connected, but will not
210 * malfunction if it is.
211 */
212
213 for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
214 (*si)->connected ();
215 }
216 }
217
218 // go to the previous track.
219 void
prev_track()220 MackieControlProtocol::prev_track()
221 {
222 if (_current_initial_bank >= 1) {
223 switch_banks (_current_initial_bank - 1);
224 }
225 }
226
227 // go to the next track.
228 void
next_track()229 MackieControlProtocol::next_track()
230 {
231 Sorted sorted = get_sorted_stripables();
232 if (_current_initial_bank + 1 < sorted.size()) {
233 switch_banks (_current_initial_bank + 1);
234 }
235 }
236
237 bool
stripable_is_locked_to_strip(boost::shared_ptr<Stripable> r) const238 MackieControlProtocol::stripable_is_locked_to_strip (boost::shared_ptr<Stripable> r) const
239 {
240 for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
241 if ((*si)->stripable_is_locked_to_strip (r)) {
242 return true;
243 }
244 }
245 return false;
246 }
247
248 // predicate for sort call in get_sorted_stripables
249 struct StripableByPresentationOrder
250 {
operator ()StripableByPresentationOrder251 bool operator () (const boost::shared_ptr<Stripable> & a, const boost::shared_ptr<Stripable> & b) const
252 {
253 return a->presentation_info().order() < b->presentation_info().order();
254 }
255
operator ()StripableByPresentationOrder256 bool operator () (const Stripable & a, const Stripable & b) const
257 {
258 return a.presentation_info().order() < b.presentation_info().order();
259 }
260
operator ()StripableByPresentationOrder261 bool operator () (const Stripable * a, const Stripable * b) const
262 {
263 return a->presentation_info().order() < b->presentation_info().order();
264 }
265 };
266
267 MackieControlProtocol::Sorted
get_sorted_stripables()268 MackieControlProtocol::get_sorted_stripables()
269 {
270 Sorted sorted;
271
272 // fetch all stripables
273 StripableList stripables;
274
275 session->get_stripables (stripables);
276
277 // sort in presentation order, and exclude master, control and hidden stripables
278 // and any stripables that are already set.
279
280 for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
281
282 boost::shared_ptr<Stripable> s = *it;
283
284 if (s->presentation_info().special()) {
285 continue;
286 }
287
288 /* don't include locked routes */
289
290 if (stripable_is_locked_to_strip (s)) {
291 continue;
292 }
293
294 switch (_view_mode) {
295 case Mixer:
296 if (!s->presentation_info().hidden()) {
297 sorted.push_back (s);
298 }
299 break;
300 case AudioTracks:
301 if (is_audio_track(s) && !s->presentation_info().hidden()) {
302 sorted.push_back (s);
303 }
304 break;
305 case Busses:
306 if (Profile->get_mixbus()) {
307 #ifdef MIXBUS
308 if (s->mixbus()) {
309 sorted.push_back (s);
310 }
311 #endif
312 } else {
313 if (!is_track(s) && !s->presentation_info().hidden()) {
314 sorted.push_back (s);
315 }
316 }
317 break;
318 case MidiTracks:
319 if (is_midi_track(s) && !s->presentation_info().hidden()) {
320 sorted.push_back (s);
321 }
322 break;
323 case Plugins:
324 break;
325 case Auxes: // in ardour, for now aux and buss are same. for mixbus, "Busses" are mixbuses, "Auxes" are ardour buses
326 #ifdef MIXBUS
327 if (!s->mixbus() && !is_track(s) && !s->presentation_info().hidden())
328 #else
329 if (!is_track(s) && !s->presentation_info().hidden())
330 #endif
331 {
332 sorted.push_back (s);
333 }
334 break;
335 case Hidden: // Show all the tracks we have hidden
336 if (s->presentation_info().hidden()) {
337 // maybe separate groups
338 sorted.push_back (s);
339 }
340 break;
341 case Selected: // For example: a group (this is USER)
342 if (s->is_selected() && !s->presentation_info().hidden()) {
343 sorted.push_back (s);
344 }
345 break;
346 }
347 }
348
349 sort (sorted.begin(), sorted.end(), StripableByPresentationOrder());
350 return sorted;
351 }
352
353 void
refresh_current_bank()354 MackieControlProtocol::refresh_current_bank()
355 {
356 switch_banks (_current_initial_bank, true);
357 }
358
359 uint32_t
n_strips(bool with_locked_strips) const360 MackieControlProtocol::n_strips (bool with_locked_strips) const
361 {
362 uint32_t strip_count = 0;
363
364 for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
365 strip_count += (*si)->n_strips (with_locked_strips);
366 }
367
368 return strip_count;
369 }
370
371 int
switch_banks(uint32_t initial,bool force)372 MackieControlProtocol::switch_banks (uint32_t initial, bool force)
373 {
374 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch banking to start at %1 force ? %2 current = %3\n", initial, force, _current_initial_bank));
375
376 if (initial == _current_initial_bank && !force) {
377 /* everything is as it should be */
378 return 0;
379 }
380
381 Sorted sorted = get_sorted_stripables();
382 uint32_t strip_cnt = n_strips (false); // do not include locked strips
383 // in this count
384
385 if (initial >= sorted.size() && !force) {
386 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("bank target %1 exceeds route range %2\n",
387 _current_initial_bank, sorted.size()));
388 /* too high, we can't get there */
389 return -1;
390 }
391
392 if (sorted.size() <= strip_cnt && _current_initial_bank == 0 && !force) {
393 /* no banking - not enough stripables to fill all strips and we're
394 * not at the first one.
395 */
396 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("less routes (%1) than strips (%2) and we're at the end already (%3)\n",
397 sorted.size(), strip_cnt, _current_initial_bank));
398 return -1;
399 }
400
401 _current_initial_bank = initial;
402 _current_selected_track = -1;
403
404 // Map current bank of stripables onto each surface(+strip)
405
406 if (_current_initial_bank < sorted.size()) {
407
408 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available stripables %3 on %4 surfaces\n",
409 _current_initial_bank, strip_cnt, sorted.size(),
410 surfaces.size()));
411
412 // link stripables to strips
413
414 Sorted::iterator r = sorted.begin() + _current_initial_bank;
415
416 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
417 vector<boost::shared_ptr<Stripable> > stripables;
418 uint32_t added = 0;
419
420 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface has %1 unlocked strips\n", (*si)->n_strips (false)));
421
422 for (; r != sorted.end() && added < (*si)->n_strips (false); ++r, ++added) {
423 stripables.push_back (*r);
424 }
425
426 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("give surface %1 stripables\n", stripables.size()));
427
428 (*si)->map_stripables (stripables);
429 }
430
431 } else {
432 /* all strips need to be reset */
433 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("clear all strips, bank target %1 is outside route range %2\n",
434 _current_initial_bank, sorted.size()));
435 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
436 vector<boost::shared_ptr<Stripable> > stripables;
437 /* pass in an empty stripables list, so that all strips will be reset */
438 (*si)->map_stripables (stripables);
439 }
440 return -1;
441 }
442
443 /* current bank has not been saved */
444 session->set_dirty();
445
446 return 0;
447 }
448
449 int
set_active(bool yn)450 MackieControlProtocol::set_active (bool yn)
451 {
452 DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active init with yn: '%1'\n", yn));
453
454 if (yn == active()) {
455 return 0;
456 }
457
458 if (yn) {
459
460 /* start event loop */
461
462 BaseUI::run ();
463
464 connect_session_signals ();
465
466 if (!_device_info.name().empty()) {
467 set_device (_device_info.name(), true);
468 }
469
470 /* set up periodic task for timecode display and metering and automation
471 */
472
473 // set different refresh time for qcon and standard mackie MCU
474
475 int iTimeCodeRefreshTime = 100; // default value for mackie MCU (100ms)
476 int iStripDisplayRefreshTime = 10; // default value for Mackie MCU (10ms)
477
478 if(_device_info.is_qcon()){
479 // set faster timecode display refresh speed (55ms)
480 iTimeCodeRefreshTime = 55;
481 // set slower refresh time on qcon than on mackie (15ms)
482 iStripDisplayRefreshTime = 15;
483 }
484
485 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (iTimeCodeRefreshTime); // milliseconds
486 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::periodic));
487 periodic_timeout->attach (main_loop()->get_context());
488
489 /* periodic task used to update strip displays */
490
491 Glib::RefPtr<Glib::TimeoutSource> redisplay_timeout = Glib::TimeoutSource::create (iStripDisplayRefreshTime); // milliseconds
492 redisplay_connection = redisplay_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::redisplay));
493 redisplay_timeout->attach (main_loop()->get_context());
494
495 notify_transport_state_changed ();
496
497 } else {
498
499 BaseUI::quit ();
500 close ();
501
502 }
503
504 ControlProtocol::set_active (yn);
505
506 DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active done with yn: '%1'\n", yn));
507
508 return 0;
509 }
510
511 bool
hui_heartbeat()512 MackieControlProtocol::hui_heartbeat ()
513 {
514 Glib::Threads::Mutex::Lock lm (surfaces_lock);
515
516 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
517 (*s)->hui_heartbeat ();
518 }
519
520 return true;
521 }
522
523 bool
periodic()524 MackieControlProtocol::periodic ()
525 {
526 if (!active()) {
527 return false;
528 }
529
530 if (!_initialized) {
531 /* wait for higher-frequency redisplay() callback to initialize
532 * us
533 */
534 return true;
535 }
536
537 update_timecode_display ();
538
539 PBD::microseconds_t now_usecs = PBD::get_microseconds ();
540
541 {
542 Glib::Threads::Mutex::Lock lm (surfaces_lock);
543
544 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
545 (*s)->periodic (now_usecs);
546 }
547 }
548
549 return true;
550 }
551
552 bool
redisplay()553 MackieControlProtocol::redisplay ()
554 {
555 if (!active()) {
556 return false;
557 }
558
559 if (needs_ipmidi_restart) {
560 ipmidi_restart ();
561 return true;
562 }
563
564 if (!_initialized) {
565 initialize();
566 }
567
568 PBD::microseconds_t now = PBD::get_microseconds ();
569
570 {
571 Glib::Threads::Mutex::Lock lm (surfaces_lock);
572
573 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
574 (*s)->redisplay (now, false);
575 }
576 }
577
578 return true;
579 }
580
581 void
update_timecode_beats_led()582 MackieControlProtocol::update_timecode_beats_led()
583 {
584 if (!_device_info.has_timecode_display()) {
585 return;
586 }
587
588 DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::update_timecode_beats_led(): %1\n", _timecode_type));
589 switch (_timecode_type) {
590 case ARDOUR::AnyTime::BBT:
591 update_global_led (Led::Beats, on);
592 update_global_led (Led::Timecode, off);
593 break;
594 case ARDOUR::AnyTime::Timecode:
595 update_global_led (Led::Timecode, on);
596 update_global_led (Led::Beats, off);
597 break;
598 default:
599 ostringstream os;
600 os << "Unknown Anytime::Type " << _timecode_type;
601 throw runtime_error (os.str());
602 }
603 }
604
605 void
update_global_button(int id,LedState ls)606 MackieControlProtocol::update_global_button (int id, LedState ls)
607 {
608 boost::shared_ptr<Surface> surface;
609
610 {
611 Glib::Threads::Mutex::Lock lm (surfaces_lock);
612
613 if (surfaces.empty()) {
614 return;
615 }
616
617 if (!_device_info.has_global_controls()) {
618 return;
619 }
620 // surface needs to be master surface
621 surface = _master_surface;
622 }
623
624 map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
625 if (x != surface->controls_by_device_independent_id.end()) {
626 Button * button = dynamic_cast<Button*> (x->second);
627 surface->write (button->set_state (ls));
628 } else {
629 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", id));
630 }
631 }
632
633 void
update_global_led(int id,LedState ls)634 MackieControlProtocol::update_global_led (int id, LedState ls)
635 {
636 Glib::Threads::Mutex::Lock lm (surfaces_lock);
637
638 if (surfaces.empty()) {
639 return;
640 }
641
642 if (!_device_info.has_global_controls()) {
643 return;
644 }
645 boost::shared_ptr<Surface> surface = _master_surface;
646
647 map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
648
649 if (x != surface->controls_by_device_independent_id.end()) {
650 Led * led = dynamic_cast<Led*> (x->second);
651 DEBUG_TRACE (DEBUG::MackieControl, "Writing LedState\n");
652 surface->write (led->set_state (ls));
653 } else {
654 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", id));
655 }
656 }
657
658 void
device_ready()659 MackieControlProtocol::device_ready ()
660 {
661 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device ready init (active=%1)\n", active()));
662 update_surfaces ();
663 set_subview_mode (Mackie::Subview::None, boost::shared_ptr<Stripable>());
664 set_flip_mode (Normal);
665 }
666
667 // send messages to surface to set controls to correct values
668 void
update_surfaces()669 MackieControlProtocol::update_surfaces()
670 {
671 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::update_surfaces() init (active=%1)\n", active()));
672 if (!active()) {
673 return;
674 }
675
676 // do the initial bank switch to connect signals
677 // _current_initial_bank is initialised by set_state
678 (void) switch_banks (_current_initial_bank, true);
679
680 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::update_surfaces() finished\n");
681 }
682
683 void
initialize()684 MackieControlProtocol::initialize()
685 {
686 {
687 Glib::Threads::Mutex::Lock lm (surfaces_lock);
688
689 if (surfaces.empty()) {
690 return;
691 }
692
693 if (!_master_surface->active ()) {
694 return;
695 }
696
697 // sometimes the jog wheel is a pot
698 if (_device_info.has_jog_wheel()) {
699 _master_surface->blank_jog_ring ();
700 }
701 }
702
703 // update global buttons and displays
704
705 notify_record_state_changed();
706 notify_transport_state_changed();
707 update_timecode_beats_led();
708
709 _initialized = true;
710 }
711
712 void
connect_session_signals()713 MackieControlProtocol::connect_session_signals()
714 {
715 // receive routes added
716 session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
717 // receive VCAs added
718 session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_vca_added, this, _1), this);
719
720 // receive record state toggled
721 session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_record_state_changed, this), this);
722 // receive transport state changed
723 session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_transport_state_changed, this), this);
724 session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_loop_state_changed, this), this);
725 // receive punch-in and punch-out
726 Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_parameter_changed, this, _1), this);
727 session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_parameter_changed, this, _1), this);
728 // receive rude solo changed
729 session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), this);
730
731 // make sure remote id changed signals reach here
732 // see also notify_stripable_added
733 Sorted sorted = get_sorted_stripables();
734 }
735
736 void
set_profile(const string & profile_name)737 MackieControlProtocol::set_profile (const string& profile_name)
738 {
739 map<string,DeviceProfile>::iterator d = DeviceProfile::device_profiles.find (profile_name);
740
741 if (d == DeviceProfile::device_profiles.end()) {
742 _device_profile = DeviceProfile (profile_name);
743 return;
744 }
745
746 _device_profile = d->second;
747 }
748
749 int
set_device_info(const string & device_name)750 MackieControlProtocol::set_device_info (const string& device_name)
751 {
752 map<string,DeviceInfo>::iterator d = DeviceInfo::device_info.find (device_name);
753
754 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("new device chosen %1\n", device_name));
755
756 if (d == DeviceInfo::device_info.end()) {
757 return -1;
758 }
759
760 _device_info = d->second;
761
762 return 0;
763 }
764
765 int
set_device(const string & device_name,bool force)766 MackieControlProtocol::set_device (const string& device_name, bool force)
767 {
768 if (device_name == device_info().name() && !force) {
769 /* already using that device, nothing to do */
770 return 0;
771 }
772 /* get state from the current setup, and make sure it is stored in
773 the configuration_states node so that if we switch back to this device,
774 we will have its state available.
775 */
776
777 {
778 Glib::Threads::Mutex::Lock lm (surfaces_lock);
779 if (!surfaces.empty()) {
780 update_configuration_state ();
781 }
782 }
783
784 if (set_device_info (device_name)) {
785 return -1;
786 }
787
788 clear_surfaces ();
789 port_connection.disconnect ();
790 hui_connection.disconnect ();
791
792 if (_device_info.device_type() == DeviceInfo::HUI) {
793 Glib::RefPtr<Glib::TimeoutSource> hui_timeout = Glib::TimeoutSource::create (1000); // milliseconds
794 hui_connection = hui_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::hui_heartbeat));
795 hui_timeout->attach (main_loop()->get_context());
796 }
797
798 if (!_device_info.uses_ipmidi()) {
799 /* notice that the handler for this will execute in our event
800 loop, not in the thread where the
801 PortConnectedOrDisconnected signal is emitted.
802 */
803 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::connection_handler, this, _1, _2, _3, _4, _5), this);
804 }
805
806 if (create_surfaces ()) {
807 return -1;
808 }
809
810 DeviceChanged ();
811
812 return 0;
813 }
814
815 gboolean
ipmidi_input_handler(GIOChannel *,GIOCondition condition,void * data)816 ArdourSurface::ipmidi_input_handler (GIOChannel*, GIOCondition condition, void *data)
817 {
818 ArdourSurface::MackieControlProtocol::ipMIDIHandler* ipm = static_cast<ArdourSurface::MackieControlProtocol::ipMIDIHandler*>(data);
819 return ipm->mcp->midi_input_handler (Glib::IOCondition (condition), ipm->port);
820 }
821
822 int
create_surfaces()823 MackieControlProtocol::create_surfaces ()
824 {
825 string device_name;
826 surface_type_t stype = mcu; // type not yet determined
827
828 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Create %1 surfaces for %2\n", 1 + _device_info.extenders(), _device_info.name()));
829
830 if (!_device_info.uses_ipmidi()) {
831 _input_bundle.reset (new ARDOUR::Bundle (_("Mackie Control In"), true));
832 _output_bundle.reset (new ARDOUR::Bundle (_("Mackie Control Out"), false));
833 } else {
834 _input_bundle.reset ();
835 _output_bundle.reset ();
836
837 }
838 for (uint32_t n = 0; n < 1 + _device_info.extenders(); ++n) {
839 bool is_master = false;
840
841 if (n == _device_info.master_position()) {
842 is_master = true;
843 if (_device_info.extenders() == 0) {
844 device_name = _device_info.name();
845 } else {
846 device_name = X_("mackie control");
847 }
848
849 }
850
851 if (!is_master) {
852 device_name = string_compose (X_("mackie control ext %1"), n+1);
853 }
854
855 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Port Name for surface %1 is %2\n", n, device_name));
856
857 boost::shared_ptr<Surface> surface;
858
859 if (is_master) {
860 stype = mcu;
861 } else {
862 stype = ext;
863 }
864 try {
865 surface.reset (new Surface (*this, device_name, n, stype));
866 } catch (...) {
867 return -1;
868 }
869
870 if (is_master) {
871 _master_surface = surface;
872 }
873
874 if (configuration_state) {
875 XMLNode* this_device = 0;
876 XMLNodeList const& devices = configuration_state->children();
877 for (XMLNodeList::const_iterator d = devices.begin(); d != devices.end(); ++d) {
878 XMLProperty const * prop = (*d)->property (X_("name"));
879 if (prop && prop->value() == _device_info.name()) {
880 this_device = *d;
881 break;
882 }
883 }
884 if (this_device) {
885 XMLNode* snode = this_device->child (X_("Surfaces"));
886 if (snode) {
887 surface->set_state (*snode, state_version);
888 }
889 }
890 }
891
892 {
893 Glib::Threads::Mutex::Lock lm (surfaces_lock);
894 surfaces.push_back (surface);
895 }
896
897 if (!_device_info.uses_ipmidi()) {
898
899 _input_bundle->add_channel (
900 "",
901 ARDOUR::DataType::MIDI,
902 session->engine().make_port_name_non_relative (surface->port().input_port().name())
903 );
904
905 _output_bundle->add_channel (
906 "",
907 ARDOUR::DataType::MIDI,
908 session->engine().make_port_name_non_relative (surface->port().output_port().name())
909 );
910 }
911
912 MIDI::Port& input_port (surface->port().input_port());
913 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (&input_port);
914
915 if (asp) {
916
917 /* async MIDI port */
918
919 asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &MackieControlProtocol::midi_input_handler), &input_port));
920 asp->xthread().attach (main_loop()->get_context());
921
922 } else {
923
924 /* ipMIDI port, no IOSource method at this time */
925
926 int fd;
927
928 if ((fd = input_port.selectable ()) >= 0) {
929
930 GIOChannel* ioc = g_io_channel_unix_new (fd);
931 surface->input_source = g_io_create_watch (ioc, GIOCondition (G_IO_IN|G_IO_HUP|G_IO_ERR));
932
933 /* make surface's input source now hold the
934 * only reference on the IO channel
935 */
936 g_io_channel_unref (ioc);
937
938 /* hack up an object so that in the callback from the event loop
939 we have both the MackieControlProtocol and the input port.
940
941 If we were using C++ for this stuff we wouldn't need this
942 but a nasty, not-fixable bug in the binding between C
943 and C++ makes it necessary to avoid C++ for the IO
944 callback setup.
945 */
946
947 ipMIDIHandler* ipm = new ipMIDIHandler (); /* we will leak this sizeof(pointer)*2 sized object */
948 ipm->mcp = this;
949 ipm->port = &input_port;
950
951 g_source_set_callback (surface->input_source, G_SOURCE_FUNC (ipmidi_input_handler), ipm, NULL);
952 g_source_attach (surface->input_source, main_loop()->get_context()->gobj());
953 }
954 }
955 }
956
957 if (!_device_info.uses_ipmidi()) {
958 Glib::Threads::Mutex::Lock lm (surfaces_lock);
959 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
960 (*s)->port().reconnect ();
961 }
962 }
963
964 session->BundleAddedOrRemoved ();
965
966 assert (_master_surface);
967
968 return 0;
969 }
970
971 void
close()972 MackieControlProtocol::close()
973 {
974 port_connection.disconnect ();
975 session_connections.drop_connections ();
976 stripable_connections.drop_connections ();
977 periodic_connection.disconnect ();
978
979 clear_surfaces();
980 }
981
982 /** Ensure that the configuration_state XML node contains an up-to-date
983 * copy of the state node the current device. If configuration_state already
984 * contains a state node for the device, it will deleted and replaced.
985 */
986 void
update_configuration_state()987 MackieControlProtocol::update_configuration_state ()
988 {
989 /* CALLER MUST HOLD SURFACES LOCK */
990
991 if (!configuration_state) {
992 configuration_state = new XMLNode (X_("Configurations"));
993 }
994
995 XMLNode* devnode = new XMLNode (X_("Configuration"));
996 devnode->set_property (X_("name"), _device_info.name());
997
998 configuration_state->remove_nodes_and_delete (X_("name"), _device_info.name());
999 configuration_state->add_child_nocopy (*devnode);
1000
1001 XMLNode* snode = new XMLNode (X_("Surfaces"));
1002
1003 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1004 snode->add_child_nocopy ((*s)->get_state());
1005 }
1006
1007 devnode->add_child_nocopy (*snode);
1008 }
1009
1010 XMLNode&
get_state()1011 MackieControlProtocol::get_state()
1012 {
1013 XMLNode& node (ControlProtocol::get_state());
1014
1015 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state init\n");
1016
1017 // add current bank
1018 node.set_property (X_("bank"), _current_initial_bank);
1019
1020 // ipMIDI base port (possibly not used)
1021 node.set_property (X_("ipmidi-base"), _ipmidi_base);
1022
1023 node.set_property (X_("device-profile"), _device_profile.name());
1024 node.set_property (X_("device-name"), _device_info.name());
1025
1026 {
1027 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1028 update_configuration_state ();
1029 }
1030
1031 /* force a copy of the _surfaces_state node, because we want to retain ownership */
1032 node.add_child_copy (*configuration_state);
1033
1034 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state done\n");
1035
1036 return node;
1037 }
1038
1039 bool
profile_exists(string const & name) const1040 MackieControlProtocol::profile_exists (string const & name) const
1041 {
1042 return DeviceProfile::device_profiles.find (name) != DeviceProfile::device_profiles.end();
1043 }
1044
1045 int
set_state(const XMLNode & node,int version)1046 MackieControlProtocol::set_state (const XMLNode & node, int version)
1047 {
1048 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", active()));
1049
1050 if (ControlProtocol::set_state (node, version)) {
1051 return -1;
1052 }
1053
1054 uint16_t ipmidi_base;
1055 if (node.get_property (X_("ipmidi-base"), ipmidi_base)) {
1056 set_ipmidi_base (ipmidi_base);
1057 }
1058
1059 uint32_t bank = 0;
1060 // fetch current bank
1061 node.get_property (X_("bank"), bank);
1062
1063 std::string device_name;
1064 if (node.get_property (X_("device-name"), device_name)) {
1065 set_device_info (device_name);
1066 }
1067
1068 std::string device_profile_name;
1069 if (node.get_property (X_("device-profile"), device_profile_name)) {
1070 if (device_profile_name.empty()) {
1071 string default_profile_name;
1072
1073 /* start by looking for a user-edited profile for the current device name */
1074
1075 default_profile_name = DeviceProfile::name_when_edited (_device_info.name());
1076
1077 if (!profile_exists (default_profile_name)) {
1078
1079 /* no user-edited profile for this device name, so try the user-edited default profile */
1080
1081 default_profile_name = DeviceProfile::name_when_edited (DeviceProfile::default_profile_name);
1082
1083 if (!profile_exists (default_profile_name)) {
1084
1085 /* no user-edited version, so just try the device name */
1086
1087 default_profile_name = _device_info.name();
1088
1089 if (!profile_exists (default_profile_name)) {
1090
1091 /* no generic device specific profile, just try the fixed default */
1092 default_profile_name = DeviceProfile::default_profile_name;
1093 }
1094 }
1095 }
1096
1097 set_profile (default_profile_name);
1098
1099 } else {
1100 if (profile_exists (device_profile_name)) {
1101 set_profile (device_profile_name);
1102 } else {
1103 set_profile (DeviceProfile::default_profile_name);
1104 }
1105 }
1106 }
1107
1108 XMLNode* dnode = node.child (X_("Configurations"));
1109
1110 delete configuration_state;
1111 configuration_state = 0;
1112
1113 if (dnode) {
1114 configuration_state = new XMLNode (*dnode);
1115 state_version = version;
1116 }
1117
1118 (void) switch_banks (bank, true);
1119
1120 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::set_state done\n");
1121
1122 return 0;
1123 }
1124
1125 string
format_bbt_timecode(samplepos_t now_sample)1126 MackieControlProtocol::format_bbt_timecode (samplepos_t now_sample)
1127 {
1128 Timecode::BBT_Time bbt_time;
1129
1130 session->bbt_time (now_sample, bbt_time);
1131
1132 // The Mackie protocol spec is built around a BBT time display of
1133 //
1134 // digits: 888/88/88/888
1135 // semantics: BBB/bb/ss/ttt
1136 //
1137 // The third field is "subdivisions" which is a concept found in Logic
1138 // but not present in Ardour. Instead Ardour displays a 4 digit tick
1139 // count, which we need to spread across the 5 digits of ss/ttt.
1140
1141 ostringstream os;
1142
1143 os << setw(3) << setfill('0') << bbt_time.bars;
1144 os << setw(2) << setfill('0') << bbt_time.beats;
1145 os << ' ';
1146 os << setw(1) << setfill('0') << bbt_time.ticks / 1000;
1147 os << setw(3) << setfill('0') << bbt_time.ticks % 1000;
1148
1149 return os.str();
1150 }
1151
1152 string
format_timecode_timecode(samplepos_t now_sample)1153 MackieControlProtocol::format_timecode_timecode (samplepos_t now_sample)
1154 {
1155 Timecode::Time timecode;
1156 session->timecode_time (now_sample, timecode);
1157
1158 // According to the Logic docs
1159 // digits: 888/88/88/888
1160 // Timecode mode: Hours/Minutes/Seconds/Samples
1161 ostringstream os;
1162 os << setw(2) << setfill('0') << timecode.hours;
1163 os << ' ';
1164 os << setw(2) << setfill('0') << timecode.minutes;
1165 os << setw(2) << setfill('0') << timecode.seconds;
1166 os << ' ';
1167 os << setw(2) << setfill('0') << timecode.frames;
1168
1169 return os.str();
1170 }
1171
1172 void
update_timecode_display()1173 MackieControlProtocol::update_timecode_display()
1174 {
1175 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1176
1177 if (surfaces.empty()) {
1178 return;
1179 }
1180
1181 boost::shared_ptr<Surface> surface = _master_surface;
1182
1183 if (surface->type() != mcu || !_device_info.has_timecode_display() || !surface->active ()) {
1184 return;
1185 }
1186
1187 // do assignment here so current_sample is fixed
1188 samplepos_t current_sample = session->transport_sample();
1189 string timecode;
1190 // For large jumps in play head possition do full reset
1191 int moved = (current_sample - _sample_last) / session->sample_rate ();
1192 if (moved) {
1193 DEBUG_TRACE (DEBUG::MackieControl, "Timecode reset\n");
1194 _timecode_last = string (10, ' ');
1195 }
1196 _sample_last = current_sample;
1197
1198 switch (_timecode_type) {
1199 case ARDOUR::AnyTime::BBT:
1200 timecode = format_bbt_timecode (current_sample);
1201 break;
1202 case ARDOUR::AnyTime::Timecode:
1203 timecode = format_timecode_timecode (current_sample);
1204 break;
1205 default:
1206 return;
1207 }
1208
1209 // only write the timecode string to the MCU if it's changed
1210 // since last time. This is to reduce midi bandwidth used.
1211 if (timecode != _timecode_last) {
1212 surface->display_timecode (timecode, _timecode_last);
1213 _timecode_last = timecode;
1214 }
1215 }
1216
1217 ///////////////////////////////////////////
1218 // Session signals
1219 ///////////////////////////////////////////
1220
notify_parameter_changed(std::string const & p)1221 void MackieControlProtocol::notify_parameter_changed (std::string const & p)
1222 {
1223 if (p == "punch-in") {
1224 update_global_button (Button::Drop, session->config.get_punch_in() ? flashing : off);
1225 } else if (p == "punch-out") {
1226 update_global_button (Button::Replace, session->config.get_punch_out() ? flashing : off);
1227 } else if (p == "clicking") {
1228 update_global_button (Button::Click, Config->get_clicking());
1229 } else if (p == "follow-edits") {
1230 /* we can't respond to this at present, because "follow-edits"
1231 * is a property of the (G)UI configuration object, to which we
1232 * have no access. For now, this means that the lit state of
1233 * this button (if there is one) won't reflect the setting.
1234 */
1235
1236 //update_global_button (Button::Enter, session->config.get_follow_edits() ? on : off);
1237 } else if (p == "external-sync") {
1238 update_global_button (Button::Cancel, session->config.get_external_sync() ? on : off);
1239 } else {
1240 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p));
1241 }
1242 }
1243
1244 void
notify_stripable_removed()1245 MackieControlProtocol::notify_stripable_removed ()
1246 {
1247 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1248 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1249 (*s)->master_monitor_may_have_changed ();
1250 }
1251 }
1252
1253 void
notify_vca_added(ARDOUR::VCAList & vl)1254 MackieControlProtocol::notify_vca_added (ARDOUR::VCAList& vl)
1255 {
1256 refresh_current_bank ();
1257 }
1258
1259 // RouteList is the set of Routes that have just been added
1260 void
notify_routes_added(ARDOUR::RouteList & rl)1261 MackieControlProtocol::notify_routes_added (ARDOUR::RouteList & rl)
1262 {
1263 {
1264 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1265
1266 if (surfaces.empty()) {
1267 return;
1268 }
1269 }
1270
1271 /* special case: single route, and it is the monitor or master out */
1272
1273 if (rl.size() == 1 && (rl.front()->is_monitor() || rl.front()->is_master())) {
1274 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1275 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1276 (*s)->master_monitor_may_have_changed ();
1277 }
1278 }
1279
1280 // currently assigned banks are less than the full set of
1281 // strips, so activate the new strip now.
1282
1283 refresh_current_bank();
1284
1285 // otherwise route added, but current bank needs no updating
1286 }
1287
1288 void
notify_solo_active_changed(bool active)1289 MackieControlProtocol::notify_solo_active_changed (bool active)
1290 {
1291 boost::shared_ptr<Surface> surface;
1292
1293 {
1294 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1295
1296 if (surfaces.empty()) {
1297 return;
1298 }
1299
1300 surface = _master_surface;
1301 }
1302
1303 map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Led::RudeSolo);
1304 if (x != surface->controls_by_device_independent_id.end()) {
1305 Led* rude_solo = dynamic_cast<Led*> (x->second);
1306 if (rude_solo) {
1307 surface->write (rude_solo->set_state (active ? flashing : off));
1308 }
1309 }
1310 }
1311
1312 void
notify_presentation_info_changed(PBD::PropertyChange const & what_changed)1313 MackieControlProtocol::notify_presentation_info_changed (PBD::PropertyChange const & what_changed)
1314 {
1315 PBD::PropertyChange order_or_hidden;
1316
1317 order_or_hidden.add (Properties::hidden);
1318 order_or_hidden.add (Properties::order);
1319
1320 if (!what_changed.contains (order_or_hidden)) {
1321 return;
1322 }
1323
1324 {
1325 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1326
1327 if (surfaces.empty()) {
1328 return;
1329 }
1330 }
1331
1332 refresh_current_bank();
1333 }
1334
1335 ///////////////////////////////////////////
1336 // Transport signals
1337 ///////////////////////////////////////////
1338
1339 void
notify_loop_state_changed()1340 MackieControlProtocol::notify_loop_state_changed()
1341 {
1342 update_global_button (Button::Loop, session->get_play_loop());
1343 }
1344
1345 void
notify_transport_state_changed()1346 MackieControlProtocol::notify_transport_state_changed()
1347 {
1348 if (!_device_info.has_global_controls()) {
1349 return;
1350 }
1351
1352 // switch various play and stop buttons on / off
1353 update_global_button (Button::Loop, loop_button_onoff ());
1354 update_global_button (Button::Play, play_button_onoff ());
1355 update_global_button (Button::Stop, stop_button_onoff ());
1356 update_global_button (Button::Rewind, rewind_button_onoff ());
1357 update_global_button (Button::Ffwd, ffwd_button_onoff ());
1358
1359 // sometimes a return to start leaves time code at old time
1360 _timecode_last = string (10, ' ');
1361
1362 notify_metering_state_changed ();
1363 }
1364
1365 void
notify_metering_state_changed()1366 MackieControlProtocol::notify_metering_state_changed()
1367 {
1368 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1369
1370 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1371 (*s)->notify_metering_state_changed ();
1372 }
1373 }
1374
1375 void
notify_record_state_changed()1376 MackieControlProtocol::notify_record_state_changed ()
1377 {
1378 if (!_device_info.has_global_controls()) {
1379 return;
1380 }
1381
1382 boost::shared_ptr<Surface> surface;
1383
1384 {
1385 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1386 if (surfaces.empty()) {
1387 return;
1388 }
1389 surface = _master_surface;
1390 }
1391
1392 /* rec is a tristate */
1393
1394 map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Button::Record);
1395 if (x != surface->controls_by_device_independent_id.end()) {
1396 Button * rec = dynamic_cast<Button*> (x->second);
1397 if (rec) {
1398 LedState ls;
1399
1400 switch (session->record_status()) {
1401 case Session::Disabled:
1402 DEBUG_TRACE (DEBUG::MackieControl, "record state changed to disabled, LED off\n");
1403 ls = off;
1404 break;
1405 case Session::Recording:
1406 DEBUG_TRACE (DEBUG::MackieControl, "record state changed to recording, LED on\n");
1407 ls = on;
1408 break;
1409 case Session::Enabled:
1410
1411 if(_device_info.is_qcon()){
1412 // For qcon the rec button is two state only (on/off)
1413 DEBUG_TRACE (DEBUG::MackieControl, "record state changed to enabled, LED on (QCon)\n");
1414 ls = on;
1415 break;
1416
1417 }
1418 else{
1419 // For standard Mackie MCU the record LED is flashing
1420 DEBUG_TRACE (DEBUG::MackieControl, "record state changed to enabled, LED flashing\n");
1421 ls = flashing;
1422 break;
1423 }
1424
1425 break;
1426 }
1427
1428 surface->write (rec->set_state (ls));
1429 }
1430 }
1431 }
1432
1433 list<boost::shared_ptr<ARDOUR::Bundle> >
bundles()1434 MackieControlProtocol::bundles ()
1435 {
1436 list<boost::shared_ptr<ARDOUR::Bundle> > b;
1437
1438 if (_input_bundle) {
1439 b.push_back (_input_bundle);
1440 b.push_back (_output_bundle);
1441 }
1442
1443 return b;
1444 }
1445
1446 void
do_request(MackieControlUIRequest * req)1447 MackieControlProtocol::do_request (MackieControlUIRequest* req)
1448 {
1449 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("doing request type %1\n", req->type));
1450 if (req->type == CallSlot) {
1451
1452 call_slot (MISSING_INVALIDATOR, req->the_slot);
1453
1454 } else if (req->type == Quit) {
1455
1456 stop ();
1457 }
1458 }
1459
1460 int
stop()1461 MackieControlProtocol::stop ()
1462 {
1463 BaseUI::quit ();
1464
1465 return 0;
1466 }
1467
1468 void
update_led(Surface & surface,Button & button,Mackie::LedState ls)1469 MackieControlProtocol::update_led (Surface& surface, Button& button, Mackie::LedState ls)
1470 {
1471 if (ls != none) {
1472 surface.port().write (button.set_state (ls));
1473 }
1474 }
1475
1476 void
build_button_map()1477 MackieControlProtocol::build_button_map ()
1478 {
1479 /* this maps our device-independent button codes to the methods that handle them.
1480 */
1481
1482 #define DEFINE_BUTTON_HANDLER(b,p,r) button_map.insert (pair<Button::ID,ButtonHandlers> ((b), ButtonHandlers ((p),(r))));
1483
1484 DEFINE_BUTTON_HANDLER (Button::Track, &MackieControlProtocol::track_press, &MackieControlProtocol::track_release);
1485 DEFINE_BUTTON_HANDLER (Button::Send, &MackieControlProtocol::send_press, &MackieControlProtocol::send_release);
1486 DEFINE_BUTTON_HANDLER (Button::Pan, &MackieControlProtocol::pan_press, &MackieControlProtocol::pan_release);
1487 DEFINE_BUTTON_HANDLER (Button::Plugin, &MackieControlProtocol::plugin_press, &MackieControlProtocol::plugin_release);
1488 DEFINE_BUTTON_HANDLER (Button::Eq, &MackieControlProtocol::eq_press, &MackieControlProtocol::eq_release);
1489 DEFINE_BUTTON_HANDLER (Button::Dyn, &MackieControlProtocol::dyn_press, &MackieControlProtocol::dyn_release);
1490 DEFINE_BUTTON_HANDLER (Button::Left, &MackieControlProtocol::left_press, &MackieControlProtocol::left_release);
1491 DEFINE_BUTTON_HANDLER (Button::Right, &MackieControlProtocol::right_press, &MackieControlProtocol::right_release);
1492 DEFINE_BUTTON_HANDLER (Button::ChannelLeft, &MackieControlProtocol::channel_left_press, &MackieControlProtocol::channel_left_release);
1493 DEFINE_BUTTON_HANDLER (Button::ChannelRight, &MackieControlProtocol::channel_right_press, &MackieControlProtocol::channel_right_release);
1494 DEFINE_BUTTON_HANDLER (Button::Flip, &MackieControlProtocol::flip_press, &MackieControlProtocol::flip_release);
1495 DEFINE_BUTTON_HANDLER (Button::View, &MackieControlProtocol::view_press, &MackieControlProtocol::view_release);
1496 DEFINE_BUTTON_HANDLER (Button::NameValue, &MackieControlProtocol::name_value_press, &MackieControlProtocol::name_value_release);
1497 DEFINE_BUTTON_HANDLER (Button::TimecodeBeats, &MackieControlProtocol::timecode_beats_press, &MackieControlProtocol::timecode_beats_release);
1498 // DEFINE_BUTTON_HANDLER (Button::F1, &MackieControlProtocol::F1_press, &MackieControlProtocol::F1_release);
1499 // DEFINE_BUTTON_HANDLER (Button::F2, &MackieControlProtocol::F2_press, &MackieControlProtocol::F2_release);
1500 // DEFINE_BUTTON_HANDLER (Button::F3, &MackieControlProtocol::F3_press, &MackieControlProtocol::F3_release);
1501 // DEFINE_BUTTON_HANDLER (Button::F4, &MackieControlProtocol::F4_press, &MackieControlProtocol::F4_release);
1502 // DEFINE_BUTTON_HANDLER (Button::F5, &MackieControlProtocol::F5_press, &MackieControlProtocol::F5_release);
1503 // DEFINE_BUTTON_HANDLER (Button::F6, &MackieControlProtocol::F6_press, &MackieControlProtocol::F6_release);
1504 // DEFINE_BUTTON_HANDLER (Button::F7, &MackieControlProtocol::F7_press, &MackieControlProtocol::F7_release);
1505 // DEFINE_BUTTON_HANDLER (Button::F8, &MackieControlProtocol::F8_press, &MackieControlProtocol::F8_release);
1506 DEFINE_BUTTON_HANDLER (Button::MidiTracks, &MackieControlProtocol::miditracks_press, &MackieControlProtocol::miditracks_release);
1507 DEFINE_BUTTON_HANDLER (Button::Inputs, &MackieControlProtocol::inputs_press, &MackieControlProtocol::inputs_release);
1508 DEFINE_BUTTON_HANDLER (Button::AudioTracks, &MackieControlProtocol::audiotracks_press, &MackieControlProtocol::audiotracks_release);
1509 DEFINE_BUTTON_HANDLER (Button::AudioInstruments, &MackieControlProtocol::audioinstruments_press, &MackieControlProtocol::audioinstruments_release);
1510 DEFINE_BUTTON_HANDLER (Button::Aux, &MackieControlProtocol::aux_press, &MackieControlProtocol::aux_release);
1511 DEFINE_BUTTON_HANDLER (Button::Busses, &MackieControlProtocol::busses_press, &MackieControlProtocol::busses_release);
1512 DEFINE_BUTTON_HANDLER (Button::Outputs, &MackieControlProtocol::outputs_press, &MackieControlProtocol::outputs_release);
1513 DEFINE_BUTTON_HANDLER (Button::User, &MackieControlProtocol::user_press, &MackieControlProtocol::user_release);
1514 DEFINE_BUTTON_HANDLER (Button::Shift, &MackieControlProtocol::shift_press, &MackieControlProtocol::shift_release);
1515 DEFINE_BUTTON_HANDLER (Button::Option, &MackieControlProtocol::option_press, &MackieControlProtocol::option_release);
1516 DEFINE_BUTTON_HANDLER (Button::Ctrl, &MackieControlProtocol::control_press, &MackieControlProtocol::control_release);
1517 DEFINE_BUTTON_HANDLER (Button::CmdAlt, &MackieControlProtocol::cmd_alt_press, &MackieControlProtocol::cmd_alt_release);
1518 DEFINE_BUTTON_HANDLER (Button::Read, &MackieControlProtocol::read_press, &MackieControlProtocol::read_release);
1519 DEFINE_BUTTON_HANDLER (Button::Write, &MackieControlProtocol::write_press, &MackieControlProtocol::write_release);
1520 DEFINE_BUTTON_HANDLER (Button::Trim, &MackieControlProtocol::trim_press, &MackieControlProtocol::trim_release);
1521 DEFINE_BUTTON_HANDLER (Button::Touch, &MackieControlProtocol::touch_press, &MackieControlProtocol::touch_release);
1522 DEFINE_BUTTON_HANDLER (Button::Latch, &MackieControlProtocol::latch_press, &MackieControlProtocol::latch_release);
1523 DEFINE_BUTTON_HANDLER (Button::Grp, &MackieControlProtocol::grp_press, &MackieControlProtocol::grp_release);
1524 DEFINE_BUTTON_HANDLER (Button::Save, &MackieControlProtocol::save_press, &MackieControlProtocol::save_release);
1525 DEFINE_BUTTON_HANDLER (Button::Undo, &MackieControlProtocol::undo_press, &MackieControlProtocol::undo_release);
1526 DEFINE_BUTTON_HANDLER (Button::Cancel, &MackieControlProtocol::cancel_press, &MackieControlProtocol::cancel_release);
1527 DEFINE_BUTTON_HANDLER (Button::Enter, &MackieControlProtocol::enter_press, &MackieControlProtocol::enter_release);
1528 DEFINE_BUTTON_HANDLER (Button::Marker, &MackieControlProtocol::marker_press, &MackieControlProtocol::marker_release);
1529 DEFINE_BUTTON_HANDLER (Button::Nudge, &MackieControlProtocol::nudge_press, &MackieControlProtocol::nudge_release);
1530 DEFINE_BUTTON_HANDLER (Button::Loop, &MackieControlProtocol::loop_press, &MackieControlProtocol::loop_release);
1531 DEFINE_BUTTON_HANDLER (Button::Drop, &MackieControlProtocol::drop_press, &MackieControlProtocol::drop_release);
1532 DEFINE_BUTTON_HANDLER (Button::Replace, &MackieControlProtocol::replace_press, &MackieControlProtocol::replace_release);
1533 DEFINE_BUTTON_HANDLER (Button::Click, &MackieControlProtocol::click_press, &MackieControlProtocol::click_release);
1534 DEFINE_BUTTON_HANDLER (Button::ClearSolo, &MackieControlProtocol::clearsolo_press, &MackieControlProtocol::clearsolo_release);
1535 DEFINE_BUTTON_HANDLER (Button::Rewind, &MackieControlProtocol::rewind_press, &MackieControlProtocol::rewind_release);
1536 DEFINE_BUTTON_HANDLER (Button::Ffwd, &MackieControlProtocol::ffwd_press, &MackieControlProtocol::ffwd_release);
1537 DEFINE_BUTTON_HANDLER (Button::Stop, &MackieControlProtocol::stop_press, &MackieControlProtocol::stop_release);
1538 DEFINE_BUTTON_HANDLER (Button::Play, &MackieControlProtocol::play_press, &MackieControlProtocol::play_release);
1539 DEFINE_BUTTON_HANDLER (Button::Record, &MackieControlProtocol::record_press, &MackieControlProtocol::record_release);
1540 DEFINE_BUTTON_HANDLER (Button::CursorUp, &MackieControlProtocol::cursor_up_press, &MackieControlProtocol::cursor_up_release);
1541 DEFINE_BUTTON_HANDLER (Button::CursorDown, &MackieControlProtocol::cursor_down_press, &MackieControlProtocol::cursor_down_release);
1542 DEFINE_BUTTON_HANDLER (Button::CursorLeft, &MackieControlProtocol::cursor_left_press, &MackieControlProtocol::cursor_left_release);
1543 DEFINE_BUTTON_HANDLER (Button::CursorRight, &MackieControlProtocol::cursor_right_press, &MackieControlProtocol::cursor_right_release);
1544 DEFINE_BUTTON_HANDLER (Button::Zoom, &MackieControlProtocol::zoom_press, &MackieControlProtocol::zoom_release);
1545 DEFINE_BUTTON_HANDLER (Button::Scrub, &MackieControlProtocol::scrub_press, &MackieControlProtocol::scrub_release);
1546 DEFINE_BUTTON_HANDLER (Button::UserA, &MackieControlProtocol::user_a_press, &MackieControlProtocol::user_a_release);
1547 DEFINE_BUTTON_HANDLER (Button::UserB, &MackieControlProtocol::user_b_press, &MackieControlProtocol::user_b_release);
1548 DEFINE_BUTTON_HANDLER (Button::MasterFaderTouch, &MackieControlProtocol::master_fader_touch_press, &MackieControlProtocol::master_fader_touch_release);
1549 }
1550
1551 void
handle_button_event(Surface & surface,Button & button,ButtonState bs)1552 MackieControlProtocol::handle_button_event (Surface& surface, Button& button, ButtonState bs)
1553 {
1554 Button::ID button_id = button.bid();
1555
1556 if (bs != press && bs != release) {
1557 update_led (surface, button, none);
1558 return;
1559 }
1560
1561 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Handling %1 for button %2 (%3)\n", (bs == press ? "press" : "release"), button.id(),
1562 Button::id_to_name (button.bid())));
1563
1564 /* check profile first */
1565
1566 string action = _device_profile.get_button_action (button.bid(), _modifier_state);
1567
1568 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device profile returned [%1] for that button\n", action));
1569
1570 if (!action.empty()) {
1571
1572 if (action.find ('/') != string::npos) { /* good chance that this is really an action */
1573
1574 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Looked up action for button %1 with modifier %2, got [%3]\n",
1575 button.bid(), _modifier_state, action));
1576
1577 /* if there is a bound action for this button, and this is a press event,
1578 carry out the action. If its a release event, do nothing since we
1579 don't bind to them at all but don't want any other handling to
1580 occur either.
1581 */
1582 if (bs == press) {
1583 update_led (surface, button, on);
1584 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("executing action %1\n", action));
1585 access_action (action);
1586 } else {
1587 update_led (surface, button, off);
1588 }
1589 return;
1590
1591 } else {
1592
1593 /* "action" is more likely to be a button name. We use this to
1594 * allow remapping buttons to different (builtin) functionality
1595 * associated with an existing button. This is similar to the
1596 * way that (for example) Nuendo moves the "Shift" function to
1597 * the "Enter" key of the MCU Pro.
1598 */
1599
1600 int bid = Button::name_to_id (action);
1601
1602 if (bid < 0) {
1603 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("apparent button name %1 not found\n", action));
1604 return;
1605 }
1606
1607 button_id = (Button::ID) bid;
1608 DEBUG_TRACE (DEBUG::MackieControl, 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)));
1609 }
1610 }
1611
1612 /* Now that we have the correct (maybe remapped) button ID, do these
1613 * checks on it.
1614 */
1615
1616 if ((button_id != Button::Marker) && (modifier_state() & MODIFIER_MARKER)) {
1617 marker_modifier_consumed_by_button = true;
1618 }
1619
1620 if ((button_id != Button::Nudge) && (modifier_state() & MODIFIER_NUDGE)) {
1621 nudge_modifier_consumed_by_button = true;
1622 }
1623
1624 /* lookup using the device-INDEPENDENT button ID */
1625
1626 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("now looking up button ID %1\n", button_id));
1627
1628 ButtonMap::iterator b = button_map.find (button_id);
1629
1630 if (b != button_map.end()) {
1631
1632 ButtonHandlers& bh (b->second);
1633
1634 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("button found in map, now invoking %1\n", (bs == press ? "press" : "release")));
1635
1636 switch (bs) {
1637 case press:
1638 surface.write (button.set_state ((this->*(bh.press)) (button)));
1639 break;
1640 case release:
1641 surface.write (button.set_state ((this->*(bh.release)) (button)));
1642 break;
1643 default:
1644 break;
1645 }
1646 } else {
1647 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("no button handlers for button ID %1 (device ID %2)\n",
1648 button.bid(), button.id()));
1649 error << string_compose ("no button handlers for button ID %1 (device ID %2)\n",
1650 button.bid(), button.id()) << endmsg;
1651 }
1652 }
1653
1654 bool
midi_input_handler(IOCondition ioc,MIDI::Port * port)1655 MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
1656 {
1657 if (ioc & ~IO_IN) {
1658 DEBUG_TRACE (DEBUG::MackieControl, "MIDI port closed\n");
1659 return false;
1660 }
1661
1662 if (ioc & IO_IN) {
1663
1664 // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("something happend on %1\n", port->name()));
1665
1666 /* Devices using regular JACK MIDI ports will need to have
1667 the x-thread FIFO drained to avoid burning endless CPU.
1668
1669 Devices using ipMIDI have port->selectable() as the same
1670 file descriptor that data arrives on, so doing this
1671 for them will simply throw all incoming data away.
1672 */
1673
1674 if (!_device_info.uses_ipmidi()) {
1675 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
1676 if (asp) {
1677 asp->clear ();
1678 }
1679 }
1680
1681 // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name()));
1682 samplepos_t now = session->engine().sample_time();
1683 port->parse (now);
1684 }
1685
1686 return true;
1687 }
1688
1689 void
clear_ports()1690 MackieControlProtocol::clear_ports ()
1691 {
1692 if (_input_bundle) {
1693 _input_bundle->remove_channels ();
1694 _output_bundle->remove_channels ();
1695 }
1696 }
1697
1698 void
notify_subview_stripable_deleted()1699 MackieControlProtocol::notify_subview_stripable_deleted ()
1700 {
1701 /* return to global/mixer view */
1702 _subview->notify_subview_stripable_deleted();
1703 set_view_mode (Mixer);
1704 }
1705
1706 bool
redisplay_subview_mode()1707 MackieControlProtocol::redisplay_subview_mode ()
1708 {
1709 Surfaces copy; /* can't hold surfaces lock while calling Strip::subview_mode_changed */
1710
1711 {
1712 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1713 copy = surfaces;
1714 }
1715
1716 for (Surfaces::iterator s = copy.begin(); s != copy.end(); ++s) {
1717 (*s)->subview_mode_changed ();
1718 }
1719
1720 /* don't call this again from a timeout */
1721 return false;
1722 }
1723
1724 bool
set_subview_mode(Subview::Mode sm,boost::shared_ptr<Stripable> r)1725 MackieControlProtocol::set_subview_mode (Subview::Mode sm, boost::shared_ptr<Stripable> r)
1726 {
1727 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));
1728
1729 if (_flip_mode != Normal) {
1730 set_flip_mode (Normal);
1731 }
1732
1733 std::string reason_why_subview_not_possible = "";
1734 if (!_subview->subview_mode_would_be_ok (sm, r, reason_why_subview_not_possible)) {
1735
1736 DEBUG_TRACE (DEBUG::MackieControl, "subview mode not OK\n");
1737
1738 if (r) {
1739
1740 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1741
1742 if (!surfaces.empty()) {
1743 if (!reason_why_subview_not_possible.empty()) {
1744 surfaces.front()->display_message_for (reason_why_subview_not_possible, 1000);
1745 if (_subview->subview_mode() != Mackie::Subview::None) {
1746 /* redisplay current subview mode after
1747 that message goes away.
1748 */
1749 Glib::RefPtr<Glib::TimeoutSource> redisplay_timeout = Glib::TimeoutSource::create (1000); // milliseconds
1750 redisplay_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::redisplay_subview_mode));
1751 redisplay_timeout->attach (main_loop()->get_context());
1752 }
1753 }
1754 }
1755 }
1756
1757 return false;
1758 }
1759
1760 _subview = Mackie::SubviewFactory::instance()->create_subview(sm, *this, r);
1761 /* Catch the current subview stripable going away */
1762 if (_subview->subview_stripable()) {
1763 _subview->subview_stripable()->DropReferences.connect (_subview->subview_stripable_connections(), MISSING_INVALIDATOR,
1764 boost::bind (&MackieControlProtocol::notify_subview_stripable_deleted, this),
1765 this);
1766 }
1767
1768 redisplay_subview_mode ();
1769 _subview->update_global_buttons();
1770
1771 return true;
1772 }
1773
1774 void
set_view_mode(ViewMode m)1775 MackieControlProtocol::set_view_mode (ViewMode m)
1776 {
1777 if (_flip_mode != Normal) {
1778 set_flip_mode (Normal);
1779 }
1780 ViewMode old_view_mode = _view_mode;
1781
1782 _view_mode = m;
1783 _last_bank[old_view_mode] = _current_initial_bank;
1784
1785 if (switch_banks(_last_bank[m], true)) {
1786 _view_mode = old_view_mode;
1787 return;
1788 }
1789
1790 /* leave subview mode, whatever it was */
1791 DEBUG_TRACE (DEBUG::MackieControl, "\t\t\tsubview mode reset in MackieControlProtocol::set_view_mode \n");
1792 set_subview_mode (Mackie::Subview::None, boost::shared_ptr<Stripable>());
1793 display_view_mode ();
1794 }
1795
1796 void
display_view_mode()1797 MackieControlProtocol::display_view_mode ()
1798 {
1799 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1800
1801 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1802 (*s)->update_view_mode_display (true);
1803 }
1804 }
1805
1806 void
set_flip_mode(FlipMode fm)1807 MackieControlProtocol::set_flip_mode (FlipMode fm)
1808 {
1809 if (fm == Normal) {
1810 update_global_button (Button::Flip, off);
1811 } else {
1812 update_global_button (Button::Flip, on);
1813 }
1814
1815 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1816
1817 _flip_mode = fm;
1818
1819 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1820 (*s)->update_flip_mode_display ();
1821 }
1822 }
1823
1824 void
set_master_on_surface_strip(uint32_t surface,uint32_t strip_number)1825 MackieControlProtocol::set_master_on_surface_strip (uint32_t surface, uint32_t strip_number)
1826 {
1827 force_special_stripable_to_strip (session->master_out(), surface, strip_number);
1828 }
1829
1830 void
set_monitor_on_surface_strip(uint32_t surface,uint32_t strip_number)1831 MackieControlProtocol::set_monitor_on_surface_strip (uint32_t surface, uint32_t strip_number)
1832 {
1833 force_special_stripable_to_strip (session->monitor_out(), surface, strip_number);
1834 }
1835
1836 void
force_special_stripable_to_strip(boost::shared_ptr<Stripable> r,uint32_t surface,uint32_t strip_number)1837 MackieControlProtocol::force_special_stripable_to_strip (boost::shared_ptr<Stripable> r, uint32_t surface, uint32_t strip_number)
1838 {
1839 if (!r) {
1840 return;
1841 }
1842
1843 Glib::Threads::Mutex::Lock lm (surfaces_lock);
1844
1845 for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
1846 if ((*s)->number() == surface) {
1847 Strip* strip = (*s)->nth_strip (strip_number);
1848 if (strip) {
1849 strip->set_stripable (session->master_out());
1850 strip->lock_controls ();
1851 }
1852 }
1853 }
1854 }
1855
1856 void
check_fader_automation_state()1857 MackieControlProtocol::check_fader_automation_state ()
1858 {
1859 fader_automation_connections.drop_connections ();
1860
1861 boost::shared_ptr<Stripable> r = first_selected_stripable ();
1862
1863 if (!r) {
1864 update_global_button (Button::Read, off);
1865 update_global_button (Button::Write, off);
1866 update_global_button (Button::Touch, off);
1867 update_global_button (Button::Trim, off);
1868 update_global_button (Button::Latch, off);
1869 update_global_button (Button::Grp, on);
1870 return;
1871 }
1872
1873 r->gain_control()->alist()->automation_state_changed.connect (fader_automation_connections,
1874 MISSING_INVALIDATOR,
1875 boost::bind (&MackieControlProtocol::update_fader_automation_state, this),
1876 this);
1877
1878 update_fader_automation_state ();
1879 }
1880
1881 void
update_fader_automation_state()1882 MackieControlProtocol::update_fader_automation_state ()
1883 {
1884 boost::shared_ptr<Stripable> r = first_selected_stripable ();
1885
1886 if (!r) {
1887 update_global_button (Button::Read, off);
1888 update_global_button (Button::Write, off);
1889 update_global_button (Button::Touch, off);
1890 update_global_button (Button::Trim, off);
1891 update_global_button (Button::Latch, off);
1892 update_global_button (Button::Grp, on);
1893 return;
1894 }
1895
1896 switch (r->gain_control()->automation_state()) {
1897 case Off:
1898 update_global_button (Button::Read, off);
1899 update_global_button (Button::Write, off);
1900 update_global_button (Button::Touch, off);
1901 update_global_button (Button::Trim, off);
1902 update_global_button (Button::Latch, off);
1903 update_global_button (Button::Grp, on);
1904 break;
1905 case Play:
1906 update_global_button (Button::Read, on);
1907 update_global_button (Button::Write, off);
1908 update_global_button (Button::Touch, off);
1909 update_global_button (Button::Trim, off);
1910 update_global_button (Button::Latch, off);
1911 update_global_button (Button::Grp, off);
1912 break;
1913 case Write:
1914 update_global_button (Button::Read, off);
1915 update_global_button (Button::Write, on);
1916 update_global_button (Button::Touch, off);
1917 update_global_button (Button::Trim, off);
1918 update_global_button (Button::Latch, off);
1919 update_global_button (Button::Grp, off);
1920 break;
1921 case Touch:
1922 update_global_button (Button::Read, off);
1923 update_global_button (Button::Write, off);
1924 update_global_button (Button::Touch, on);
1925 update_global_button (Button::Trim, off);
1926 update_global_button (Button::Latch, off);
1927 update_global_button (Button::Grp, off);
1928 break;
1929 case Latch:
1930 update_global_button (Button::Read, off);
1931 update_global_button (Button::Write, off);
1932 update_global_button (Button::Touch, off);
1933 update_global_button (Button::Trim, off);
1934 update_global_button (Button::Latch, on);
1935 update_global_button (Button::Grp, off);
1936 break;
1937 }
1938 }
1939
1940 samplepos_t
transport_sample() const1941 MackieControlProtocol::transport_sample() const
1942 {
1943 return session->transport_sample();
1944 }
1945
1946 void
add_down_select_button(int surface,int strip)1947 MackieControlProtocol::add_down_select_button (int surface, int strip)
1948 {
1949 _down_select_buttons.insert ((surface<<8)|(strip&0xf));
1950 }
1951
1952 void
remove_down_select_button(int surface,int strip)1953 MackieControlProtocol::remove_down_select_button (int surface, int strip)
1954 {
1955 DownButtonList::iterator x = find (_down_select_buttons.begin(), _down_select_buttons.end(), (uint32_t) (surface<<8)|(strip&0xf));
1956 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("removing surface %1 strip %2 from down select buttons\n", surface, strip));
1957 if (x != _down_select_buttons.end()) {
1958 _down_select_buttons.erase (x);
1959 } else {
1960 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 not found in down select buttons\n",
1961 surface, strip));
1962 }
1963 }
1964
1965 void
select_range(uint32_t pressed)1966 MackieControlProtocol::select_range (uint32_t pressed)
1967 {
1968 StripableList stripables;
1969
1970 pull_stripable_range (_down_select_buttons, stripables, pressed);
1971
1972 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("select range: found %1 stripables, first = %2\n", stripables.size(),
1973 (stripables.empty() ? "null" : stripables.front()->name())));
1974
1975 if (stripables.empty()) {
1976 return;
1977 }
1978
1979 if (stripables.size() == 1 && ControlProtocol::last_selected().size() == 1 && stripables.front()->is_selected()) {
1980 /* cancel selection for one and only selected stripable */
1981 toggle_stripable_selection (stripables.front());
1982 } else {
1983 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
1984
1985 if (main_modifier_state() == MODIFIER_SHIFT) {
1986 toggle_stripable_selection (*s);
1987 } else {
1988 if (s == stripables.begin()) {
1989 set_stripable_selection (*s);
1990 } else {
1991 add_stripable_to_selection (*s);
1992 }
1993 }
1994 }
1995 }
1996 }
1997
1998 void
add_down_button(AutomationType a,int surface,int strip)1999 MackieControlProtocol::add_down_button (AutomationType a, int surface, int strip)
2000 {
2001 DownButtonMap::iterator m = _down_buttons.find (a);
2002
2003 if (m == _down_buttons.end()) {
2004 _down_buttons[a] = DownButtonList();
2005 }
2006
2007 _down_buttons[a].insert ((surface<<8)|(strip&0xf));
2008 }
2009
2010 void
remove_down_button(AutomationType a,int surface,int strip)2011 MackieControlProtocol::remove_down_button (AutomationType a, int surface, int strip)
2012 {
2013 DownButtonMap::iterator m = _down_buttons.find (a);
2014
2015 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("removing surface %1 strip %2 from down buttons for %3\n", surface, strip, (int) a));
2016
2017 if (m == _down_buttons.end()) {
2018 return;
2019 }
2020
2021 DownButtonList& l (m->second);
2022 DownButtonList::iterator x = find (l.begin(), l.end(), (surface<<8)|(strip&0xf));
2023
2024 if (x != l.end()) {
2025 l.erase (x);
2026 } else {
2027 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 not found in down buttons for %3\n",
2028 surface, strip, (int) a));
2029 }
2030 }
2031
2032 MackieControlProtocol::ControlList
down_controls(AutomationType p,uint32_t pressed)2033 MackieControlProtocol::down_controls (AutomationType p, uint32_t pressed)
2034 {
2035 ControlList controls;
2036 StripableList stripables;
2037
2038 DownButtonMap::iterator m = _down_buttons.find (p);
2039
2040 if (m == _down_buttons.end()) {
2041 return controls;
2042 }
2043
2044 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("looking for down buttons for %1, got %2\n",
2045 p, m->second.size()));
2046
2047 pull_stripable_range (m->second, stripables, pressed);
2048
2049 switch (p) {
2050 case GainAutomation:
2051 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
2052 controls.push_back ((*s)->gain_control());
2053 }
2054 break;
2055 case SoloAutomation:
2056 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
2057 controls.push_back ((*s)->solo_control());
2058 }
2059 break;
2060 case MuteAutomation:
2061 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
2062 controls.push_back ((*s)->mute_control());
2063 }
2064 break;
2065 case RecEnableAutomation:
2066 for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
2067 boost::shared_ptr<AutomationControl> ac = (*s)->rec_enable_control();
2068 if (ac) {
2069 controls.push_back (ac);
2070 }
2071 }
2072 break;
2073 default:
2074 break;
2075 }
2076
2077 return controls;
2078
2079 }
2080
2081 struct ButtonRangeSorter {
operator ()ButtonRangeSorter2082 bool operator() (const uint32_t& a, const uint32_t& b) {
2083 return (a>>8) < (b>>8) // a.surface < b.surface
2084 ||
2085 ((a>>8) == (b>>8) && (a&0xf) < (b&0xf)); // a.surface == b.surface && a.strip < b.strip
2086 }
2087 };
2088
2089 void
pull_stripable_range(DownButtonList & down,StripableList & selected,uint32_t pressed)2090 MackieControlProtocol::pull_stripable_range (DownButtonList& down, StripableList& selected, uint32_t pressed)
2091 {
2092 ButtonRangeSorter cmp;
2093
2094 if (down.empty()) {
2095 return;
2096 }
2097
2098 list<uint32_t> ldown;
2099 ldown.insert (ldown.end(), down.begin(), down.end());
2100 ldown.sort (cmp);
2101
2102 uint32_t first = ldown.front();
2103 uint32_t last = ldown.back ();
2104
2105 uint32_t first_surface = first>>8;
2106 uint32_t first_strip = first&0xf;
2107
2108 uint32_t last_surface = last>>8;
2109 uint32_t last_strip = last&0xf;
2110
2111 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("PRR %5 in list %1.%2 - %3.%4\n", first_surface, first_strip, last_surface, last_strip,
2112 down.size()));
2113
2114 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2115
2116 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2117
2118 if ((*s)->number() >= first_surface && (*s)->number() <= last_surface) {
2119
2120 uint32_t fs;
2121 uint32_t ls;
2122
2123 if ((*s)->number() == first_surface) {
2124 fs = first_strip;
2125 } else {
2126 fs = 0;
2127 }
2128
2129 if ((*s)->number() == last_surface) {
2130 ls = last_strip;
2131 ls += 1;
2132 } else {
2133 ls = (*s)->n_strips ();
2134 }
2135
2136 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("adding strips for surface %1 (%2 .. %3)\n",
2137 (*s)->number(), fs, ls));
2138
2139 for (uint32_t n = fs; n < ls; ++n) {
2140 Strip* strip = (*s)->nth_strip (n);
2141 boost::shared_ptr<Stripable> r = strip->stripable();
2142 if (r) {
2143 if (global_index_locked (*strip) == pressed) {
2144 selected.push_front (r);
2145 } else {
2146 selected.push_back (r);
2147 }
2148 }
2149 }
2150 }
2151 }
2152
2153 }
2154
2155 void
set_ipmidi_base(int16_t portnum)2156 MackieControlProtocol::set_ipmidi_base (int16_t portnum)
2157 {
2158 /* this will not be saved without a session save, so .. */
2159
2160 session->set_dirty ();
2161
2162 _ipmidi_base = portnum;
2163
2164 /* if the current device uses ipMIDI we need
2165 to restart.
2166 */
2167
2168 if (active() && _device_info.uses_ipmidi()) {
2169 needs_ipmidi_restart = true;
2170 }
2171 }
2172
2173 int
ipmidi_restart()2174 MackieControlProtocol::ipmidi_restart ()
2175 {
2176 clear_surfaces ();
2177 if (create_surfaces ()) {
2178 return -1;
2179 }
2180 (void) switch_banks (_current_initial_bank, true);
2181 needs_ipmidi_restart = false;
2182 return 0;
2183 }
2184
2185 void
clear_surfaces()2186 MackieControlProtocol::clear_surfaces ()
2187 {
2188 clear_ports ();
2189
2190 {
2191 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2192 _master_surface.reset ();
2193 surfaces.clear ();
2194 }
2195 }
2196
2197 void
set_touch_sensitivity(int sensitivity)2198 MackieControlProtocol::set_touch_sensitivity (int sensitivity)
2199 {
2200 sensitivity = min (9, sensitivity);
2201 sensitivity = max (0, sensitivity);
2202
2203 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2204
2205 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2206 (*s)->set_touch_sensitivity (sensitivity);
2207 }
2208 }
2209
2210 void
recalibrate_faders()2211 MackieControlProtocol::recalibrate_faders ()
2212 {
2213 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2214
2215 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2216 (*s)->recalibrate_faders ();
2217 }
2218 }
2219
2220 void
toggle_backlight()2221 MackieControlProtocol::toggle_backlight ()
2222 {
2223 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2224
2225 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2226 (*s)->toggle_backlight ();
2227 }
2228 }
2229
2230 boost::shared_ptr<Surface>
get_surface_by_raw_pointer(void * ptr) const2231 MackieControlProtocol::get_surface_by_raw_pointer (void* ptr) const
2232 {
2233 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2234
2235 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2236 if ((*s).get() == (Surface*) ptr) {
2237 return *s;
2238 }
2239 }
2240
2241 return boost::shared_ptr<Surface> ();
2242 }
2243
2244 boost::shared_ptr<Surface>
nth_surface(uint32_t n) const2245 MackieControlProtocol::nth_surface (uint32_t n) const
2246 {
2247 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2248
2249 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s, --n) {
2250 if (n == 0) {
2251 return *s;
2252 }
2253 }
2254
2255 return boost::shared_ptr<Surface> ();
2256 }
2257
2258 void
connection_handler(boost::weak_ptr<ARDOUR::Port> wp1,std::string name1,boost::weak_ptr<ARDOUR::Port> wp2,std::string name2,bool yn)2259 MackieControlProtocol::connection_handler (boost::weak_ptr<ARDOUR::Port> wp1, std::string name1, boost::weak_ptr<ARDOUR::Port> wp2, std::string name2, bool yn)
2260 {
2261 Surfaces scopy;
2262 {
2263 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2264 scopy = surfaces;
2265 }
2266
2267 for (Surfaces::const_iterator s = scopy.begin(); s != scopy.end(); ++s) {
2268 if ((*s)->connection_handler (wp1, name1, wp2, name2, yn)) {
2269 ConnectionChange (*s);
2270 break;
2271 }
2272 }
2273 }
2274
2275 bool
is_track(boost::shared_ptr<Stripable> r) const2276 MackieControlProtocol::is_track (boost::shared_ptr<Stripable> r) const
2277 {
2278 return boost::dynamic_pointer_cast<Track>(r) != 0;
2279 }
2280
2281 bool
is_audio_track(boost::shared_ptr<Stripable> r) const2282 MackieControlProtocol::is_audio_track (boost::shared_ptr<Stripable> r) const
2283 {
2284 return boost::dynamic_pointer_cast<AudioTrack>(r) != 0;
2285 }
2286
2287 bool
is_midi_track(boost::shared_ptr<Stripable> r) const2288 MackieControlProtocol::is_midi_track (boost::shared_ptr<Stripable> r) const
2289 {
2290 return boost::dynamic_pointer_cast<MidiTrack>(r) != 0;
2291 }
2292
2293 bool
is_mapped(boost::shared_ptr<Stripable> r) const2294 MackieControlProtocol::is_mapped (boost::shared_ptr<Stripable> r) const
2295 {
2296 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2297
2298 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2299 if ((*s)->stripable_is_mapped (r)) {
2300 return true;
2301 }
2302 }
2303
2304 return false;
2305 }
2306
2307 void
stripable_selection_changed()2308 MackieControlProtocol::stripable_selection_changed ()
2309 {
2310 //this function is called after the stripable selection is "stable", so this is the place to check surface selection state
2311 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
2312 (*si)->update_strip_selection ();
2313 }
2314
2315 /* if we are following the Gui, find the selected strips and map them here */
2316 if (_device_info.single_fader_follows_selection()) {
2317
2318 Sorted sorted = get_sorted_stripables();
2319
2320 Sorted::iterator r = sorted.begin();
2321 for (Surfaces::iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
2322 vector<boost::shared_ptr<Stripable> > stripables;
2323 uint32_t added = 0;
2324
2325 for (; r != sorted.end() && added < (*si)->n_strips (false); ++r, ++added) {
2326 if ((*r)->is_selected()) {
2327 stripables.push_back (*r);
2328 }
2329 }
2330
2331 (*si)->map_stripables (stripables);
2332 }
2333 return;
2334 }
2335
2336 boost::shared_ptr<Stripable> s = first_selected_stripable ();
2337 if (s) {
2338 check_fader_automation_state ();
2339
2340 /* It is possible that first_selected_route() may return null if we
2341 * are no longer displaying/mapping that route. In that case,
2342 * we will exit subview mode. If first_selected_route() is
2343 * null, and subview mode is not None, then the first call to
2344 * set_subview_mode() will fail, and we will reset to None.
2345 */
2346
2347 if (!set_subview_mode (_subview->subview_mode(), s)) {
2348 set_subview_mode (Mackie::Subview::None, boost::shared_ptr<Stripable>());
2349 }
2350 }
2351 else {
2352 // none selected or not on surface
2353 set_subview_mode(Mackie::Subview::None, boost::shared_ptr<Stripable>());
2354 }
2355 }
2356
2357 boost::shared_ptr<Stripable>
first_selected_stripable() const2358 MackieControlProtocol::first_selected_stripable () const
2359 {
2360 boost::shared_ptr<Stripable> s = ControlProtocol::first_selected_stripable();
2361
2362 if (s) {
2363 /* check it is on one of our surfaces */
2364
2365 if (is_mapped (s)) {
2366 return s;
2367 }
2368
2369 /* stripable is not mapped. thus, the currently selected stripable is
2370 * not on the surfaces, and so from our perspective, there is
2371 * no currently selected stripable.
2372 */
2373
2374 s.reset ();
2375 }
2376
2377 return s; /* may be null */
2378 }
2379
2380 uint32_t
global_index(Strip & strip)2381 MackieControlProtocol::global_index (Strip& strip)
2382 {
2383 Glib::Threads::Mutex::Lock lm (surfaces_lock);
2384 return global_index_locked (strip);
2385 }
2386
2387 uint32_t
global_index_locked(Strip & strip)2388 MackieControlProtocol::global_index_locked (Strip& strip)
2389 {
2390 uint32_t global = 0;
2391
2392 for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
2393 if ((*s).get() == strip.surface()) {
2394 return global + strip.index();
2395 }
2396 global += (*s)->n_strips ();
2397 }
2398
2399 return global;
2400 }
2401
2402 void*
request_factory(uint32_t num_requests)2403 MackieControlProtocol::request_factory (uint32_t num_requests)
2404 {
2405 /* AbstractUI<T>::request_buffer_factory() is a template method only
2406 instantiated in this source module. To provide something visible for
2407 use in the interface/descriptor, we have this static method that is
2408 template-free.
2409 */
2410 return request_buffer_factory (num_requests);
2411 }
2412
2413 void
set_automation_state(AutoState as)2414 MackieControlProtocol::set_automation_state (AutoState as)
2415 {
2416 boost::shared_ptr<Stripable> r = first_selected_stripable ();
2417
2418 if (!r) {
2419 return;
2420 }
2421
2422 boost::shared_ptr<AutomationControl> ac = r->gain_control();
2423
2424 if (!ac) {
2425 return;
2426 }
2427
2428 ac->set_automation_state (as);
2429 }
2430