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