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