1 /*
2  * Copyright (C) 2015-2018 Ben Loftis <ben@harrisonconsoles.com>
3  * Copyright (C) 2015-2018 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2016-2019 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <cstdlib>
22 #include <sstream>
23 #include <algorithm>
24 
25 #include <stdint.h>
26 
27 #include <glibmm/fileutils.h>
28 #include <glibmm/miscutils.h>
29 
30 #include "pbd/error.h"
31 #include "pbd/failed_constructor.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/compose.h"
35 #include "pbd/xml++.h"
36 
37 #include "midi++/port.h"
38 
39 #include "ardour/async_midi_port.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/amp.h"
42 #include "ardour/bundle.h"
43 #include "ardour/debug.h"
44 #include "ardour/filesystem_paths.h"
45 #include "ardour/midi_port.h"
46 #include "ardour/midiport_manager.h"
47 #include "ardour/monitor_processor.h"
48 #include "ardour/profile.h"
49 #include "ardour/rc_configuration.h"
50 #include "ardour/record_enable_control.h"
51 #include "ardour/stripable.h"
52 #include "ardour/session.h"
53 #include "ardour/session_configuration.h"
54 #include "ardour/track.h"
55 
56 #include "faderport.h"
57 
58 using namespace ARDOUR;
59 using namespace ArdourSurface;
60 using namespace PBD;
61 using namespace Glib;
62 using namespace std;
63 
64 #include "pbd/i18n.h"
65 
66 #include "pbd/abstract_ui.cc" // instantiate template
67 
FaderPort(Session & s)68 FaderPort::FaderPort (Session& s)
69 	: ControlProtocol (s, _("PreSonus FaderPort"))
70 	, AbstractUI<FaderPortRequest> (name())
71 	, gui (0)
72 	, connection_state (ConnectionState (0))
73 	, _device_active (false)
74 	, fader_msb (0)
75 	, fader_lsb (0)
76 	, fader_is_touched (false)
77 	, button_state (ButtonState (0))
78 	, blink_state (false)
79 	, rec_enable_state (false)
80 {
81 	last_encoder_time = 0;
82 
83 	boost::shared_ptr<ARDOUR::Port> inp;
84 	boost::shared_ptr<ARDOUR::Port> outp;
85 
86 	inp  = AudioEngine::instance()->register_input_port (DataType::MIDI, "Faderport Recv", true);
87 	outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "Faderport Send", true);
88 
89 	_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(inp);
90 	_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(outp);
91 
92 	if (_input_port == 0 || _output_port == 0) {
93 		throw failed_constructor();
94 	}
95 
96 	_input_bundle.reset (new ARDOUR::Bundle (_("Faderport Support (Receive)"), true));
97 	_output_bundle.reset (new ARDOUR::Bundle (_("Faderport Support (Send)"), false));
98 
99 	_input_bundle->add_channel (
100 		"",
101 		ARDOUR::DataType::MIDI,
102 		session->engine().make_port_name_non_relative (inp->name())
103 		);
104 
105 	_output_bundle->add_channel (
106 		"",
107 		ARDOUR::DataType::MIDI,
108 		session->engine().make_port_name_non_relative (outp->name())
109 		);
110 
111 	/* Catch port connections and disconnections */
112 	ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (_port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), this);
113 
114 	buttons.insert (std::make_pair (Mute, Button (*this, _("Mute"), Mute, 21)));
115 	buttons.insert (std::make_pair (Solo, Button (*this, _("Solo"), Solo, 22)));
116 	buttons.insert (std::make_pair (Rec, Button (*this, _("Rec"), Rec, 23)));
117 	buttons.insert (std::make_pair (Left, Button (*this, _("Left"), Left, 20)));
118 	buttons.insert (std::make_pair (Bank, Button (*this, _("Bank"), Bank, 19)));
119 	buttons.insert (std::make_pair (Right, Button (*this, _("Right"), Right, 18)));
120 	buttons.insert (std::make_pair (Output, Button (*this, _("Output"), Output, 17)));
121 	buttons.insert (std::make_pair (FP_Read, Button (*this, _("Read"), FP_Read, 13)));
122 	buttons.insert (std::make_pair (FP_Write, Button (*this, _("Write"), FP_Write, 14)));
123 	buttons.insert (std::make_pair (FP_Touch, Button (*this, _("Touch"), FP_Touch, 15)));
124 	buttons.insert (std::make_pair (FP_Off, Button (*this, _("Off"), FP_Off, 16)));
125 	buttons.insert (std::make_pair (Mix, Button (*this, _("Mix"), Mix, 12)));
126 	buttons.insert (std::make_pair (Proj, Button (*this, _("Proj"), Proj, 11)));
127 	buttons.insert (std::make_pair (Trns, Button (*this, _("Trns"), Trns, 10)));
128 	buttons.insert (std::make_pair (Undo, Button (*this, _("Undo"), Undo, 9)));
129 	buttons.insert (std::make_pair (Shift, Button (*this, _("Shift"), Shift, 5)));
130 	buttons.insert (std::make_pair (Punch, Button (*this, _("Punch"), Punch, 6)));
131 	buttons.insert (std::make_pair (User, Button (*this, _("User"), User, 7)));
132 	buttons.insert (std::make_pair (Loop, Button (*this, _("Loop"), Loop, 8)));
133 	buttons.insert (std::make_pair (Rewind, Button (*this, _("Rewind"), Rewind, 4)));
134 	buttons.insert (std::make_pair (Ffwd, Button (*this, _("Ffwd"), Ffwd, 3)));
135 	buttons.insert (std::make_pair (Stop, Button (*this, _("Stop"), Stop, 2)));
136 	buttons.insert (std::make_pair (Play, Button (*this, _("Play"), Play, 1)));
137 	buttons.insert (std::make_pair (RecEnable, Button (*this, _("RecEnable"), RecEnable, 0)));
138 	buttons.insert (std::make_pair (Footswitch, Button (*this, _("Footswitch"), Footswitch, -1)));
139 	buttons.insert (std::make_pair (FaderTouch, Button (*this, _("Fader (touch)"), FaderTouch, -1)));
140 
141 	get_button (Shift).set_flash (true);
142 	get_button (Mix).set_flash (true);
143 	get_button (Proj).set_flash (true);
144 	get_button (Trns).set_flash (true);
145 	get_button (User).set_flash (true);
146 
147 	get_button (Left).set_action ( boost::bind (&FaderPort::left, this), true);
148 	get_button (Right).set_action ( boost::bind (&FaderPort::right, this), true);
149 
150 	get_button (Undo).set_action (boost::bind (&FaderPort::undo, this), true);
151 	get_button (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown);
152 	get_button (Undo).set_flash (true);
153 
154 	get_button (FP_Read).set_action (boost::bind (&FaderPort::read, this), true);
155 	get_button (FP_Read).set_action (boost::bind (&FaderPort::off, this), false, LongPress);
156 	get_button (FP_Write).set_action (boost::bind (&FaderPort::write, this), true);
157 	get_button (FP_Write).set_action (boost::bind (&FaderPort::off, this), false, LongPress);
158 	get_button (FP_Touch).set_action (boost::bind (&FaderPort::touch, this), true);
159 	get_button (FP_Touch).set_action (boost::bind (&FaderPort::off, this), false, LongPress);
160 	get_button (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
161 
162 	get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
163 	get_button (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
164 	/* Stop is a modifier, so we have to use its own button state to get
165 	   the default action (since StopDown will be set when looking for the
166 	   action to invoke.
167 	*/
168 	get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
169 	get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
170 
171 	/* See comments about Stop above .. */
172 	get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
173 	get_button (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
174 	get_button (Rewind).set_action (boost::bind (&BasicUI::goto_start, this, false), true, ButtonState (RewindDown|ShiftDown));
175 
176 	get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
177 	get_button (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
178 
179 	get_button (Punch).set_action (boost::bind (&FaderPort::punch, this), true);
180 
181 	get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
182 	get_button (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
183 
184 	get_button (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown);
185 	get_button (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
186 
187 	get_button (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
188 	get_button (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
189 	get_button (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true);
190 
191 	get_button (Output).set_action (boost::bind (&FaderPort::use_master, this), true);
192 	get_button (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
193 }
194 
~FaderPort()195 FaderPort::~FaderPort ()
196 {
197 	cerr << "~FP\n";
198 
199 	close ();
200 
201 	if (_input_port) {
202 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("unregistering input port %1\n", boost::shared_ptr<ARDOUR::Port>(_input_port)->name()));
203 		Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
204 		AudioEngine::instance()->unregister_port (_input_port);
205 		_input_port.reset ();
206 	}
207 
208 	if (_output_port) {
209 		_output_port->drain (10000,  250000); /* check every 10 msecs, wait up to 1/4 second for the port to drain */
210 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("unregistering output port %1\n", boost::shared_ptr<ARDOUR::Port>(_output_port)->name()));
211 		Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
212 		AudioEngine::instance()->unregister_port (_output_port);
213 		_output_port.reset ();
214 	}
215 
216 	tear_down_gui ();
217 
218 	/* stop event loop */
219 	DEBUG_TRACE (DEBUG::FaderPort, "BaseUI::quit ()\n");
220 	BaseUI::quit ();
221 }
222 
223 void*
request_factory(uint32_t num_requests)224 FaderPort::request_factory (uint32_t num_requests)
225 {
226 	/* AbstractUI<T>::request_buffer_factory() is a template method only
227 	   instantiated in this source module. To provide something visible for
228 	   use in the interface/descriptor, we have this static method that is
229 	   template-free.
230 	*/
231 	return request_buffer_factory (num_requests);
232 }
233 
234 void
start_midi_handling()235 FaderPort::start_midi_handling ()
236 {
237 	/* handle device inquiry response */
238 	_input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
239 	/* handle buttons */
240 	_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::button_handler, this, _1, _2));
241 	/* handle encoder */
242 	_input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
243 	/* handle fader */
244 	_input_port->parser()->controller.connect_same_thread (midi_connections, boost::bind (&FaderPort::fader_handler, this, _1, _2));
245 
246 	/* This connection means that whenever data is ready from the input
247 	 * port, the relevant thread will invoke our ::midi_input_handler()
248 	 * method, which will read the data, and invoke the parser.
249 	 */
250 
251 	_input_port->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &FaderPort::midi_input_handler), boost::weak_ptr<AsyncMIDIPort> (_input_port)));
252 	_input_port->xthread().attach (main_loop()->get_context());
253 }
254 
255 void
stop_midi_handling()256 FaderPort::stop_midi_handling ()
257 {
258 	midi_connections.drop_connections ();
259 
260 	/* Note: the input handler is still active at this point, but we're no
261 	 * longer connected to any of the parser signals
262 	 */
263 }
264 
265 void
do_request(FaderPortRequest * req)266 FaderPort::do_request (FaderPortRequest* req)
267 {
268 	if (req->type == CallSlot) {
269 
270 		call_slot (MISSING_INVALIDATOR, req->the_slot);
271 
272 	} else if (req->type == Quit) {
273 
274 		stop ();
275 	}
276 }
277 
278 int
stop()279 FaderPort::stop ()
280 {
281 	BaseUI::quit ();
282 
283 	return 0;
284 }
285 
286 void
thread_init()287 FaderPort::thread_init ()
288 {
289 	pthread_set_name (event_loop_name().c_str());
290 
291 	PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
292 	ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
293 
294 	set_thread_priority ();
295 }
296 
297 void
all_lights_out()298 FaderPort::all_lights_out ()
299 {
300 	for (ButtonMap::iterator b = buttons.begin(); b != buttons.end(); ++b) {
301 		b->second.set_led_state (_output_port, false);
302 	}
303 }
304 
305 FaderPort::Button&
get_button(ButtonID id) const306 FaderPort::get_button (ButtonID id) const
307 {
308 	ButtonMap::const_iterator b = buttons.find (id);
309 	assert (b != buttons.end());
310 	return const_cast<Button&>(b->second);
311 }
312 
313 bool
button_long_press_timeout(ButtonID id)314 FaderPort::button_long_press_timeout (ButtonID id)
315 {
316 	if (buttons_down.find (id) != buttons_down.end()) {
317 		if (get_button (id).invoke (ButtonState (LongPress|button_state), false)) {
318 			/* whichever button this was, we've used it ... don't invoke the
319 			   release action.
320 			*/
321 			consumed.insert (id);
322 		}
323 	} else {
324 		/* release happened and somehow we were not cancelled */
325 	}
326 
327 	return false; /* don't get called again */
328 }
329 
330 void
start_press_timeout(Button & button,ButtonID id)331 FaderPort::start_press_timeout (Button& button, ButtonID id)
332 {
333 	Glib::RefPtr<Glib::TimeoutSource> timeout = Glib::TimeoutSource::create (500); // milliseconds
334 	button.timeout_connection = timeout->connect (sigc::bind (sigc::mem_fun (*this, &FaderPort::button_long_press_timeout), id));
335 	timeout->attach (main_loop()->get_context());
336 }
337 
338 void
button_handler(MIDI::Parser &,MIDI::EventTwoBytes * tb)339 FaderPort::button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
340 {
341 	ButtonID id (ButtonID (tb->controller_number));
342 	Button& button (get_button (id));
343 
344 	DEBUG_TRACE (DEBUG::FaderPort, string_compose ("button event for ID %1 press ? %2\n", (int) tb->controller_number, (tb->value ? "yes" : "no")));
345 
346 	if (tb->value) {
347 		buttons_down.insert (id);
348 	} else {
349 		buttons_down.erase (id);
350 		button.timeout_connection.disconnect ();
351 	}
352 
353 	ButtonState bs (ButtonState (0));
354 
355 	switch (id) {
356 	case Shift:
357 		bs = ShiftDown;
358 		break;
359 	case Stop:
360 		bs = StopDown;
361 		break;
362 	case Rewind:
363 		bs = RewindDown;
364 		break;
365 	case FaderTouch:
366 		fader_is_touched = tb->value;
367 		if (_current_stripable) {
368 			boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
369 			if (gain) {
370 				samplepos_t now = session->engine().sample_time();
371 				if (tb->value) {
372 					gain->start_touch (now);
373 				} else {
374 					gain->stop_touch (now);
375 				}
376 			}
377 		}
378 		break;
379 	default:
380 		if (tb->value) {
381 			start_press_timeout (button, id);
382 		}
383 		break;
384 	}
385 
386 	if (bs) {
387 		button_state = (tb->value ? ButtonState (button_state|bs) : ButtonState (button_state&~bs));
388 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("reset button state to %1 using %2\n", button_state, (int) bs));
389 	}
390 
391 	if (button.uses_flash()) {
392 		button.set_led_state (_output_port, (int)tb->value);
393 	}
394 
395 	set<ButtonID>::iterator c = consumed.find (id);
396 
397 	if (c == consumed.end()) {
398 		(void) button.invoke (button_state, tb->value ? true : false);
399 	} else {
400 		DEBUG_TRACE (DEBUG::FaderPort, "button was consumed, ignored\n");
401 		consumed.erase (c);
402 	}
403 }
404 
405 void
encoder_handler(MIDI::Parser &,MIDI::pitchbend_t pb)406 FaderPort::encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb)
407 {
408 	int delta = 1;
409 
410 	if (pb >= 8192) {
411 		delta = -1;
412 	}
413 
414 	//knob debouncing and hysteresis.  The presonus encoder often sends bursts of events, or goes the wrong direction
415 	{
416 		last_last_encoder_delta = last_encoder_delta;
417 		last_encoder_delta = delta;
418 		microseconds_t now = get_microseconds ();
419 		if ((now - last_encoder_time) < 10*1000) { //require at least 10ms interval between changes, because the device sometimes sends multiple deltas
420 			return;
421 		}
422 		if ((now - last_encoder_time) < 100*1000) { //avoid directional changes while "spinning", 100ms window
423 			if ( (delta == last_encoder_delta) && (delta == last_last_encoder_delta) ) {
424 				last_good_encoder_delta = delta;  //3 in a row, grudgingly accept this as the new direction
425 			}
426 			if (delta != last_good_encoder_delta) {  //otherwise ensure we keep going the same way
427 				delta = last_good_encoder_delta;
428 			}
429 		} else {  //we aren't yet in a spin window, just assume this move is really what we want
430 			//NOTE:  if you are worried about where these get initialized, here it is.
431 			last_last_encoder_delta = delta;
432 			last_encoder_delta = delta;
433 		}
434 		last_encoder_time = now;
435 		last_good_encoder_delta = delta;
436 	}
437 
438 	if (_current_stripable) {
439 
440 		ButtonState trim_modifier;
441 		ButtonState width_modifier;
442 
443 		if (Profile->get_mixbus()) {
444 			trim_modifier = ShiftDown;
445 			width_modifier = ButtonState (0);
446 		} else {
447 			trim_modifier = UserDown;
448 			width_modifier = ShiftDown;
449 		}
450 
451 		if ((button_state & trim_modifier) == trim_modifier ) {    // mod+encoder = input trim
452 			boost::shared_ptr<AutomationControl> trim = _current_stripable->trim_control ();
453 			if (trim) {
454 				float val = accurate_coefficient_to_dB (trim->get_value());
455 				val += delta * .5f; // use 1/2 dB Steps -20..+20
456 				trim->set_value (dB_to_coefficient (val), Controllable::UseGroup);
457 			}
458 		} else if (width_modifier && ((button_state & width_modifier) == width_modifier)) {
459 			pan_width (delta);
460 
461 		} else {  // pan/balance
462 			pan_azimuth (delta);
463 		}
464 	}
465 }
466 
467 void
fader_handler(MIDI::Parser &,MIDI::EventTwoBytes * tb)468 FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
469 {
470 	bool was_fader = false;
471 
472 	if (tb->controller_number == 0x0) {
473 		fader_msb = tb->value;
474 		was_fader = true;
475 	} else if (tb->controller_number == 0x20) {
476 		fader_lsb = tb->value;
477 		was_fader = true;
478 	}
479 
480 	if (was_fader) {
481 		if (_current_stripable) {
482 			boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
483 			if (gain) {
484 				int ival = (fader_msb << 7) | fader_lsb;
485 				float val = gain->interface_to_internal (ival/16383.0);
486 				/* even though the faderport only controls a
487 				   single stripable at a time, allow the fader to
488 				   modify the group, if appropriate.
489 				*/
490 				_current_stripable->gain_control()->set_value (val, Controllable::UseGroup);
491 			}
492 		}
493 	}
494 }
495 
496 void
sysex_handler(MIDI::Parser & p,MIDI::byte * buf,size_t sz)497 FaderPort::sysex_handler (MIDI::Parser &p, MIDI::byte *buf, size_t sz)
498 {
499         DEBUG_TRACE (DEBUG::FaderPort, string_compose ("sysex message received, size = %1\n", sz));
500 
501 	if (sz < 17) {
502 		return;
503 	}
504 
505 	if (buf[2] != 0x7f ||
506 	    buf[3] != 0x06 ||
507 	    buf[4] != 0x02 ||
508 	    buf[5] != 0x0 ||
509 	    buf[6] != 0x1 ||
510 	    buf[7] != 0x06 ||
511 	    buf[8] != 0x02 ||
512 	    buf[9] != 0x0 ||
513 	    buf[10] != 0x01 ||
514 	    buf[11] != 0x0) {
515 		return;
516 	}
517 
518 	_device_active = true;
519 
520 	DEBUG_TRACE (DEBUG::FaderPort, "FaderPort identified via MIDI Device Inquiry response\n");
521 
522 	/* put it into native mode */
523 
524 	MIDI::byte native[3];
525 	native[0] = 0x91;
526 	native[1] = 0x00;
527 	native[2] = 0x64;
528 
529 	_output_port->write (native, 3, 0);
530 
531 	all_lights_out ();
532 
533 	/* catch up on state */
534 
535 	/* make sure that rec_enable_state is consistent with current device state */
536 	get_button (RecEnable).set_led_state (_output_port, rec_enable_state);
537 
538 	map_transport_state ();
539 	map_recenable_state ();
540 }
541 
542 int
set_active(bool yn)543 FaderPort::set_active (bool yn)
544 {
545 	DEBUG_TRACE (DEBUG::FaderPort, string_compose("Faderport::set_active init with yn: '%1'\n", yn));
546 
547 	if (yn == active()) {
548 		return 0;
549 	}
550 
551 	if (yn) {
552 
553 		/* start event loop */
554 
555 		BaseUI::run ();
556 
557 		connect_session_signals ();
558 
559 		Glib::RefPtr<Glib::TimeoutSource> blink_timeout = Glib::TimeoutSource::create (200); // milliseconds
560 		blink_connection = blink_timeout->connect (sigc::mem_fun (*this, &FaderPort::blink));
561 		blink_timeout->attach (main_loop()->get_context());
562 
563 		Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds
564 		periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &FaderPort::periodic));
565 		periodic_timeout->attach (main_loop()->get_context());
566 
567 	} else {
568 
569 		BaseUI::quit ();
570 		close ();
571 
572 	}
573 
574 	ControlProtocol::set_active (yn);
575 
576 	DEBUG_TRACE (DEBUG::FaderPort, string_compose("Faderport::set_active done with yn: '%1'\n", yn));
577 
578 	return 0;
579 }
580 
581 bool
periodic()582 FaderPort::periodic ()
583 {
584 	if (!_current_stripable) {
585 		return true;
586 	}
587 
588 	ARDOUR::AutoState gain_state = _current_stripable->gain_control()->automation_state();
589 
590 	if (gain_state == ARDOUR::Touch || gain_state == ARDOUR::Play) {
591 		map_gain ();
592 	}
593 
594 	return true;
595 }
596 
597 void
stop_blinking(ButtonID id)598 FaderPort::stop_blinking (ButtonID id)
599 {
600 	blinkers.remove (id);
601 	get_button (id).set_led_state (_output_port, false);
602 }
603 
604 void
start_blinking(ButtonID id)605 FaderPort::start_blinking (ButtonID id)
606 {
607 	blinkers.push_back (id);
608 	get_button (id).set_led_state (_output_port, true);
609 }
610 
611 bool
blink()612 FaderPort::blink ()
613 {
614 	blink_state = !blink_state;
615 
616 	for (Blinkers::iterator b = blinkers.begin(); b != blinkers.end(); b++) {
617 		get_button(*b).set_led_state (_output_port, blink_state);
618 	}
619 
620 	map_recenable_state ();
621 
622 	return true;
623 }
624 
625 void
close()626 FaderPort::close ()
627 {
628 	all_lights_out ();
629 
630 	stop_midi_handling ();
631 	session_connections.drop_connections ();
632 	_port_connection.disconnect ();
633 	blink_connection.disconnect ();
634 	selection_connection.disconnect ();
635 	stripable_connections.drop_connections ();
636 	periodic_connection.disconnect ();
637 
638 #if 0
639 	stripable_connections.drop_connections ();
640 #endif
641 }
642 
643 void
map_recenable_state()644 FaderPort::map_recenable_state ()
645 {
646 	/* special case for RecEnable because its status can change as a
647 	 * confluence of unrelated parameters: (a) session rec-enable state (b)
648 	 * rec-enabled tracks. So we don't add the button to the blinkers list,
649 	 * we just call this:
650 	 *
651 	 *  * from the blink callback
652 	 *  * when the session tells us about a status change
653 	 *
654 	 * We do the last one so that the button changes state promptly rather
655 	 * than waiting for the next blink callback. The change in "blinking"
656 	 * based on having record-enabled tracks isn't urgent, and that happens
657 	 * during the blink callback.
658 	 */
659 
660 	bool onoff;
661 
662 	switch (session->record_status()) {
663 	case Session::Disabled:
664 		onoff = false;
665 		break;
666 	case Session::Enabled:
667 		onoff = blink_state;
668 		break;
669 	case Session::Recording:
670 		if (session->have_rec_enabled_track ()) {
671 			onoff = true;
672 		} else {
673 			onoff = blink_state;
674 		}
675 		break;
676 	}
677 
678 	if (onoff != rec_enable_state) {
679 		get_button(RecEnable).set_led_state (_output_port, onoff);
680 		rec_enable_state = onoff;
681 	}
682 }
683 
684 void
map_transport_state()685 FaderPort::map_transport_state ()
686 {
687 	get_button (Loop).set_led_state (_output_port, session->get_play_loop());
688 
689 	float ts = get_transport_speed();
690 
691 	if (ts == 0) {
692 		stop_blinking (Play);
693 	} else if (fabs (ts) == 1.0) {
694 		stop_blinking (Play);
695 		get_button (Play).set_led_state (_output_port, true);
696 	} else {
697 		start_blinking (Play);
698 	}
699 
700 	get_button (Stop).set_led_state (_output_port, stop_button_onoff());
701 	get_button (Rewind).set_led_state (_output_port, rewind_button_onoff ());
702 	get_button (Ffwd).set_led_state (_output_port, ffwd_button_onoff());
703 }
704 
705 void
parameter_changed(string what)706 FaderPort::parameter_changed (string what)
707 {
708 	if (what == "punch-in" || what == "punch-out") {
709 		bool in = session->config.get_punch_in ();
710 		bool out = session->config.get_punch_out ();
711 		if (in && out) {
712 			get_button (Punch).set_led_state (_output_port, true);
713 			blinkers.remove (Punch);
714 		} else if (in || out) {
715 			start_blinking (Punch);
716 		} else {
717 			stop_blinking (Punch);
718 		}
719 	}
720 }
721 
722 void
connect_session_signals()723 FaderPort::connect_session_signals()
724 {
725 	session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable_state, this), this);
726 	session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_transport_state, this), this);
727 	/* not session, but treat it similarly */
728 	session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::parameter_changed, this, _1), this);
729 }
730 
731 bool
midi_input_handler(Glib::IOCondition ioc,boost::weak_ptr<ARDOUR::AsyncMIDIPort> wport)732 FaderPort::midi_input_handler (Glib::IOCondition ioc, boost::weak_ptr<ARDOUR::AsyncMIDIPort> wport)
733 {
734 	boost::shared_ptr<AsyncMIDIPort> port (wport.lock());
735 
736 	if (!port) {
737 		return false;
738 	}
739 
740 	DEBUG_TRACE (DEBUG::FaderPort, string_compose ("something happend on  %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
741 
742 	if (ioc & ~IO_IN) {
743 		return false;
744 	}
745 
746 	if (ioc & IO_IN) {
747 
748 		port->clear ();
749 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("data available on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
750 		samplepos_t now = session->engine().sample_time();
751 		port->parse (now);
752 	}
753 
754 	return true;
755 }
756 
757 
758 XMLNode&
get_state()759 FaderPort::get_state ()
760 {
761 	XMLNode& node (ControlProtocol::get_state());
762 
763 	XMLNode* child;
764 
765 	child = new XMLNode (X_("Input"));
766 	child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_input_port)->get_state());
767 	node.add_child_nocopy (*child);
768 
769 
770 	child = new XMLNode (X_("Output"));
771 	child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
772 	node.add_child_nocopy (*child);
773 
774 	/* Save action state for Mix, Proj, Trns and User buttons, since these
775 	 * are user controlled. We can only save named-action operations, since
776 	 * internal functions are just pointers to functions and hard to
777 	 * serialize without enumerating them all somewhere.
778 	 */
779 
780 	node.add_child_nocopy (get_button (Mix).get_state());
781 	node.add_child_nocopy (get_button (Proj).get_state());
782 	node.add_child_nocopy (get_button (Trns).get_state());
783 	node.add_child_nocopy (get_button (User).get_state());
784 	node.add_child_nocopy (get_button (Footswitch).get_state());
785 
786 	return node;
787 }
788 
789 int
set_state(const XMLNode & node,int version)790 FaderPort::set_state (const XMLNode& node, int version)
791 {
792 	XMLNodeList nlist;
793 	XMLNode const* child;
794 
795 	if (ControlProtocol::set_state (node, version)) {
796 		return -1;
797 	}
798 
799 	if ((child = node.child (X_("Input"))) != 0) {
800 		XMLNode* portnode = child->child (Port::state_node_name.c_str());
801 		if (portnode) {
802 			portnode->remove_property ("name");
803 			boost::shared_ptr<ARDOUR::Port>(_input_port)->set_state (*portnode, version);
804 		}
805 	}
806 
807 	if ((child = node.child (X_("Output"))) != 0) {
808 		XMLNode* portnode = child->child (Port::state_node_name.c_str());
809 		if (portnode) {
810 			portnode->remove_property ("name");
811 			boost::shared_ptr<ARDOUR::Port>(_output_port)->set_state (*portnode, version);
812 		}
813 	}
814 
815 	for (XMLNodeList::const_iterator n = node.children().begin(); n != node.children().end(); ++n) {
816 		if ((*n)->name() == X_("Button")) {
817 			int32_t xid;
818 			if (!(*n)->get_property (X_("id"), xid)) {
819 				continue;
820 			}
821 			ButtonMap::iterator b = buttons.find (ButtonID (xid));
822 			if (b == buttons.end()) {
823 				continue;
824 			}
825 			b->second.set_state (**n);
826 		}
827 	}
828 
829 	return 0;
830 }
831 
832 bool
connection_handler(boost::weak_ptr<ARDOUR::Port>,std::string name1,boost::weak_ptr<ARDOUR::Port>,std::string name2,bool yn)833 FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
834 {
835 	DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler  start\n");
836 	if (!_input_port || !_output_port) {
837 		return false;
838 	}
839 
840 	string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
841 	string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
842 
843 	if (ni == name1 || ni == name2) {
844 		if (yn) {
845 			connection_state |= InputConnected;
846 		} else {
847 			connection_state &= ~InputConnected;
848 		}
849 	} else if (no == name1 || no == name2) {
850 		if (yn) {
851 			connection_state |= OutputConnected;
852 		} else {
853 			connection_state &= ~OutputConnected;
854 		}
855 	} else {
856 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("Connections between %1 and %2 changed, but I ignored it\n", name1, name2));
857 		/* not our ports */
858 		return false;
859 	}
860 
861 	if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
862 
863 		/* XXX this is a horrible hack. Without a short sleep here,
864 		   something prevents the device wakeup messages from being
865 		   sent and/or the responses from being received.
866 		*/
867 
868 		g_usleep (100000);
869                 DEBUG_TRACE (DEBUG::FaderPort, "device now connected for both input and output\n");
870 		connected ();
871 
872 	} else {
873 		DEBUG_TRACE (DEBUG::FaderPort, "Device disconnected (input or output or both) or not yet fully connected\n");
874 		_device_active = false;
875 	}
876 
877 	ConnectionChange (); /* emit signal for our GUI */
878 
879 	DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler  end\n");
880 
881 	return true; /* connection status changed */
882 }
883 
884 void
connected()885 FaderPort::connected ()
886 {
887 	DEBUG_TRACE (DEBUG::FaderPort, "sending device inquiry message...\n");
888 
889 	start_midi_handling ();
890 
891 	/* send device inquiry */
892 
893 	MIDI::byte buf[6];
894 
895 	buf[0] = 0xf0;
896 	buf[1] = 0x7e;
897 	buf[2] = 0x7f;
898 	buf[3] = 0x06;
899 	buf[4] = 0x01;
900 	buf[5] = 0xf7;
901 
902 	_output_port->write (buf, 6, 0);
903 }
904 
905 bool
invoke(FaderPort::ButtonState bs,bool press)906 FaderPort::Button::invoke (FaderPort::ButtonState bs, bool press)
907 {
908 	DEBUG_TRACE (DEBUG::FaderPort, string_compose ("invoke button %1 for %2 state %3%4%5\n", id, (press ? "press":"release"), hex, bs, dec));
909 
910 	ToDoMap::iterator x;
911 
912 	if (press) {
913 		if ((x = on_press.find (bs)) == on_press.end()) {
914 			DEBUG_TRACE (DEBUG::FaderPort, string_compose ("no press action for button %1 state %2 @ %3 in %4\n", id, bs, this, &on_press));
915 			return false;
916 		}
917 	} else {
918 		if ((x = on_release.find (bs)) == on_release.end()) {
919 			DEBUG_TRACE (DEBUG::FaderPort, string_compose ("no release action for button %1 state %2 @%3 in %4\n", id, bs, this, &on_release));
920 			return false;
921 		}
922 	}
923 
924 	switch (x->second.type) {
925 	case NamedAction:
926 		if (!x->second.action_name.empty()) {
927 			fp.access_action (x->second.action_name);
928 			return true;
929 		}
930 		break;
931 	case InternalFunction:
932 		if (x->second.function) {
933 			x->second.function ();
934 			return true;
935 		}
936 	}
937 
938 	return false;
939 }
940 
941 void
set_action(string const & name,bool when_pressed,FaderPort::ButtonState bs)942 FaderPort::Button::set_action (string const& name, bool when_pressed, FaderPort::ButtonState bs)
943 {
944 	ToDo todo;
945 
946 	todo.type = NamedAction;
947 
948 	if (when_pressed) {
949 		if (name.empty()) {
950 			on_press.erase (bs);
951 		} else {
952 			DEBUG_TRACE (DEBUG::FaderPort, string_compose ("set button %1 to action %2 on press + %3\n", id, name, bs));
953 			todo.action_name = name;
954 			on_press[bs] = todo;
955 		}
956 	} else {
957 		if (name.empty()) {
958 			on_release.erase (bs);
959 		} else {
960 			DEBUG_TRACE (DEBUG::FaderPort, string_compose ("set button %1 to action %2 on release + %3\n", id, name, bs));
961 			todo.action_name = name;
962 			on_release[bs] = todo;
963 		}
964 	}
965 }
966 
967 string
get_action(bool press,FaderPort::ButtonState bs)968 FaderPort::Button::get_action (bool press, FaderPort::ButtonState bs)
969 {
970 	ToDoMap::iterator x;
971 
972 	if (press) {
973 		if ((x = on_press.find (bs)) == on_press.end()) {
974 			return string();
975 		}
976 		if (x->second.type != NamedAction) {
977 			return string ();
978 		}
979 		return x->second.action_name;
980 	} else {
981 		if ((x = on_release.find (bs)) == on_release.end()) {
982 			return string();
983 		}
984 		if (x->second.type != NamedAction) {
985 			return string ();
986 		}
987 		return x->second.action_name;
988 	}
989 }
990 
991 void
set_action(boost::function<void ()> f,bool when_pressed,FaderPort::ButtonState bs)992 FaderPort::Button::set_action (boost::function<void()> f, bool when_pressed, FaderPort::ButtonState bs)
993 {
994 	ToDo todo;
995 	todo.type = InternalFunction;
996 
997 	if (when_pressed) {
998 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("set button %1 (%2) @ %5 to some functor on press + %3 in %4\n", id, name, bs, &on_press, this));
999 		todo.function = f;
1000 		on_press[bs] = todo;
1001 	} else {
1002 		DEBUG_TRACE (DEBUG::FaderPort, string_compose ("set button %1 (%2) @ %5 to some functor on release + %3\n", id, name, bs, this));
1003 		todo.function = f;
1004 		on_release[bs] = todo;
1005 	}
1006 }
1007 
1008 void
set_led_state(boost::shared_ptr<MIDI::Port> port,bool onoff)1009 FaderPort::Button::set_led_state (boost::shared_ptr<MIDI::Port> port, bool onoff)
1010 {
1011 	if (out < 0) {
1012 		/* fader button ID - no LED */
1013 		return;
1014 	}
1015 
1016 	MIDI::byte buf[3];
1017 	buf[0] = 0xa0;
1018 	buf[1] = out;
1019 	buf[2] = onoff ? 1 : 0;
1020 	port->write (buf, 3, 0);
1021 }
1022 
1023 int
set_state(XMLNode const & node)1024 FaderPort::Button::set_state (XMLNode const& node)
1025 {
1026 	int32_t xid;
1027 	if (!node.get_property ("id", xid) || xid != id) {
1028 		return -1;
1029 	}
1030 
1031 	typedef pair<string,FaderPort::ButtonState> state_pair_t;
1032 	vector<state_pair_t> state_pairs;
1033 
1034 	state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
1035 	state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
1036 	state_pairs.push_back (make_pair (string ("long"), LongPress));
1037 
1038 	for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
1039 
1040 		string propname = sp->first + X_("-press");
1041 		string value;
1042 		if (node.get_property (propname.c_str(), value)) {
1043 			set_action (value, true, sp->second);
1044 		}
1045 
1046 		propname = sp->first + X_("-release");
1047 		if (node.get_property (propname.c_str(), value)) {
1048 			set_action (value, false, sp->second);
1049 		}
1050 	}
1051 
1052 	return 0;
1053 }
1054 
1055 XMLNode&
get_state() const1056 FaderPort::Button::get_state () const
1057 {
1058 	XMLNode* node = new XMLNode (X_("Button"));
1059 
1060 	node->set_property (X_("id"), to_string<int32_t>(id));
1061 
1062 	ToDoMap::const_iterator x;
1063 	ToDo null;
1064 	null.type = NamedAction;
1065 
1066 	typedef pair<string,FaderPort::ButtonState> state_pair_t;
1067 	vector<state_pair_t> state_pairs;
1068 
1069 	state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
1070 	state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
1071 	state_pairs.push_back (make_pair (string ("long"), LongPress));
1072 
1073 	for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
1074 		if ((x = on_press.find (sp->second)) != on_press.end()) {
1075 			if (x->second.type == NamedAction) {
1076 				node->set_property (string (sp->first + X_("-press")).c_str(), x->second.action_name);
1077 			}
1078 		}
1079 
1080 		if ((x = on_release.find (sp->second)) != on_release.end()) {
1081 			if (x->second.type == NamedAction) {
1082 				node->set_property (string (sp->first + X_("-release")).c_str(), x->second.action_name);
1083 			}
1084 		}
1085 	}
1086 
1087 	return *node;
1088 }
1089 
1090 void
stripable_selection_changed()1091 FaderPort::stripable_selection_changed ()
1092 {
1093 	set_current_stripable (ControlProtocol::first_selected_stripable());
1094 }
1095 
1096 void
drop_current_stripable()1097 FaderPort::drop_current_stripable ()
1098 {
1099 	if (_current_stripable) {
1100 		if (_current_stripable == session->monitor_out()) {
1101 			set_current_stripable (session->master_out());
1102 		} else {
1103 			set_current_stripable (boost::shared_ptr<Stripable>());
1104 		}
1105 	}
1106 }
1107 
1108 void
set_current_stripable(boost::shared_ptr<Stripable> r)1109 FaderPort::set_current_stripable (boost::shared_ptr<Stripable> r)
1110 {
1111 	stripable_connections.drop_connections ();
1112 
1113 	_current_stripable = r;
1114 
1115 	/* turn this off. It will be turned on back on in use_master() or
1116 	   use_monitor() as appropriate.
1117 	*/
1118 	get_button(Output).set_led_state (_output_port, false);
1119 
1120 	if (_current_stripable) {
1121 		_current_stripable->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::drop_current_stripable, this), this);
1122 
1123 		_current_stripable->mute_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_mute, this), this);
1124 		_current_stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_solo, this), this);
1125 
1126 		boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_stripable);
1127 		if (t) {
1128 			t->rec_enable_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable, this), this);
1129 		}
1130 
1131 		boost::shared_ptr<AutomationControl> control = _current_stripable->gain_control ();
1132 		if (control) {
1133 			control->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_gain, this), this);
1134 			control->alist()->automation_state_changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_auto, this), this);
1135 		}
1136 
1137 		boost::shared_ptr<MonitorProcessor> mp = _current_stripable->monitor_control();
1138 		if (mp) {
1139 			mp->cut_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_cut, this), this);
1140 		}
1141 	}
1142 
1143 	//ToDo: subscribe to the fader automation modes so we can light the LEDs
1144 
1145 	map_stripable_state ();
1146 }
1147 
1148 void
map_auto()1149 FaderPort::map_auto ()
1150 {
1151 	/* Under no circumstances send a message to "enable" the LED state of
1152 	 * the Off button, because this will disable the fader.
1153 	 */
1154 
1155 	boost::shared_ptr<AutomationControl> control = _current_stripable->gain_control ();
1156 	const AutoState as = control->automation_state ();
1157 
1158 	switch (as) {
1159 		case ARDOUR::Play:
1160 			get_button (FP_Read).set_led_state (_output_port, true);
1161 			get_button (FP_Write).set_led_state (_output_port, false);
1162 			get_button (FP_Touch).set_led_state (_output_port, false);
1163 		break;
1164 		case ARDOUR::Write:
1165 			get_button (FP_Read).set_led_state (_output_port, false);
1166 			get_button (FP_Write).set_led_state (_output_port, true);
1167 			get_button (FP_Touch).set_led_state (_output_port, false);
1168 		break;
1169 		case ARDOUR::Touch:
1170 		case ARDOUR::Latch: // XXX
1171 			get_button (FP_Read).set_led_state (_output_port, false);
1172 			get_button (FP_Write).set_led_state (_output_port, false);
1173 			get_button (FP_Touch).set_led_state (_output_port, true);
1174 		break;
1175 		case ARDOUR::Off:
1176 			get_button (FP_Read).set_led_state (_output_port, false);
1177 			get_button (FP_Write).set_led_state (_output_port, false);
1178 			get_button (FP_Touch).set_led_state (_output_port, false);
1179 		break;
1180 	}
1181 
1182 }
1183 
1184 
1185 void
map_cut()1186 FaderPort::map_cut ()
1187 {
1188 	boost::shared_ptr<MonitorProcessor> mp = _current_stripable->monitor_control();
1189 
1190 	if (mp) {
1191 		bool yn = mp->cut_all ();
1192 		if (yn) {
1193 			start_blinking (Mute);
1194 		} else {
1195 			stop_blinking (Mute);
1196 		}
1197 	} else {
1198 		stop_blinking (Mute);
1199 	}
1200 }
1201 
1202 void
map_mute()1203 FaderPort::map_mute ()
1204 {
1205 	if (_current_stripable) {
1206 		if (_current_stripable->mute_control()->muted()) {
1207 			stop_blinking (Mute);
1208 			get_button (Mute).set_led_state (_output_port, true);
1209 		} else if (_current_stripable->mute_control()->muted_by_others_soloing () || _current_stripable->mute_control()->muted_by_masters()) {
1210 			start_blinking (Mute);
1211 		} else {
1212 			stop_blinking (Mute);
1213 		}
1214 	} else {
1215 		stop_blinking (Mute);
1216 	}
1217 }
1218 
1219 void
map_solo()1220 FaderPort::map_solo ()
1221 {
1222 	if (_current_stripable) {
1223 		get_button (Solo).set_led_state (_output_port, _current_stripable->solo_control()->soloed());
1224 	} else {
1225 		get_button (Solo).set_led_state (_output_port, false);
1226 	}
1227 }
1228 
1229 void
map_recenable()1230 FaderPort::map_recenable ()
1231 {
1232 	boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_stripable);
1233 	if (t) {
1234 		get_button (Rec).set_led_state (_output_port, t->rec_enable_control()->get_value());
1235 	} else {
1236 		get_button (Rec).set_led_state (_output_port, false);
1237 	}
1238 }
1239 
1240 void
map_gain()1241 FaderPort::map_gain ()
1242 {
1243 	if (fader_is_touched) {
1244 		/* Do not send fader moves while the user is touching the fader */
1245 		return;
1246 	}
1247 
1248 	if (!_current_stripable) {
1249 		return;
1250 	}
1251 
1252 	boost::shared_ptr<AutomationControl> control = _current_stripable->gain_control ();
1253 	double val;
1254 
1255 	if (!control) {
1256 		val = 0.0;
1257 	} else {
1258 		val = control->internal_to_interface (control->get_value ());
1259 	}
1260 
1261 	/* Faderport sends fader position with range 0..16384 (though some of
1262 	 * the least-significant bits at the top end are missing - it may only
1263 	 * get to 1636X or so).
1264 	 *
1265 	 * But ... position must be sent in the range 0..1023.
1266 	 *
1267 	 * Thanks, Obama.
1268 	 */
1269 
1270 	int ival = (int) lrintf (val * 1023.0);
1271 
1272 	/* MIDI normalization requires that we send two separate messages here,
1273 	 * not one single 6 byte one.
1274 	 */
1275 
1276 	MIDI::byte buf[3];
1277 
1278 	buf[0] = 0xb0;
1279 	buf[1] = 0x0;
1280 	buf[2] = ival >> 7;
1281 
1282 	_output_port->write (buf, 3, 0);
1283 
1284 	buf[1] = 0x20;
1285 	buf[2] = ival & 0x7f;
1286 
1287 	_output_port->write (buf, 3, 0);
1288 }
1289 
1290 void
map_stripable_state()1291 FaderPort::map_stripable_state ()
1292 {
1293 	if (!_current_stripable) {
1294 		stop_blinking (Mute);
1295 		stop_blinking (Solo);
1296 		get_button (Rec).set_led_state (_output_port, false);
1297 	} else {
1298 		map_solo ();
1299 		map_recenable ();
1300 		map_gain ();
1301 		map_auto ();
1302 
1303 		if (_current_stripable == session->monitor_out()) {
1304 			map_cut ();
1305 		} else {
1306 			map_mute ();
1307 		}
1308 	}
1309 }
1310 
1311 list<boost::shared_ptr<ARDOUR::Bundle> >
bundles()1312 FaderPort::bundles ()
1313 {
1314 	list<boost::shared_ptr<ARDOUR::Bundle> > b;
1315 
1316 	if (_input_bundle) {
1317 		b.push_back (_input_bundle);
1318 		b.push_back (_output_bundle);
1319 	}
1320 
1321 	return b;
1322 }
1323 
1324 boost::shared_ptr<Port>
output_port()1325 FaderPort::output_port()
1326 {
1327 	return _output_port;
1328 }
1329 
1330 boost::shared_ptr<Port>
input_port()1331 FaderPort::input_port()
1332 {
1333 	return _input_port;
1334 }
1335 
1336 void
set_action(ButtonID id,std::string const & action_name,bool on_press,ButtonState bs)1337 FaderPort::set_action (ButtonID id, std::string const& action_name, bool on_press, ButtonState bs)
1338 {
1339 	get_button(id).set_action (action_name, on_press, bs);
1340 }
1341 
1342 string
get_action(ButtonID id,bool press,ButtonState bs)1343 FaderPort::get_action (ButtonID id, bool press, ButtonState bs)
1344 {
1345 	return get_button(id).get_action (press, bs);
1346 }
1347