b10868aeede66b2ae0d5d14ca446c51f442090a8
[ardour.git] / libs / surfaces / faderport8 / faderport8.cc
1 /*
2  * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2015 Paul Davis
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include <cstdlib>
21 #include <sstream>
22 #include <algorithm>
23
24 #include <stdint.h>
25
26 #include "pbd/error.h"
27 #include "pbd/failed_constructor.h"
28 #include "pbd/pthread_utils.h"
29 #include "pbd/compose.h"
30 #include "pbd/xml++.h"
31
32 #include "midi++/port.h"
33
34 #include "ardour/audioengine.h"
35 #include "ardour/audio_track.h"
36 #include "ardour/bundle.h"
37 #include "ardour/debug.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/midiport_manager.h"
40 #include "ardour/panner_shell.h"
41 #include "ardour/plugin.h"
42 #include "ardour/plugin_insert.h"
43 #include "ardour/processor.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/route.h"
46 #include "ardour/session.h"
47 #include "ardour/session_configuration.h"
48 #include "ardour/tempo.h"
49 #include "ardour/vca.h"
50
51 #include "faderport8.h"
52
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Glib;
56 using namespace std;
57 using namespace ArdourSurface::FP_NAMESPACE;
58 using namespace ArdourSurface::FP_NAMESPACE::FP8Types;
59
60 #include "pbd/i18n.h"
61
62 #include "pbd/abstract_ui.cc" // instantiate template
63
64 #ifndef NDEBUG
65 //#define VERBOSE_DEBUG
66 #endif
67
68 static void
69 debug_2byte_msg (std::string const& msg, int b0, int b1)
70 {
71 #ifndef NDEBUG
72         if (DEBUG_ENABLED(DEBUG::FaderPort8)) {
73                 DEBUG_STR_DECL(a);
74                 DEBUG_STR_APPEND(a, "RECV: ");
75                 DEBUG_STR_APPEND(a, msg);
76                 DEBUG_STR_APPEND(a,' ');
77                 DEBUG_STR_APPEND(a,hex);
78                 DEBUG_STR_APPEND(a,"0x");
79                 DEBUG_STR_APPEND(a, b0);
80                 DEBUG_STR_APPEND(a,' ');
81                 DEBUG_STR_APPEND(a,"0x");
82                 DEBUG_STR_APPEND(a, b1);
83                 DEBUG_STR_APPEND(a,'\n');
84                 DEBUG_TRACE (DEBUG::FaderPort8, DEBUG_STR(a).str());
85         }
86 #endif
87 }
88
89 FaderPort8::FaderPort8 (Session& s)
90 #ifdef FADERPORT16
91         : ControlProtocol (s, _("PreSonus FaderPort16"))
92 #else
93         : ControlProtocol (s, _("PreSonus FaderPort8"))
94 #endif
95         , AbstractUI<FaderPort8Request> (name())
96         , _connection_state (ConnectionState (0))
97         , _device_active (false)
98         , _ctrls (*this)
99         , _plugin_off (0)
100         , _parameter_off (0)
101         , _show_presets (false)
102         , _showing_well_known (0)
103         , _timer_divider (0)
104         , _blink_onoff (false)
105         , _shift_lock (false)
106         , _shift_pressed (0)
107         , gui (0)
108         , _link_enabled (false)
109         , _link_locked (false)
110         , _clock_mode (1)
111         , _scribble_mode (2)
112         , _two_line_text (false)
113         , _auto_pluginui (true)
114 {
115         boost::shared_ptr<ARDOUR::Port> inp;
116         boost::shared_ptr<ARDOUR::Port> outp;
117
118 #ifdef FADERPORT16
119         inp  = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort16 Recv", true);
120         outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort16 Send", true);
121 #else
122         inp  = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort8 Recv", true);
123         outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort8 Send", true);
124 #endif
125         _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(inp);
126         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(outp);
127
128         if (_input_port == 0 || _output_port == 0) {
129                 throw failed_constructor();
130         }
131
132 #ifdef FADERPORT16
133         _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Receive)"), true));
134         _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Send) "), false));
135 #else
136         _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Receive)"), true));
137         _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Send) "), false));
138 #endif
139
140         _input_bundle->add_channel (
141                 inp->name(),
142                 ARDOUR::DataType::MIDI,
143                 session->engine().make_port_name_non_relative (inp->name())
144                 );
145
146         _output_bundle->add_channel (
147                 outp->name(),
148                 ARDOUR::DataType::MIDI,
149                 session->engine().make_port_name_non_relative (outp->name())
150                 );
151
152         ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::connection_handler, this, _2, _4), this);
153         ARDOUR::AudioEngine::instance()->Stopped.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this);
154         ARDOUR::Port::PortDrop.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this);
155
156         /* bind button events to call libardour actions */
157         setup_actions ();
158
159         _ctrls.FaderModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::notify_fader_mode_changed, this));
160         _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this));
161 }
162
163 FaderPort8::~FaderPort8 ()
164 {
165         /* this will be called from the main UI thread. during Session::destroy().
166          * There can be concurrent activity from BaseUI::main_thread -> AsyncMIDIPort
167          * -> MIDI::Parser::signal -> ... to any of the midi_connections
168          *
169          * stop event loop early and join thread */
170         stop ();
171
172         if (_input_port) {
173                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering input port %1\n", boost::shared_ptr<ARDOUR::Port>(_input_port)->name()));
174                 Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
175                 AudioEngine::instance()->unregister_port (_input_port);
176                 _input_port.reset ();
177         }
178
179         disconnected (); // zero faders, turn lights off, clear strips
180
181         if (_output_port) {
182                 _output_port->drain (10000,  250000); /* check every 10 msecs, wait up to 1/4 second for the port to drain */
183                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering output port %1\n", boost::shared_ptr<ARDOUR::Port>(_output_port)->name()));
184                 Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
185                 AudioEngine::instance()->unregister_port (_output_port);
186                 _output_port.reset ();
187         }
188
189         tear_down_gui ();
190 }
191
192 /* ****************************************************************************
193  * Event Loop
194  */
195
196 void*
197 FaderPort8::request_factory (uint32_t num_requests)
198 {
199         /* AbstractUI<T>::request_buffer_factory() is a template method only
200          * instantiated in this source module. To provide something visible for
201          * use in the interface/descriptor, we have this static method that is
202          * template-free.
203          */
204         return request_buffer_factory (num_requests);
205 }
206
207 void
208 FaderPort8::do_request (FaderPort8Request* req)
209 {
210         if (req->type == CallSlot) {
211                 call_slot (MISSING_INVALIDATOR, req->the_slot);
212         } else if (req->type == Quit) {
213                 stop ();
214                 disconnected ();
215         }
216 }
217
218 void
219 FaderPort8::stop ()
220 {
221         DEBUG_TRACE (DEBUG::FaderPort8, "BaseUI::quit ()\n");
222         BaseUI::quit ();
223         close (); // drop references, disconnect from session signals
224 }
225
226 void
227 FaderPort8::thread_init ()
228 {
229         pthread_set_name (event_loop_name().c_str());
230
231         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
232         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
233
234         set_thread_priority ();
235 }
236
237 bool
238 FaderPort8::periodic ()
239 {
240         /* prepare TC display -- handled by stripable Periodic ()
241          * in FP8Strip::periodic_update_timecode
242          */
243         if (_ctrls.display_timecode () && clock_mode ()) {
244                 Timecode::Time TC;
245                 session->timecode_time (TC);
246                 _timecode = Timecode::timecode_format_time(TC);
247
248                 char buf[16];
249                 Timecode::BBT_Time BBT = session->tempo_map ().bbt_at_sample (session->transport_sample ());
250                 snprintf (buf, sizeof (buf),
251                                 " %02" PRIu32 "|%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32,
252                                 BBT.bars % 100, BBT.beats %100,
253                                 (BBT.ticks/ 100) %100, BBT.ticks %100);
254                 _musical_time = std::string (buf);
255         } else {
256                 _timecode.clear ();
257                 _musical_time.clear ();
258         }
259
260 #ifdef FADERPORT16
261         /* every second, send "running" */
262         if (++_timer_divider == 10) {
263                 _timer_divider = 0;
264                 tx_midi3 (0xa0, 0x00, 0x00);
265         }
266 #endif
267
268         /* update stripables */
269         Periodic ();
270         return true;
271 }
272
273 bool
274 FaderPort8::blink_it ()
275 {
276         _blink_onoff = !_blink_onoff;
277         BlinkIt (_blink_onoff);
278         return true;
279 }
280
281 /* ****************************************************************************
282  * Port and Signal Connection Management
283  */
284 int
285 FaderPort8::set_active (bool yn)
286 {
287         DEBUG_TRACE (DEBUG::FaderPort8, string_compose("set_active init with yn: '%1'\n", yn));
288
289         if (yn == active()) {
290                 return 0;
291         }
292
293         if (yn) {
294                 /* start event loop */
295                 BaseUI::run ();
296                 connect_session_signals ();
297         } else {
298                 stop ();
299         }
300
301         ControlProtocol::set_active (yn);
302         DEBUG_TRACE (DEBUG::FaderPort8, string_compose("set_active done with yn: '%1'\n", yn));
303         return 0;
304 }
305
306 void
307 FaderPort8::close ()
308 {
309         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::close\n");
310         stop_midi_handling ();
311         session_connections.drop_connections ();
312         automation_state_connections.drop_connections ();
313         assigned_stripable_connections.drop_connections ();
314         _assigned_strips.clear ();
315         drop_ctrl_connections ();
316         port_connections.drop_connections ();
317         selection_connection.disconnect ();
318 }
319
320 void
321 FaderPort8::stop_midi_handling ()
322 {
323         _periodic_connection.disconnect ();
324         _blink_connection.disconnect ();
325         midi_connections.drop_connections ();
326         /* Note: the input handler is still active at this point, but we're no
327          * longer connected to any of the parser signals
328          */
329 }
330
331 void
332 FaderPort8::connected ()
333 {
334         DEBUG_TRACE (DEBUG::FaderPort8, "initializing\n");
335         assert (!_device_active);
336
337         if (_device_active) {
338                 stop_midi_handling (); // re-init
339         }
340
341         // ideally check firmware version >= 1.01 (USB bcdDevice 0x0101) (vendor 0x194f prod 0x0202)
342         // but we don't have a handle to the underlying USB device here.
343
344         memset (_channel_off, 0, sizeof (_channel_off));
345         _plugin_off = _parameter_off = 0;
346         _blink_onoff = false;
347         _shift_lock = false;
348         _shift_pressed = 0;
349         _timer_divider = 0;
350
351         start_midi_handling ();
352         _ctrls.initialize ();
353
354         /* highlight bound user-actions */
355         for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin ();
356                         i != _ctrls.user_buttons ().end (); ++i) {
357                 _ctrls.button (i->first).set_active (! _user_action_map[i->first].empty ());
358         }
359         /* shift button lights */
360         tx_midi3 (0x90, 0x06, 0x00);
361         tx_midi3 (0x90, 0x46, 0x00);
362
363         send_session_state ();
364         assign_strips ();
365
366         Glib::RefPtr<Glib::TimeoutSource> blink_timer =
367                 Glib::TimeoutSource::create (200);
368         _blink_connection = blink_timer->connect (sigc::mem_fun (*this, &FaderPort8::blink_it));
369         blink_timer->attach (main_loop()->get_context());
370
371         Glib::RefPtr<Glib::TimeoutSource> periodic_timer =
372                 Glib::TimeoutSource::create (100);
373         _periodic_connection = periodic_timer->connect (sigc::mem_fun (*this, &FaderPort8::periodic));
374         periodic_timer->attach (main_loop()->get_context());
375 }
376
377 void
378 FaderPort8::disconnected ()
379 {
380         stop_midi_handling ();
381         if (_device_active) {
382                 for (uint8_t id = 0; id < N_STRIPS; ++id) {
383                         _ctrls.strip(id).unset_controllables ();
384                 }
385                 _ctrls.all_lights_off ();
386         }
387 }
388
389 void
390 FaderPort8::engine_reset ()
391 {
392         /* Port::PortDrop is called when the engine is halted or stopped */
393         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::engine_reset\n");
394         _connection_state = 0;
395         _device_active = false;
396         disconnected ();
397 }
398
399 bool
400 FaderPort8::connection_handler (std::string name1, std::string name2)
401 {
402 #ifdef VERBOSE_DEBUG
403         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::connection_handler: start\n");
404 #endif
405         if (!_input_port || !_output_port) {
406                 return false;
407         }
408
409         string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
410         string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
411
412         if (ni == name1 || ni == name2) {
413                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2));
414                 if (_input_port->connected ()) {
415                         if (_connection_state & InputConnected) {
416                                 return false;
417                         }
418                         _connection_state |= InputConnected;
419                 } else {
420                         _connection_state &= ~InputConnected;
421                 }
422         } else if (no == name1 || no == name2) {
423                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2));
424                 if (_output_port->connected ()) {
425                         if (_connection_state & OutputConnected) {
426                                 return false;
427                         }
428                         _connection_state |= OutputConnected;
429                 } else {
430                         _connection_state &= ~OutputConnected;
431                 }
432         } else {
433 #ifdef VERBOSE_DEBUG
434                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connections between %1 and %2 changed, but I ignored it\n", name1, name2));
435 #endif
436                 /* not our ports */
437                 return false;
438         }
439
440         if ((_connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
441
442                 /* XXX this is a horrible hack. Without a short sleep here,
443                  * something prevents the device wakeup messages from being
444                  * sent and/or the responses from being received.
445                  */
446                 g_usleep (100000);
447                 DEBUG_TRACE (DEBUG::FaderPort8, "device now connected for both input and output\n");
448                 connected ();
449                 _device_active = true;
450
451         } else {
452                 DEBUG_TRACE (DEBUG::FaderPort8, "Device disconnected (input or output or both) or not yet fully connected\n");
453                 if (_device_active) {
454                         disconnected ();
455                 }
456                 _device_active = false;
457         }
458
459         ConnectionChange (); /* emit signal for our GUI */
460
461 #ifdef VERBOSE_DEBUG
462         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::connection_handler: end\n");
463 #endif
464
465         return true; /* connection status changed */
466 }
467
468 list<boost::shared_ptr<ARDOUR::Bundle> >
469 FaderPort8::bundles ()
470 {
471         list<boost::shared_ptr<ARDOUR::Bundle> > b;
472
473         if (_input_bundle) {
474                 b.push_back (_input_bundle);
475                 b.push_back (_output_bundle);
476         }
477
478         return b;
479 }
480
481 /* ****************************************************************************
482  * MIDI I/O
483  */
484 bool
485 FaderPort8::midi_input_handler (Glib::IOCondition ioc, boost::weak_ptr<ARDOUR::AsyncMIDIPort> wport)
486 {
487         boost::shared_ptr<AsyncMIDIPort> port (wport.lock());
488
489         if (!port || !_input_port) {
490                 return false;
491         }
492
493 #ifdef VERBOSE_DEBUG
494         DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("something happend on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
495 #endif
496
497         if (ioc & ~IO_IN) {
498                 return false;
499         }
500
501         if (ioc & IO_IN) {
502
503                 port->clear ();
504 #ifdef VERBOSE_DEBUG
505                 DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("data available on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
506 #endif
507                 samplepos_t now = session->engine().sample_time();
508                 port->parse (now);
509         }
510
511         return true;
512 }
513
514 void
515 FaderPort8::start_midi_handling ()
516 {
517         _input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort8::sysex_handler, this, _1, _2, _3));
518         _input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort8::polypressure_handler, this, _1, _2));
519         for (uint8_t i = 0; i < 16; ++i) {
520         _input_port->parser()->channel_pitchbend[i].connect_same_thread (midi_connections, boost::bind (&FaderPort8::pitchbend_handler, this, _1, i, _2));
521         }
522         _input_port->parser()->controller.connect_same_thread (midi_connections, boost::bind (&FaderPort8::controller_handler, this, _1, _2));
523         _input_port->parser()->note_on.connect_same_thread (midi_connections, boost::bind (&FaderPort8::note_on_handler, this, _1, _2));
524         _input_port->parser()->note_off.connect_same_thread (midi_connections, boost::bind (&FaderPort8::note_off_handler, this, _1, _2));
525
526         /* This connection means that whenever data is ready from the input
527          * port, the relevant thread will invoke our ::midi_input_handler()
528          * method, which will read the data, and invoke the parser.
529          */
530         _input_port->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &FaderPort8::midi_input_handler), boost::weak_ptr<AsyncMIDIPort> (_input_port)));
531         _input_port->xthread().attach (main_loop()->get_context());
532 }
533
534 size_t
535 FaderPort8::tx_midi (std::vector<uint8_t> const& d) const
536 {
537         /* work around midi buffer overflow for batch changes */
538         if (d.size() == 3 && (d[0] == 0x91 || d[0] == 0x92)) {
539                 /* set colors triplet in one go */
540         } else if (d.size() == 3 && (d[0] == 0x93)) {
541                 g_usleep (1500);
542         } else {
543                 g_usleep (400 * d.size());
544         }
545 #ifndef NDEBUG
546         size_t tx = _output_port->write (&d[0], d.size(), 0);
547         assert (tx == d.size());
548         return tx;
549 #else
550         return _output_port->write (&d[0], d.size(), 0);
551 #endif
552 }
553
554 /* ****************************************************************************
555  * MIDI Callbacks
556  */
557 void
558 FaderPort8::polypressure_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
559 {
560         debug_2byte_msg ("PP", tb->controller_number, tb->value);
561         // outgoing only (meter)
562 }
563
564 void
565 FaderPort8::pitchbend_handler (MIDI::Parser &, uint8_t chan, MIDI::pitchbend_t pb)
566 {
567         debug_2byte_msg ("PB", chan, pb);
568         /* fader 0..16368 (0x3ff0 -- 1024 steps) */
569         bool handled = _ctrls.midi_fader (chan, pb);
570         /* if Shift key is held while moving a fader (group override), don't lock shift. */
571         if ((_shift_pressed > 0) && handled) {
572                 _shift_connection.disconnect ();
573                 _shift_lock = false;
574         }
575 }
576
577 void
578 FaderPort8::controller_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
579 {
580         debug_2byte_msg ("CC", tb->controller_number, tb->value);
581         /* encoder
582          *  val Bit 6 = direction, Bits 0-5 = number of steps
583          */
584         static const uint8_t dir_mask = 0x40;
585         static const uint8_t step_mask = 0x3f;
586
587         if (tb->controller_number == 0x3c) {
588                 encoder_navigate (tb->value & dir_mask ? true : false, tb->value & step_mask);
589         }
590         if (tb->controller_number == 0x10) {
591                 encoder_parameter (tb->value & dir_mask ? true : false, tb->value & step_mask);
592         }
593 }
594
595 void
596 FaderPort8::note_on_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
597 {
598         debug_2byte_msg ("ON", tb->note_number, tb->velocity);
599
600         /* fader touch */
601 #ifdef FADERPORT16
602         static const uint8_t touch_id_uppper = 0x77;
603 #else
604         static const uint8_t touch_id_uppper = 0x6f;
605 #endif
606         if (tb->note_number >= 0x68 && tb->note_number <= touch_id_uppper) {
607                 _ctrls.midi_touch (tb->note_number - 0x68, tb->velocity);
608                 return;
609         }
610
611         /* special case shift */
612         if (tb->note_number == 0x06 || tb->note_number == 0x46) {
613                 _shift_pressed |= (tb->note_number == 0x06) ? 1 : 2;
614                 if (_shift_pressed == 3) {
615                         return;
616                 }
617                 _shift_connection.disconnect ();
618                 if (_shift_lock) {
619                         _shift_lock = false;
620                         ShiftButtonChange (false);
621                         tx_midi3 (0x90, 0x06, 0x00);
622                         tx_midi3 (0x90, 0x46, 0x00);
623                         return;
624                 }
625
626                 Glib::RefPtr<Glib::TimeoutSource> shift_timer =
627                         Glib::TimeoutSource::create (1000);
628                 shift_timer->attach (main_loop()->get_context());
629                 _shift_connection = shift_timer->connect (sigc::mem_fun (*this, &FaderPort8::shift_timeout));
630
631                 ShiftButtonChange (true);
632                 tx_midi3 (0x90, 0x06, 0x7f);
633                 tx_midi3 (0x90, 0x46, 0x7f);
634                 return;
635         }
636
637         _ctrls.midi_event (tb->note_number, tb->velocity);
638 }
639
640 void
641 FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
642 {
643         debug_2byte_msg ("OF", tb->note_number, tb->velocity);
644
645 #ifdef FADERPORT16
646         static const uint8_t touch_id_uppper = 0x77;
647 #else
648         static const uint8_t touch_id_uppper = 0x6f;
649 #endif
650         if (tb->note_number >= 0x68 && tb->note_number <= touch_id_uppper) {
651                 // fader touch
652                 _ctrls.midi_touch (tb->note_number - 0x68, tb->velocity);
653                 return;
654         }
655
656         /* special case shift */
657         if (tb->note_number == 0x06 || tb->note_number == 0x46) {
658                 _shift_pressed &= (tb->note_number == 0x06) ? 2 : 1;
659                 if (_shift_pressed > 0) {
660                         return;
661                 }
662                 if (_shift_lock) {
663                         return;
664                 }
665                 ShiftButtonChange (false);
666                 tx_midi3 (0x90, 0x06, 0x00);
667                 tx_midi3 (0x90, 0x46, 0x00);
668                 /* just in case this happens concurrently */
669                 _shift_connection.disconnect ();
670                 _shift_lock = false;
671                 return;
672         }
673
674         bool handled = _ctrls.midi_event (tb->note_number, tb->velocity);
675         /* if Shift key is held while activating an action, don't lock shift. */
676         if ((_shift_pressed > 0) && handled) {
677                 _shift_connection.disconnect ();
678                 _shift_lock = false;
679         }
680 }
681
682 void
683 FaderPort8::sysex_handler (MIDI::Parser &p, MIDI::byte *buf, size_t size)
684 {
685 #ifndef NDEBUG
686         if (DEBUG_ENABLED(DEBUG::FaderPort8)) {
687                 DEBUG_STR_DECL(a);
688                 DEBUG_STR_APPEND(a, string_compose ("RECV sysex siz=%1", size));
689                 for (size_t i=0; i < size; ++i) {
690                         DEBUG_STR_APPEND(a,hex);
691                         DEBUG_STR_APPEND(a,"0x");
692                         DEBUG_STR_APPEND(a,(int)buf[i]);
693                         DEBUG_STR_APPEND(a,' ');
694                 }
695                 DEBUG_STR_APPEND(a,'\n');
696                 DEBUG_TRACE (DEBUG::FaderPort8, DEBUG_STR(a).str());
697         }
698 #endif
699 }
700
701 /* ****************************************************************************
702  * User actions
703  */
704 void
705 FaderPort8::set_button_action (FP8Controls::ButtonId id, bool press, std::string const& action_name)
706 {
707         if (_ctrls.user_buttons().find (id) == _ctrls.user_buttons().end ()) {
708                 return;
709         }
710         _user_action_map[id].action (press).assign_action (action_name);
711
712         if (!_device_active) {
713                 return;
714         }
715         _ctrls.button (id).set_active (!_user_action_map[id].empty ());
716 }
717
718 std::string
719 FaderPort8::get_button_action (FP8Controls::ButtonId id, bool press)
720 {
721         return _user_action_map[id].action(press)._action_name;
722 }
723
724 /* ****************************************************************************
725  * Persistent State
726  */
727 XMLNode&
728 FaderPort8::get_state ()
729 {
730         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::get_state\n");
731         XMLNode& node (ControlProtocol::get_state());
732
733         XMLNode* child;
734
735         child = new XMLNode (X_("Input"));
736         child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_input_port)->get_state());
737         node.add_child_nocopy (*child);
738
739         child = new XMLNode (X_("Output"));
740         child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
741         node.add_child_nocopy (*child);
742
743         node.set_property (X_("clock-mode"), _clock_mode);
744         node.set_property (X_("scribble-mode"), _scribble_mode);
745         node.set_property (X_("two-line-text"), _two_line_text);
746
747         for (UserActionMap::const_iterator i = _user_action_map.begin (); i != _user_action_map.end (); ++i) {
748                 if (i->second.empty()) {
749                         continue;
750                 }
751                 std::string name;
752                 if (!_ctrls.button_enum_to_name (i->first, name)) {
753                         continue;
754                 }
755                 XMLNode* btn = new XMLNode (X_("Button"));
756                 btn->set_property (X_("id"), name);
757                 if (!i->second.action(true).empty ()) {
758                         btn->set_property ("press", i->second.action(true)._action_name);
759                 }
760                 if (!i->second.action(false).empty ()) {
761                         btn->set_property ("release", i->second.action(false)._action_name);
762                 }
763                 node.add_child_nocopy (*btn);
764         }
765
766         return node;
767 }
768
769 int
770 FaderPort8::set_state (const XMLNode& node, int version)
771 {
772         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::set_state\n");
773         XMLNodeList nlist;
774         XMLNodeConstIterator niter;
775         XMLNode const* child;
776
777         if (ControlProtocol::set_state (node, version)) {
778                 return -1;
779         }
780
781         if ((child = node.child (X_("Input"))) != 0) {
782                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
783                 if (portnode) {
784                         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::set_state Input\n");
785                         boost::shared_ptr<ARDOUR::Port>(_input_port)->set_state (*portnode, version);
786                 }
787         }
788
789         if ((child = node.child (X_("Output"))) != 0) {
790                 XMLNode* portnode = child->child (Port::state_node_name.c_str());
791                 if (portnode) {
792                         DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::set_state Output\n");
793                         boost::shared_ptr<ARDOUR::Port>(_output_port)->set_state (*portnode, version);
794                 }
795         }
796
797         node.get_property (X_("clock-mode"), _clock_mode);
798         node.get_property (X_("scribble-mode"), _scribble_mode);
799         node.get_property (X_("two-line-text"), _two_line_text);
800
801         _user_action_map.clear ();
802         // TODO: When re-loading state w/o surface re-init becomes possible,
803         // unset lights and reset colors of user buttons.
804
805         for (XMLNodeList::const_iterator n = node.children().begin(); n != node.children().end(); ++n) {
806                 if ((*n)->name() != X_("Button")) {
807                         continue;
808                 }
809
810                 std::string id_str;
811                 if (!(*n)->get_property (X_("id"), id_str)) {
812                         continue;
813                 }
814
815                 FP8Controls::ButtonId id;
816                 if (!_ctrls.button_name_to_enum (id_str, id)) {
817                         continue;
818                 }
819
820                 std::string action_str;
821                 if ((*n)->get_property (X_("press"), action_str)) {
822                         set_button_action (id, true, action_str);
823                 }
824                 if ((*n)->get_property (X_("release"), action_str)) {
825                         set_button_action (id, false, action_str);
826                 }
827         }
828
829         return 0;
830 }
831
832 /* ****************************************************************************
833  * Stripable Assignment
834  */
835
836 static bool flt_audio_track (boost::shared_ptr<Stripable> s) {
837         return boost::dynamic_pointer_cast<AudioTrack>(s) != 0;
838 }
839
840 static bool flt_midi_track (boost::shared_ptr<Stripable> s) {
841         return boost::dynamic_pointer_cast<MidiTrack>(s) != 0;
842 }
843
844 static bool flt_bus (boost::shared_ptr<Stripable> s) {
845         if (boost::dynamic_pointer_cast<Route>(s) == 0) {
846                 return false;
847         }
848 #ifdef MIXBUS
849         if (s->mixbus () == 0) {
850                 return false;
851         }
852 #endif
853         return boost::dynamic_pointer_cast<Track>(s) == 0;
854 }
855
856 static bool flt_auxbus (boost::shared_ptr<Stripable> s) {
857         if (boost::dynamic_pointer_cast<Route>(s) == 0) {
858                 return false;
859         }
860 #ifdef MIXBUS
861         if (s->mixbus () > 0) {
862                 return false;
863         }
864 #endif
865         return boost::dynamic_pointer_cast<Track>(s) == 0;
866 }
867
868 static bool flt_vca (boost::shared_ptr<Stripable> s) {
869         return boost::dynamic_pointer_cast<VCA>(s) != 0;
870 }
871
872 static bool flt_selected (boost::shared_ptr<Stripable> s) {
873         return s->is_selected ();
874 }
875
876 static bool flt_mains (boost::shared_ptr<Stripable> s) {
877         return (s->is_master() || s->is_monitor());
878 }
879
880 static bool flt_all (boost::shared_ptr<Stripable> s) {
881         return true;
882 }
883
884 static bool flt_rec_armed (boost::shared_ptr<Stripable> s) {
885         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(s);
886         if (!t) {
887                 return false;
888         }
889         return t->rec_enable_control ()->get_value () > 0.;
890 }
891
892 static bool flt_instrument (boost::shared_ptr<Stripable> s) {
893         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(s);
894         if (!r) {
895                 return false;
896         }
897         return 0 != r->the_instrument ();
898 }
899
900 void
901 FaderPort8::filter_stripables (StripableList& strips) const
902 {
903         typedef bool (*FilterFunction)(boost::shared_ptr<Stripable>);
904         FilterFunction flt;
905
906         bool allow_master = false;
907         bool allow_monitor = false;
908
909         switch (_ctrls.mix_mode ()) {
910                 case MixAudio:
911                         flt = &flt_audio_track;
912                         break;
913                 case MixInstrument:
914                         flt = &flt_instrument;
915                         break;
916                 case MixBus:
917                         flt = &flt_bus;
918                         break;
919                 case MixVCA:
920                         flt = &flt_vca;
921                         break;
922                 case MixMIDI:
923                         flt = &flt_midi_track;
924                         break;
925                 case MixUser:
926                         allow_master = true;
927                         flt = &flt_selected;
928                         break;
929                 case MixOutputs:
930                         allow_master = true;
931                         allow_monitor = true;
932                         flt = &flt_mains;
933                         break;
934                 case MixInputs:
935                         flt = &flt_rec_armed;
936                         break;
937                 case MixFX:
938                         flt = &flt_auxbus;
939                         break;
940                 default:
941                         assert (0);
942                         // fall through
943                 case MixAll:
944                         allow_master = true;
945                         flt = &flt_all;
946                         break;
947         }
948
949         StripableList all;
950         session->get_stripables (all);
951
952         for (StripableList::const_iterator s = all.begin(); s != all.end(); ++s) {
953                 if ((*s)->is_auditioner ()) { continue; }
954                 if ((*s)->is_hidden ()) { continue; }
955
956                 if (!allow_master  && (*s)->is_master ()) { continue; }
957                 if (!allow_monitor && (*s)->is_monitor ()) { continue; }
958
959                 if ((*flt)(*s)) {
960                         strips.push_back (*s);
961                 }
962         }
963         strips.sort (Stripable::Sorter(true));
964 }
965
966 /* Track/Pan mode: assign stripable to strips, Send-mode: selection */
967 void
968 FaderPort8::assign_stripables (bool select_only)
969 {
970         StripableList strips;
971         filter_stripables (strips);
972
973         if (!select_only) {
974                 set_periodic_display_mode (FP8Strip::Stripables);
975         }
976
977         int n_strips = strips.size();
978         int channel_off = get_channel_off (_ctrls.mix_mode ());
979         channel_off = std::min (channel_off, n_strips - N_STRIPS);
980         channel_off = std::max (0, channel_off);
981         set_channel_off (_ctrls.mix_mode (), channel_off);
982
983         uint8_t id = 0;
984         int skip = channel_off;
985         for (StripableList::const_iterator s = strips.begin(); s != strips.end(); ++s) {
986                 if (skip > 0) {
987                         --skip;
988                         continue;
989                 }
990
991                 _assigned_strips[*s] = id;
992                 (*s)->DropReferences.connect (assigned_stripable_connections, MISSING_INVALIDATOR,
993                                 boost::bind (&FaderPort8::notify_stripable_added_or_removed, this), this);
994
995                 (*s)->PropertyChanged.connect (assigned_stripable_connections, MISSING_INVALIDATOR,
996                                 boost::bind (&FaderPort8::notify_stripable_property_changed, this, boost::weak_ptr<Stripable> (*s), _1), this);
997                 (*s)->presentation_info ().PropertyChanged.connect (assigned_stripable_connections, MISSING_INVALIDATOR,
998                                 boost::bind (&FaderPort8::notify_stripable_property_changed, this, boost::weak_ptr<Stripable> (*s), _1), this);
999
1000                 if (boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(*s)) {
1001                         if (r->panner_shell()) {
1002                                 r->panner_shell()->Changed.connect (assigned_stripable_connections, MISSING_INVALIDATOR,
1003                                 boost::bind (&FaderPort8::notify_stripable_property_changed, this, boost::weak_ptr<Stripable> (*s), PropertyChange()), this);
1004                         }
1005                 }
1006
1007                 if (select_only) {
1008                         /* used in send mode */
1009                         _ctrls.strip(id).set_text_line (3, (*s)->name (), true);
1010                         _ctrls.strip(id).set_select_button_color ((*s)->presentation_info ().color());
1011                         /* update selection lights */
1012                         _ctrls.strip(id).select_button ().set_active ((*s)->is_selected ());
1013                         _ctrls.strip(id).select_button ().set_blinking (*s == first_selected_stripable ());
1014                 } else {
1015                         _ctrls.strip(id).set_stripable (*s, _ctrls.fader_mode() == ModePan);
1016                 }
1017
1018                  boost::function<void ()> cb (boost::bind (&FaderPort8::select_strip, this, boost::weak_ptr<Stripable> (*s)));
1019                  _ctrls.strip(id).set_select_cb (cb);
1020
1021                 if (++id == N_STRIPS) {
1022                         break;
1023                 }
1024         }
1025         for (; id < N_STRIPS; ++id) {
1026                 _ctrls.strip(id).unset_controllables (select_only ? (FP8Strip::CTRL_SELECT | FP8Strip::CTRL_TEXT3) : FP8Strip::CTRL_ALL);
1027                 _ctrls.strip(id).set_periodic_display_mode (FP8Strip::Stripables);
1028         }
1029 }
1030
1031 /* ****************************************************************************
1032  * Control Link/Lock
1033  */
1034
1035 void
1036 FaderPort8::unlock_link (bool drop)
1037 {
1038         link_locked_connection.disconnect ();
1039
1040         if (drop) {
1041                 stop_link (); // calls back here with drop = false
1042                 return;
1043         }
1044
1045         _link_locked = false;
1046
1047         if (_link_enabled) {
1048                 assert (_ctrls.button (FP8Controls::BtnLink).is_active ());
1049                 _link_control.reset ();
1050                 start_link (); // re-connect & update LED colors
1051         } else {
1052                 _ctrls.button (FP8Controls::BtnLink).set_active (false);
1053                 _ctrls.button (FP8Controls::BtnLink).set_color (0x888888ff);
1054                 _ctrls.button (FP8Controls::BtnLock).set_active (false);
1055                 _ctrls.button (FP8Controls::BtnLock).set_color (0x888888ff);
1056         }
1057 }
1058
1059 void
1060 FaderPort8::lock_link ()
1061 {
1062         boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (_link_control.lock ());
1063         if (!ac) {
1064                 return;
1065         }
1066         ac->DropReferences.connect (link_locked_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::unlock_link, this, true), this);
1067
1068         // stop watching for focus events
1069         link_connection.disconnect ();
1070
1071         _link_locked = true;
1072
1073         _ctrls.button (FP8Controls::BtnLock).set_color (0x00ff00ff);
1074         _ctrls.button (FP8Controls::BtnLink).set_color (0x00ff00ff);
1075 }
1076
1077 void
1078 FaderPort8::stop_link ()
1079 {
1080         if (!_link_enabled) {
1081                 return;
1082         }
1083         link_connection.disconnect ();
1084         _link_control.reset ();
1085         _link_enabled = false;
1086         unlock_link (); // also updates button colors
1087 }
1088
1089 void
1090 FaderPort8::start_link ()
1091 {
1092         assert (!_link_locked);
1093
1094         _link_enabled = true;
1095         _ctrls.button (FP8Controls::BtnLink).set_active (true);
1096         _ctrls.button (FP8Controls::BtnLock).set_active (true);
1097         nofity_focus_control (_link_control); // update BtnLink, BtnLock colors
1098
1099         PBD::Controllable::GUIFocusChanged.connect (link_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::nofity_focus_control, this, _1), this);
1100 }
1101
1102
1103 /* ****************************************************************************
1104  * Plugin selection and parameters
1105  */
1106
1107 void
1108 FaderPort8::toggle_preset_param_mode ()
1109 {
1110         FaderMode fadermode = _ctrls.fader_mode ();
1111         if (fadermode != ModePlugins || _proc_params.size() == 0) {
1112                 return;
1113         }
1114         _show_presets = ! _show_presets;
1115         assign_processor_ctrls ();
1116 }
1117
1118 void
1119 FaderPort8::preset_changed ()
1120 {
1121         if (_show_presets) {
1122                 assign_processor_ctrls ();
1123         }
1124 }
1125
1126 void
1127 FaderPort8::assign_processor_ctrls ()
1128 {
1129         if (_proc_params.size() == 0) {
1130                 _ctrls.set_fader_mode (ModeTrack);
1131                 return;
1132         }
1133         set_periodic_display_mode (FP8Strip::PluginParam);
1134
1135         if (_show_presets) {
1136                 if (assign_plugin_presets (_plugin_insert.lock ())) {
1137                         return;
1138                 }
1139                 _show_presets = false;
1140         }
1141
1142         std::vector <ProcessorCtrl*> toggle_params;
1143         std::vector <ProcessorCtrl*> slider_params;
1144
1145         for ( std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
1146                 if ((*i).ac->toggled()) {
1147                         toggle_params.push_back (&(*i));
1148                 } else {
1149                         slider_params.push_back (&(*i));
1150                 }
1151         }
1152
1153         int n_parameters = std::max (toggle_params.size(), slider_params.size());
1154
1155         _parameter_off = std::min (_parameter_off, n_parameters - N_STRIPS);
1156         _parameter_off = std::max (0, _parameter_off);
1157
1158         uint8_t id = 0;
1159         for (size_t i = _parameter_off; i < (size_t)n_parameters; ++i) {
1160                 if (i >= toggle_params.size ()) {
1161                         _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT2);
1162                 }
1163                 else if (i >= slider_params.size ()) {
1164                         _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_SELECT & ~FP8Strip::CTRL_TEXT3);
1165                 } else {
1166                         _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT);
1167                 }
1168
1169                 if (i < slider_params.size ()) {
1170                         _ctrls.strip(id).set_fader_controllable (slider_params[i]->ac);
1171                         std::string param_name = slider_params[i]->name;
1172                         _ctrls.strip(id).set_text_line (0, param_name.substr (0, 9));
1173                         _ctrls.strip(id).set_text_line (1, param_name.length () > 9 ? param_name.substr (9) : "");
1174                 }
1175                 if (i < toggle_params.size ()) {
1176                         _ctrls.strip(id).set_select_controllable (toggle_params[i]->ac);
1177                         _ctrls.strip(id).set_text_line (3, toggle_params[i]->name, true);
1178                 }
1179                 if (++id == N_STRIPS) {
1180                         break;
1181                 }
1182         }
1183
1184         // clear remaining
1185         for (; id < N_STRIPS; ++id) {
1186                 _ctrls.strip(id).unset_controllables ();
1187         }
1188 }
1189
1190 bool
1191 FaderPort8::assign_plugin_presets (boost::shared_ptr<PluginInsert> pi)
1192 {
1193         if (!pi) {
1194                 return false;
1195         }
1196         boost::shared_ptr<ARDOUR::Plugin> plugin = pi->plugin ();
1197
1198         std::vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets ();
1199         if (presets.size () == 0) {
1200                 return false;
1201         }
1202
1203         int n_parameters = presets.size ();
1204
1205         _parameter_off = std::min (_parameter_off, n_parameters - (N_STRIPS - 1));
1206         _parameter_off = std::max (0, _parameter_off);
1207         Plugin::PresetRecord active = plugin->last_preset ();
1208
1209         uint8_t id = 0;
1210         for (size_t i = _parameter_off; i < (size_t)n_parameters; ++i) {
1211                 _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT);
1212                  boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin_preset, this, i));
1213                 _ctrls.strip(id).set_select_cb (cb);
1214                 _ctrls.strip(id).select_button ().set_active (true);
1215                 if (active != presets.at(i)) {
1216                         _ctrls.strip(id).select_button ().set_color (0x0000ffff);
1217                         _ctrls.strip(id).select_button ().set_blinking (false);
1218                 } else {
1219                         _ctrls.strip(id).select_button ().set_color (0x00ffffff);
1220                         _ctrls.strip(id).select_button ().set_blinking (plugin->parameter_changed_since_last_preset ());
1221                 }
1222                 std::string label = presets.at(i).label;
1223                 _ctrls.strip(id).set_text_line (0, label.substr (0, 9));
1224                 _ctrls.strip(id).set_text_line (1, label.length () > 9 ? label.substr (9) : "");
1225                 _ctrls.strip(id).set_text_line (3, "PRESET", true);
1226                 if (++id == (N_STRIPS - 1)) {
1227                         break;
1228                 }
1229         }
1230
1231         // clear remaining
1232         for (; id < (N_STRIPS - 1); ++id) {
1233                 _ctrls.strip(id).unset_controllables ();
1234         }
1235
1236         // pin clear-preset to the last slot
1237         assert (id == (N_STRIPS - 1));
1238         _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT);
1239          boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin_preset, this, SIZE_MAX));
1240         _ctrls.strip(id).set_select_cb (cb);
1241         _ctrls.strip(id).select_button ().set_blinking (false);
1242         _ctrls.strip(id).select_button ().set_color (active.uri.empty() ? 0x00ffffff : 0x0000ffff);
1243         _ctrls.strip(id).select_button ().set_active (true);
1244         _ctrls.strip(id).set_text_line (0, _("(none)"));
1245         _ctrls.strip(id).set_text_line (3, "PRESET", true);
1246         return true;
1247 }
1248
1249 void
1250 FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr<Stripable> s, bool eq)
1251 {
1252 #define PUSH_BACK_NON_NULL(N, C) do {if (C) { _proc_params.push_back (ProcessorCtrl (N, C)); }} while (0)
1253
1254         _proc_params.clear ();
1255         if (eq) {
1256                 int cnt = s->eq_band_cnt();
1257
1258 #ifdef MIXBUS32C
1259                 PUSH_BACK_NON_NULL ("Flt In", s->filter_enable_controllable (true)); // both HP/LP
1260                 PUSH_BACK_NON_NULL ("HP Freq", s->filter_freq_controllable (true));
1261                 PUSH_BACK_NON_NULL ("LP Freq", s->filter_freq_controllable (false));
1262                 PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ());
1263 #elif defined (MIXBUS)
1264                 PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ());
1265                 PUSH_BACK_NON_NULL ("HP Freq", s->filter_freq_controllable (true));
1266 #endif
1267
1268                 for (int band = 0; band < cnt; ++band) {
1269                         std::string bn = s->eq_band_name (band);
1270                         PUSH_BACK_NON_NULL (string_compose ("Gain %1", bn), s->eq_gain_controllable (band));
1271                         PUSH_BACK_NON_NULL (string_compose ("Freq %1", bn), s->eq_freq_controllable (band));
1272                         PUSH_BACK_NON_NULL (string_compose ("Band %1", bn), s->eq_q_controllable (band));
1273                         PUSH_BACK_NON_NULL (string_compose ("Shape %1", bn), s->eq_shape_controllable (band));
1274                 }
1275         } else {
1276                 PUSH_BACK_NON_NULL ("Comp In", s->comp_enable_controllable ());
1277                 PUSH_BACK_NON_NULL ("Threshold", s->comp_threshold_controllable ());
1278                 PUSH_BACK_NON_NULL ("Speed", s->comp_speed_controllable ());
1279                 PUSH_BACK_NON_NULL ("Mode", s->comp_mode_controllable ());
1280         }
1281 }
1282
1283 void
1284 FaderPort8::select_plugin (int num)
1285 {
1286         // make sure drop_ctrl_connections() was called
1287         assert (_proc_params.size() == 0 && _showing_well_known == 0 && _plugin_insert.expired());
1288
1289         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (first_selected_stripable());
1290         if (!r) {
1291                 _ctrls.set_fader_mode (ModeTrack);
1292                 return;
1293         }
1294
1295         // Toggle Bypass
1296         if (shift_mod ()) {
1297                 if (num >= 0) {
1298                         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (r->nth_plugin (num));
1299 #ifdef MIXBUS
1300                         if (pi && !pi->is_channelstrip () && pi->display_to_user ())
1301 #else
1302                         if (pi && pi->display_to_user ())
1303 #endif
1304                         {
1305                                 pi->enable (! pi->enabled ());
1306                         }
1307                 }
1308                 return;
1309         }
1310
1311         if (num < 0) {
1312                 build_well_known_processor_ctrls (r, num == -1);
1313                 assign_processor_ctrls ();
1314                 _showing_well_known = num;
1315                 return;
1316         }
1317         _showing_well_known = 0;
1318
1319         boost::shared_ptr<Processor> proc = r->nth_plugin (num);
1320         if (!proc) {
1321                 _ctrls.set_fader_mode (ModeTrack);
1322                 return;
1323         }
1324
1325         // disconnect signals from spill_plugins: processors_changed and ActiveChanged
1326         processor_connections.drop_connections ();
1327         r->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this);
1328
1329         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
1330         assert (pi); // nth_plugin() always returns a PI.
1331         /* _plugin_insert is used for Bypass/Enable & presets */
1332 #ifdef MIXBUS
1333         if (!pi->is_channelstrip () && pi->display_to_user ())
1334 #else
1335         if (pi->display_to_user ())
1336 #endif
1337         {
1338                 _plugin_insert = boost::weak_ptr<ARDOUR::PluginInsert> (pi);
1339                 pi->ActiveChanged.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_plugin_active_changed, this), this);
1340                 boost::shared_ptr<ARDOUR::Plugin> plugin = pi->plugin ();
1341
1342                 plugin->PresetAdded.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this);
1343                 plugin->PresetRemoved.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this);
1344                 plugin->PresetLoaded.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this);
1345                 plugin->PresetDirty.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this);
1346
1347                 if (_auto_pluginui) {
1348                         pi->ShowUI (); /* EMIT SIGNAL */
1349                 }
1350         }
1351
1352         // switching to "Mode Track" -> calls FaderPort8::notify_fader_mode_changed()
1353         // which drops the references, disconnects the signal and re-spills tracks
1354         proc->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this);
1355
1356         // build params
1357         _proc_params.clear();
1358         set<Evoral::Parameter> p = proc->what_can_be_automated ();
1359         for (set<Evoral::Parameter>::iterator i = p.begin(); i != p.end(); ++i) {
1360                 std::string n = proc->describe_parameter (*i);
1361                 if (n == "hidden") {
1362                         continue;
1363                 }
1364                 _proc_params.push_back (ProcessorCtrl (n, proc->automation_control (*i)));
1365         }
1366
1367         // TODO: open plugin GUI  if (_proc_params.size() > 0)
1368
1369         // display
1370         assign_processor_ctrls ();
1371         notify_plugin_active_changed ();
1372 }
1373
1374 void
1375 FaderPort8::select_plugin_preset (size_t num)
1376 {
1377         assert (_proc_params.size() > 0);
1378         boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock();
1379         if (!pi) {
1380                 _ctrls.set_fader_mode (ModeTrack);
1381                 return;
1382         }
1383         if (num == SIZE_MAX) {
1384                 pi->plugin ()->clear_preset ();
1385         } else {
1386                 std::vector<ARDOUR::Plugin::PresetRecord> presets = pi->plugin ()->get_presets ();
1387                 if (num < presets.size ()) {
1388                         pi->load_preset (presets.at (num));
1389                 }
1390         }
1391         _show_presets = false;
1392         assign_processor_ctrls ();
1393 }
1394
1395 /* short 4 chars at most */
1396 static std::string plugintype (ARDOUR::PluginType t) {
1397         switch (t) {
1398                 case AudioUnit:
1399                         return "AU";
1400                 case LADSPA:
1401                         return "LV1";
1402                 case LV2:
1403                         return "LV2";
1404                 case Windows_VST:
1405                 case LXVST:
1406                 case MacVST:
1407                         return "VST";
1408                 case Lua:
1409                         return "Lua";
1410                 default:
1411                         break;
1412         }
1413         return enum_2_string (t);
1414 }
1415
1416 void
1417 FaderPort8::spill_plugins ()
1418 {
1419         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (first_selected_stripable());
1420         if (!r) {
1421                 _ctrls.set_fader_mode (ModeTrack);
1422                 return;
1423         }
1424
1425         drop_ctrl_connections ();
1426
1427         // switching to "Mode Track" -> calls FaderPort8::notify_fader_mode_changed()
1428         // which drops the references, disconnects the signal and re-spills tracks
1429         r->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this);
1430
1431         // update when processor change
1432         r->processors_changed.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::spill_plugins, this), this);
1433
1434         // count available
1435         boost::shared_ptr<Processor> proc;
1436
1437         std::vector<uint32_t> procs;
1438
1439         for (uint32_t i = 0; 0 != (proc = r->nth_plugin (i)); ++i) {
1440                 if (!proc->display_to_user ()) {
1441                         continue;
1442                 }
1443 #ifdef MIXBUS
1444                 /* don't show channelstrip plugins, use "well known" */
1445                 if (boost::dynamic_pointer_cast<PluginInsert> (proc)->is_channelstrip ()) {
1446                         continue;
1447                 }
1448 #endif
1449                 int n_controls = 0;
1450                 set<Evoral::Parameter> p = proc->what_can_be_automated ();
1451                 for (set<Evoral::Parameter>::iterator j = p.begin(); j != p.end(); ++j) {
1452                         std::string n = proc->describe_parameter (*j);
1453                         if (n == "hidden") {
1454                                 continue;
1455                         }
1456                         ++n_controls;
1457                 }
1458                 if (n_controls > 0) {
1459                         procs.push_back (i);
1460                 }
1461         }
1462
1463         int n_plugins = procs.size();
1464         int spillwidth = N_STRIPS;
1465         bool have_well_known_eq = false;
1466         bool have_well_known_comp = false;
1467
1468         // reserve last slot(s) for "well-known"
1469         if (r->eq_band_cnt() > 0) {
1470                 --spillwidth;
1471                 have_well_known_eq = true;
1472         }
1473         if (r->comp_enable_controllable ()) {
1474                 --spillwidth;
1475                 have_well_known_comp = true;
1476         }
1477
1478         if (n_plugins == 0 && !have_well_known_eq && !have_well_known_comp) {
1479                 _ctrls.set_fader_mode (ModeTrack);
1480                 return;
1481         }
1482
1483         set_periodic_display_mode (FP8Strip::PluginSelect);
1484
1485         _plugin_off = std::min (_plugin_off, n_plugins - spillwidth);
1486         _plugin_off = std::max (0, _plugin_off);
1487
1488         uint8_t id = 0;
1489         for (uint32_t i = _plugin_off; ; ++i) {
1490                 if (i >= procs.size()) {
1491                         break;
1492                 }
1493                 boost::shared_ptr<Processor> proc = r->nth_plugin (procs[i]);
1494                 if (!proc) {
1495                         break;
1496                 }
1497                 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
1498                 boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, procs[i]));
1499
1500                 _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT);
1501                 _ctrls.strip(id).set_select_cb (cb);
1502                 _ctrls.strip(id).select_button ().set_color (proc->enabled () ? 0x00ff00ff : 0xff0000ff);
1503                 _ctrls.strip(id).select_button ().set_active (true);
1504                 _ctrls.strip(id).select_button ().set_blinking (false);
1505                 _ctrls.strip(id).set_text_line (0, proc->name());
1506                 _ctrls.strip(id).set_text_line (1, pi->plugin()->maker());
1507                 _ctrls.strip(id).set_text_line (2, plugintype (pi->type()));
1508                 _ctrls.strip(id).set_text_line (3, "");
1509
1510                 pi->ActiveChanged.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::spill_plugins, this), this);
1511
1512                 if (++id == spillwidth) {
1513                         break;
1514                 }
1515         }
1516         // clear remaining
1517         for (; id < spillwidth; ++id) {
1518                 _ctrls.strip(id).unset_controllables ();
1519         }
1520
1521         if (have_well_known_comp) {
1522                         assert (id < N_STRIPS);
1523                  boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, -2));
1524                  _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT);
1525                  _ctrls.strip(id).set_select_cb (cb);
1526                  _ctrls.strip(id).select_button ().set_color (0xffff00ff);
1527                  _ctrls.strip(id).select_button ().set_active (true);
1528                  _ctrls.strip(id).select_button ().set_blinking (false);
1529                  _ctrls.strip(id).set_text_line (0, "Comp");
1530                  _ctrls.strip(id).set_text_line (1, "Built-In");
1531                  _ctrls.strip(id).set_text_line (2, "--");
1532                  _ctrls.strip(id).set_text_line (3, "");
1533                  ++id;
1534         }
1535         if (have_well_known_eq) {
1536                         assert (id < N_STRIPS);
1537                  boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, -1));
1538                  _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT);
1539                  _ctrls.strip(id).set_select_cb (cb);
1540                  _ctrls.strip(id).select_button ().set_color (0xffff00ff);
1541                  _ctrls.strip(id).select_button ().set_active (true);
1542                  _ctrls.strip(id).select_button ().set_blinking (false);
1543                  _ctrls.strip(id).set_text_line (0, "EQ");
1544                  _ctrls.strip(id).set_text_line (1, "Built-In");
1545                  _ctrls.strip(id).set_text_line (2, "--");
1546                  _ctrls.strip(id).set_text_line (3, "");
1547                  ++id;
1548         }
1549         assert (id == N_STRIPS);
1550 }
1551
1552 /* ****************************************************************************
1553  * Aux Sends and Mixbus assigns
1554  */
1555
1556 void
1557 FaderPort8::assign_sends ()
1558 {
1559         boost::shared_ptr<Stripable> s = first_selected_stripable();
1560         if (!s) {
1561                 _ctrls.set_fader_mode (ModeTrack);
1562                 return;
1563         }
1564
1565         int n_sends = 0;
1566         while (0 != s->send_level_controllable (n_sends)) {
1567                 ++n_sends;
1568         }
1569         if (n_sends == 0) {
1570                 _ctrls.set_fader_mode (ModeTrack);
1571                 return;
1572         }
1573
1574         drop_ctrl_connections ();
1575         s->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this);
1576
1577         set_periodic_display_mode (FP8Strip::SendDisplay);
1578
1579         _plugin_off = std::min (_plugin_off, n_sends - N_STRIPS);
1580         _plugin_off = std::max (0, _plugin_off);
1581
1582         uint8_t id = 0;
1583         int skip = _parameter_off;
1584         for (uint32_t i = _plugin_off; ; ++i) {
1585                 if (skip > 0) {
1586                         --skip;
1587                         continue;
1588                 }
1589                 boost::shared_ptr<AutomationControl> send = s->send_level_controllable (i);
1590                 if (!send) {
1591                         break;
1592                 }
1593
1594                 _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT);
1595                 _ctrls.strip(id).set_fader_controllable (send);
1596                 _ctrls.strip(id).set_text_line (0, s->send_name (i));
1597                 _ctrls.strip(id).set_mute_controllable (s->send_enable_controllable (i));
1598
1599                 if (++id == N_STRIPS) {
1600                         break;
1601                 }
1602         }
1603         // clear remaining
1604         for (; id < N_STRIPS; ++id) {
1605                 _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT);
1606         }
1607 #ifdef MIXBUS // master-assign on last solo
1608         _ctrls.strip(N_STRIPS - 1).set_solo_controllable (s->master_send_enable_controllable ());
1609 #endif
1610         /* set select buttons */
1611         assigned_stripable_connections.drop_connections ();
1612         _assigned_strips.clear ();
1613         assign_stripables (true);
1614 }
1615
1616 /* ****************************************************************************
1617  * Main stripable assignment (dispatch depending on mode)
1618  */
1619
1620 void
1621 FaderPort8::assign_strips ()
1622 {
1623         assigned_stripable_connections.drop_connections ();
1624         _assigned_strips.clear ();
1625
1626         FaderMode fadermode = _ctrls.fader_mode ();
1627         switch (fadermode) {
1628                 case ModeTrack:
1629                 case ModePan:
1630                         assign_stripables ();
1631                         stripable_selection_changed (); // update selection, automation-state
1632                         break;
1633                 case ModePlugins:
1634                         if (_proc_params.size() > 0) {
1635                                 assign_processor_ctrls ();
1636                         } else {
1637                                 spill_plugins ();
1638                         }
1639                         break;
1640                 case ModeSend:
1641                         assign_sends ();
1642                         break;
1643         }
1644 }
1645
1646 /* ****************************************************************************
1647  * some helper functions
1648  */
1649
1650 void
1651 FaderPort8::set_periodic_display_mode (FP8Strip::DisplayMode m)
1652 {
1653         for (uint8_t id = 0; id < N_STRIPS; ++id) {
1654                 _ctrls.strip(id).set_periodic_display_mode (m);
1655         }
1656 }
1657
1658 void
1659 FaderPort8::drop_ctrl_connections ()
1660 {
1661         _proc_params.clear();
1662         if (_auto_pluginui) {
1663                 boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock ();
1664                 if (pi) {
1665                         pi->HideUI (); /* EMIT SIGNAL */
1666                 }
1667         }
1668         _plugin_insert.reset ();
1669         _show_presets = false;
1670         processor_connections.drop_connections ();
1671         _showing_well_known = 0;
1672         notify_plugin_active_changed ();
1673 }
1674
1675 /* functor for FP8Strip's select button */
1676 void
1677 FaderPort8::select_strip (boost::weak_ptr<Stripable> ws)
1678 {
1679         boost::shared_ptr<Stripable> s = ws.lock();
1680         if (!s) {
1681                 return;
1682         }
1683 #if 1 /* single exclusive selection by default, toggle via shift */
1684
1685 # if 1 /* selecting a selected strip -> move fader to unity */
1686         if (s == first_selected_stripable () && !shift_mod ()) {
1687                 if (_ctrls.fader_mode () == ModeTrack) {
1688                         boost::shared_ptr<AutomationControl> ac = s->gain_control ();
1689                         ac->start_touch (ac->session().transport_sample());
1690                         ac->set_value (ac->normal (), PBD::Controllable::UseGroup);
1691                 }
1692                 return;
1693         }
1694 # endif
1695
1696         if (shift_mod ()) {
1697                 ToggleStripableSelection (s);
1698         } else {
1699                 SetStripableSelection (s);
1700         }
1701 #else
1702         /* tri-state selection: This allows to set the "first selected"
1703          * with a single click without clearing the selection.
1704          * Single de/select via shift.
1705          */
1706         if (shift_mod ()) {
1707                 if (s->is_selected ()) {
1708                         RemoveStripableFromSelection (s);
1709                 } else {
1710                         SetStripableSelection (s);
1711                 }
1712                 return;
1713         }
1714         if (s->is_selected () && s != first_selected_stripable ()) {
1715                 set_first_selected_stripable (s);
1716                 stripable_selection_changed ();
1717         } else {
1718                 ToggleStripableSelection (s);
1719         }
1720 #endif
1721 }
1722
1723 /* ****************************************************************************
1724  * Assigned Stripable Callbacks
1725  */
1726
1727 void
1728 FaderPort8::notify_fader_mode_changed ()
1729 {
1730         FaderMode fadermode = _ctrls.fader_mode ();
1731
1732         boost::shared_ptr<Stripable> s = first_selected_stripable();
1733         if (!s && (fadermode == ModePlugins || fadermode == ModeSend)) {
1734                 _ctrls.set_fader_mode (ModeTrack);
1735                 return;
1736         }
1737
1738         drop_ctrl_connections ();
1739
1740         switch (fadermode) {
1741                 case ModeTrack:
1742                 case ModePan:
1743                         break;
1744                 case ModePlugins:
1745                 case ModeSend:
1746                         _plugin_off = 0;
1747                         _parameter_off = 0;
1748                         stop_link ();
1749                         // force unset rec-arm button, see also FaderPort8::button_arm
1750                         _ctrls.button (FP8Controls::BtnArm).set_active (false);
1751                         ARMButtonChange (false);
1752                         break;
1753         }
1754         assign_strips ();
1755         notify_automation_mode_changed ();
1756 }
1757
1758 void
1759 FaderPort8::notify_stripable_added_or_removed ()
1760 {
1761         /* called by
1762          *  - DropReferences
1763          *  - session->RouteAdded
1764          *  - PresentationInfo::Change
1765          *    - Properties::hidden
1766          *    - Properties::order
1767          */
1768         assign_strips ();
1769 }
1770
1771 /* called from static PresentationInfo::Change */
1772 void
1773 FaderPort8::notify_pi_property_changed (const PropertyChange& what_changed)
1774 {
1775         if (what_changed.contains (Properties::hidden)) {
1776                 notify_stripable_added_or_removed ();
1777         }
1778         if (what_changed.contains (Properties::order)) {
1779                 notify_stripable_added_or_removed ();
1780         }
1781         // Properties::selected is handled via StripableSelectionChanged
1782 }
1783
1784 void
1785 FaderPort8::notify_stripable_property_changed (boost::weak_ptr<Stripable> ws, const PropertyChange& what_changed)
1786 {
1787         boost::shared_ptr<Stripable> s = ws.lock();
1788         if (!s) {
1789                 assert (0); // this should not happen
1790                 return;
1791         }
1792         if (_assigned_strips.find (s) == _assigned_strips.end()) {
1793                 /* it can happen that signal emission is delayed.
1794                  * A signal may already be in the queue but the
1795                  * _assigned_strips has meanwhile changed.
1796                  *
1797                  * before _assigned_strips changes, the connections are dropped
1798                  * but that does not seem to invalidate pending requests :(
1799                  *
1800                  * Seen when creating a new MB session and Mixbusses are added
1801                  * incrementally.
1802                  */
1803                 return;
1804         }
1805         uint8_t id = _assigned_strips[s];
1806
1807         if (what_changed.contains (Properties::color)) {
1808                 _ctrls.strip(id).set_select_button_color (s->presentation_info ().color());
1809         }
1810
1811         if (what_changed.empty ()) {
1812                 _ctrls.strip(id).set_stripable (s, _ctrls.fader_mode() == ModePan);
1813         }
1814
1815         if (what_changed.contains (Properties::name)) {
1816                 switch (_ctrls.fader_mode ()) {
1817                         case ModeSend:
1818                                 _ctrls.strip(id).set_text_line (3, s->name(), true);
1819                                 break;
1820                         case ModeTrack:
1821                         case ModePan:
1822                                 _ctrls.strip(id).set_text_line (0, s->name());
1823                                 break;
1824                         case ModePlugins:
1825                                 assert (0);
1826                                 break;
1827                 }
1828         }
1829 }
1830
1831 void
1832 FaderPort8::stripable_selection_changed ()
1833 {
1834         if (!_device_active) {
1835                 /* this can be called anytime from the static
1836                  * ControlProtocol::StripableSelectionChanged
1837                  */
1838                 return;
1839         }
1840         automation_state_connections.drop_connections();
1841
1842         switch (_ctrls.fader_mode ()) {
1843                 case ModePlugins:
1844                         if (_proc_params.size () > 0 && _showing_well_known < 0) {
1845                                 /* w/well-known -> re-assign to new strip */
1846                                 int wk = _showing_well_known;
1847                                 drop_ctrl_connections ();
1848                                 select_plugin (wk);
1849                         } else if (_proc_params.size() == 0) {
1850                                 /* selecting plugin, update available */
1851                                 spill_plugins ();
1852                         }
1853                         return;
1854                 case ModeSend:
1855                         _plugin_off = 0;
1856                         assign_sends ();
1857                         return;
1858                 case ModeTrack:
1859                 case ModePan:
1860                         break;
1861         }
1862
1863         /* update selection lights */
1864         for (StripAssignmentMap::const_iterator i = _assigned_strips.begin(); i != _assigned_strips.end(); ++i) {
1865                 boost::shared_ptr<ARDOUR::Stripable> s = i->first;
1866                 uint8_t id = i->second;
1867                 bool sel = s->is_selected ();
1868                 _ctrls.strip(id).select_button ().set_active (sel);
1869                 _ctrls.strip(id).select_button ().set_blinking (sel && s == first_selected_stripable ());
1870         }
1871
1872         /* track automation-mode of primary selection */
1873         boost::shared_ptr<Stripable> s = first_selected_stripable();
1874         if (s) {
1875                 boost::shared_ptr<AutomationControl> ac;
1876                 ac = s->gain_control();
1877                 if (ac && ac->alist()) {
1878                         ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this);
1879                 }
1880                 ac = s->pan_azimuth_control();
1881                 if (ac && ac->alist()) {
1882                         ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this);
1883                 }
1884         }
1885         /* set lights */
1886         notify_automation_mode_changed ();
1887 }
1888
1889
1890 /* ****************************************************************************
1891  * Banking
1892  */
1893
1894 void
1895 FaderPort8::move_selected_into_view ()
1896 {
1897         boost::shared_ptr<Stripable> selected = first_selected_stripable ();
1898         if (!selected) {
1899                 return;
1900         }
1901
1902         StripableList strips;
1903         filter_stripables (strips);
1904
1905         StripableList::iterator it = std::find (strips.begin(), strips.end(), selected);
1906         if (it == strips.end()) {
1907                 return;
1908         }
1909         int off = std::distance (strips.begin(), it);
1910
1911         int channel_off = get_channel_off (_ctrls.mix_mode ());
1912         if (channel_off <= off && off < channel_off + N_STRIPS) {
1913                 return;
1914         }
1915
1916         if (channel_off > off) {
1917                 channel_off = off;
1918         } else {
1919                 channel_off = off - (N_STRIPS - 1);
1920         }
1921         set_channel_off (_ctrls.mix_mode (), channel_off);
1922         assign_strips ();
1923 }
1924
1925 void
1926 FaderPort8::select_prev_next (bool next)
1927 {
1928         StripableList strips;
1929         filter_stripables (strips);
1930
1931         boost::shared_ptr<Stripable> selected = first_selected_stripable ();
1932         if (!selected) {
1933                 if (strips.size() > 0) {
1934                         if (next) {
1935                                 SetStripableSelection (strips.front ());
1936                         } else {
1937                                 SetStripableSelection (strips.back ());
1938                         }
1939                 }
1940                 return;
1941         }
1942
1943         bool found = false;
1944         boost::shared_ptr<Stripable> toselect;
1945         for (StripableList::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1946                 if (*s == selected) {
1947                         if (!next) {
1948                                 found = true;
1949                                 break;
1950                         }
1951                         ++s;
1952                         if (s != strips.end()) {
1953                                 toselect = *s;
1954                                 found = true;
1955                         }
1956                         break;
1957                 }
1958                 if (!next) {
1959                         toselect = *s;
1960                 }
1961         }
1962
1963         if (found && toselect) {
1964                 SetStripableSelection (toselect);
1965         }
1966 }
1967
1968 void
1969 FaderPort8::bank (bool down, bool page)
1970 {
1971         int dt = page ? N_STRIPS : 1;
1972         if (down) {
1973                 dt *= -1;
1974         }
1975         set_channel_off (_ctrls.mix_mode (), get_channel_off (_ctrls.mix_mode ()) + dt);
1976         assign_strips ();
1977 }
1978
1979 void
1980 FaderPort8::bank_param (bool down, bool page)
1981 {
1982         int dt = page ? N_STRIPS : 1;
1983         if (down) {
1984                 dt *= -1;
1985         }
1986         switch (_ctrls.fader_mode ()) {
1987                 case ModePlugins:
1988                         if (_proc_params.size() > 0) {
1989                                 _parameter_off += dt;
1990                                 assign_processor_ctrls ();
1991                         } else {
1992                                 _plugin_off += dt;
1993                                 spill_plugins ();
1994                         }
1995                         break;
1996                 case ModeSend:
1997                         _plugin_off += dt;
1998                         assign_sends ();
1999                         break;
2000                 default:
2001                         break;
2002         }
2003 }