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