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