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