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