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