a201d253758d49d29e885242098418466e126592
[ardour.git] / libs / surfaces / mackie / strip.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3         Copyright (C) 2012 Paul Davis
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 2 of the License, or
8         (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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <sstream>
21 #include <vector>
22 #include <climits>
23
24 #include <stdint.h>
25
26 #include <sys/time.h>
27
28 #include <glibmm/convert.h>
29
30 #include "midi++/port.h"
31
32 #include "pbd/compose.h"
33 #include "pbd/convert.h"
34
35 #include "ardour/amp.h"
36 #include "ardour/bundle.h"
37 #include "ardour/debug.h"
38 #include "ardour/midi_ui.h"
39 #include "ardour/meter.h"
40 #include "ardour/monitor_control.h"
41 #include "ardour/plugin_insert.h"
42 #include "ardour/pannable.h"
43 #include "ardour/panner.h"
44 #include "ardour/panner_shell.h"
45 #include "ardour/phase_control.h"
46 #include "ardour/rc_configuration.h"
47 #include "ardour/route.h"
48 #include "ardour/session.h"
49 #include "ardour/send.h"
50 #include "ardour/solo_isolate_control.h"
51 #include "ardour/track.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/user_bundle.h"
54 #include "ardour/profile.h"
55
56 #include "mackie_control_protocol.h"
57 #include "surface_port.h"
58 #include "surface.h"
59 #include "strip.h"
60 #include "button.h"
61 #include "led.h"
62 #include "pot.h"
63 #include "fader.h"
64 #include "jog.h"
65 #include "meter.h"
66
67 using namespace std;
68 using namespace ARDOUR;
69 using namespace PBD;
70 using namespace ArdourSurface;
71 using namespace Mackie;
72
73 #ifndef timeradd /// only avail with __USE_BSD
74 #define timeradd(a,b,result)                         \
75   do {                                               \
76     (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;    \
77     (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
78     if ((result)->tv_usec >= 1000000)                \
79     {                                                \
80       ++(result)->tv_sec;                            \
81       (result)->tv_usec -= 1000000;                  \
82     }                                                \
83   } while (0)
84 #endif
85
86 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
87
88 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
89         : Group (name)
90         , _solo (0)
91         , _recenable (0)
92         , _mute (0)
93         , _select (0)
94         , _vselect (0)
95         , _fader_touch (0)
96         , _vpot (0)
97         , _fader (0)
98         , _meter (0)
99         , _index (index)
100         , _surface (&s)
101         , _controls_locked (false)
102         , _transport_is_rolling (false)
103         , _metering_active (true)
104         , _block_screen_redisplay_until (0)
105         , return_to_vpot_mode_display_at (UINT64_MAX)
106         , eq_band (-1)
107         , _pan_mode (PanAzimuthAutomation)
108         , _last_gain_position_written (-1.0)
109         , _last_pan_azi_position_written (-1.0)
110         , _last_pan_width_position_written (-1.0)
111         , _last_trim_position_written (-1.0)
112 {
113         _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
114         _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
115
116         if (s.mcp().device_info().has_meters()) {
117                 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
118         }
119
120         for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
121                 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
122                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
123                                                                    _surface->number(), index, Button::id_to_name (bb->bid()),
124                                                                    bb->id(), b->second.base_id));
125         }
126 }
127
128 Strip::~Strip ()
129 {
130         /* surface is responsible for deleting all controls */
131 }
132
133 void
134 Strip::add (Control & control)
135 {
136         Button* button;
137
138         Group::add (control);
139
140         /* fader, vpot, meter were all set explicitly */
141
142         if ((button = dynamic_cast<Button*>(&control)) != 0) {
143                 switch (button->bid()) {
144                 case Button::RecEnable:
145                         _recenable = button;
146                         break;
147                 case Button::Mute:
148                         _mute = button;
149                         break;
150                 case Button::Solo:
151                         _solo = button;
152                         break;
153                 case Button::Select:
154                         _select = button;
155                         break;
156                 case Button::VSelect:
157                         _vselect = button;
158                         break;
159                 case Button::FaderTouch:
160                         _fader_touch = button;
161                         break;
162                 default:
163                         break;
164                 }
165         }
166 }
167
168 void
169 Strip::set_stripable (boost::shared_ptr<Stripable> r, bool /*with_messages*/)
170 {
171         if (_controls_locked) {
172                 return;
173         }
174
175         mb_pan_controllable.reset();
176
177         stripable_connections.drop_connections ();
178
179         _solo->set_control (boost::shared_ptr<AutomationControl>());
180         _mute->set_control (boost::shared_ptr<AutomationControl>());
181         _select->set_control (boost::shared_ptr<AutomationControl>());
182         _recenable->set_control (boost::shared_ptr<AutomationControl>());
183         _fader->set_control (boost::shared_ptr<AutomationControl>());
184         _vpot->set_control (boost::shared_ptr<AutomationControl>());
185
186         _stripable = r;
187
188         reset_saved_values ();
189
190         if (!r) {
191                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
192                 zero ();
193                 return;
194         }
195
196         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping stripable %3\n",
197                                                            _surface->number(), _index, _stripable->name()));
198
199         _solo->set_control (_stripable->solo_control());
200         _mute->set_control (_stripable->mute_control());
201
202         _stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
203         _stripable->mute_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
204
205         boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control();
206         if (pan_control) {
207                 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
208         }
209
210         pan_control = _stripable->pan_width_control();
211         if (pan_control) {
212                 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
213         }
214
215         _stripable->gain_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
216         _stripable->PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
217
218         boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_stripable);
219
220         if (trk) {
221                 _recenable->set_control (trk->rec_enable_control());
222                 trk->rec_enable_control()->Changed .connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
223         }
224
225         // TODO this works when a currently-banked stripable is made inactive, but not
226         // when a stripable is activated which should be currently banked.
227
228         // XXX Stripable
229         // _stripable->active_changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
230         _stripable->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_stripable_deleted, this), ui_context());
231
232         /* setup legal VPot modes for this stripable */
233
234         possible_pot_parameters.clear();
235
236         if (_stripable->pan_azimuth_control()) {
237                 possible_pot_parameters.push_back (PanAzimuthAutomation);
238         }
239         if (_stripable->pan_width_control()) {
240                 possible_pot_parameters.push_back (PanWidthAutomation);
241         }
242         if (_stripable->pan_elevation_control()) {
243                 possible_pot_parameters.push_back (PanElevationAutomation);
244         }
245         if (_stripable->pan_frontback_control()) {
246                 possible_pot_parameters.push_back (PanFrontBackAutomation);
247         }
248         if (_stripable->pan_lfe_control()) {
249                 possible_pot_parameters.push_back (PanLFEAutomation);
250         }
251
252         _pan_mode = PanAzimuthAutomation;
253
254         if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
255                 set_vpot_parameter (_pan_mode);
256         }
257
258         _fader->set_control (_stripable->gain_control());
259
260         notify_all ();
261 }
262
263 void
264 Strip::notify_all()
265 {
266         if (!_stripable) {
267                 zero ();
268                 return;
269         }
270         // The active V-pot control may not be active for this strip
271         // But if we zero it in the controls function it may erase
272         // the one we do want
273         _surface->write (_vpot->zero());
274
275         notify_solo_changed ();
276         notify_mute_changed ();
277         notify_gain_changed ();
278         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
279         notify_panner_azi_changed ();
280         notify_panner_width_changed ();
281         notify_record_enable_changed ();
282         notify_processor_changed ();
283 }
284
285 void
286 Strip::notify_solo_changed ()
287 {
288         if (_stripable && _solo) {
289                 _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
290         }
291 }
292
293 void
294 Strip::notify_mute_changed ()
295 {
296         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
297         if (_stripable && _mute) {
298                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\tstripable muted ? %1\n", _stripable->mute_control()->muted()));
299                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_stripable->mute_control()->muted() ? on : off)));
300
301                 _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
302         }
303 }
304
305 void
306 Strip::notify_record_enable_changed ()
307 {
308         if (_stripable && _recenable)  {
309                 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (_stripable);
310                 if (trk) {
311                         _surface->write (_recenable->set_state (trk->rec_enable_control()->get_value() ? on : off));
312                 }
313         }
314 }
315
316 void
317 Strip::notify_active_changed ()
318 {
319         _surface->mcp().refresh_current_bank();
320 }
321
322 void
323 Strip::notify_stripable_deleted ()
324 {
325         _surface->mcp().notify_stripable_removed ();
326         _surface->mcp().refresh_current_bank();
327 }
328
329 void
330 Strip::notify_gain_changed (bool force_update)
331 {
332         if (!_stripable) {
333                 return;
334         }
335
336         boost::shared_ptr<AutomationControl> ac = _stripable->gain_control();
337         Control* control;
338
339         if (!ac) {
340                 /* doesn't seem possible but lets be safe */
341                 return;
342         }
343
344         /* track gain control could be on vpot or fader, depending in
345          * flip mode.
346          */
347
348         if (_vpot->control() == ac) {
349                 control = _vpot;
350         } else if (_fader->control() == ac) {
351                 control = _fader;
352         } else {
353                 return;
354         }
355
356         float gain_coefficient = ac->get_value();
357         float normalized_position = ac->internal_to_interface (gain_coefficient);
358
359         if (force_update || normalized_position != _last_gain_position_written) {
360
361                 if (!control->in_use()) {
362                         if (control == _vpot) {
363                                 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
364                         } else {
365                                 _surface->write (_fader->set_position (normalized_position));
366                         }
367                 }
368
369                 do_parameter_display (GainAutomation, gain_coefficient);
370                 _last_gain_position_written = normalized_position;
371         }
372 }
373
374 void
375 Strip::notify_processor_changed (bool force_update)
376 {
377 }
378
379 void
380 Strip::notify_property_changed (const PropertyChange& what_changed)
381 {
382         if (!what_changed.contains (ARDOUR::Properties::name)) {
383                 return;
384         }
385
386         show_stripable_name ();
387 }
388
389 void
390 Strip::show_stripable_name ()
391 {
392         MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
393
394         if (svm != MackieControlProtocol::None) {
395                 /* subview mode is responsible for upper line */
396                 return;
397         }
398
399         string fullname = string();
400         if (!_stripable) {
401                 fullname = string();
402         } else {
403                 fullname = _stripable->name();
404         }
405
406         if (fullname.length() <= 6) {
407                 pending_display[0] = fullname;
408         } else {
409                 pending_display[0] = PBD::short_version (fullname, 6);
410         }
411 }
412
413 void
414 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
415 {
416         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
417
418         if (!r) {
419                 /* not in subview mode */
420                 return;
421         }
422
423         if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
424                 /* no longer in Sends subview mode */
425                 return;
426         }
427
428         boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
429         if (!control) {
430                 return;
431         }
432
433         if (control) {
434                 float val = control->get_value();
435                 do_parameter_display (type, val);
436
437                 if (_vpot->control() == control) {
438                         /* update pot/encoder */
439                         _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
440                 }
441         }
442 }
443
444 void
445 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
446 {
447         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
448
449         if (!r) {
450                 /* not in subview mode */
451                 return;
452         }
453
454         if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
455                 /* no longer in TrackViewsubview mode */
456                 return;
457         }
458
459         boost::shared_ptr<AutomationControl> control;
460         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
461
462         switch (type) {
463         case TrimAutomation:
464                 control = r->trim_control();
465                 break;
466         case SoloIsolateAutomation:
467                 control = r->solo_isolate_control ();
468                 break;
469         case SoloSafeAutomation:
470                 control = r->solo_safe_control ();
471                 break;
472         case MonitoringAutomation:
473                 if (track) {
474                         control = track->monitoring_control();
475                 }
476                 break;
477         case PhaseAutomation:
478                 control = r->phase_control ();
479                 break;
480         default:
481                 break;
482         }
483
484         if (control) {
485                 float val = control->get_value();
486
487                 /* Note: all of the displayed controllables require the display
488                  * of their *actual* ("internal") value, not the version mapped
489                  * into the normalized 0..1.0 ("interface") range.
490                  */
491
492                 do_parameter_display (type, val);
493                 /* update pot/encoder */
494                 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
495         }
496 }
497
498 void
499 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
500 {
501         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
502
503         if (!r) {
504                 /* not in subview mode */
505                 return;
506         }
507
508         if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
509                 /* no longer in EQ subview mode */
510                 return;
511         }
512
513         boost::shared_ptr<AutomationControl> control;
514
515         switch (type) {
516         case EQGain:
517                 control = r->eq_gain_controllable (band);
518                 break;
519         case EQFrequency:
520                 control = r->eq_freq_controllable (band);
521                 break;
522         case EQQ:
523                 control = r->eq_q_controllable (band);
524                 break;
525         case EQShape:
526                 control = r->eq_shape_controllable (band);
527                 break;
528         case EQHPF:
529                 control = r->eq_hpf_controllable ();
530                 break;
531         case EQEnable:
532                 control = r->eq_enable_controllable ();
533                 break;
534         default:
535                 break;
536         }
537
538         if (control) {
539                 float val = control->get_value();
540                 do_parameter_display (type, val);
541                 /* update pot/encoder */
542                 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
543         }
544 }
545
546 void
547 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
548 {
549         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
550
551         if (!r) {
552                 /* not in subview mode */
553                 return;
554         }
555
556         if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
557                 /* no longer in EQ subview mode */
558                 return;
559         }
560
561         boost::shared_ptr<AutomationControl> control;
562         bool reset_all = false;
563
564         switch (type) {
565         case CompThreshold:
566                 control = r->comp_threshold_controllable ();
567                 break;
568         case CompSpeed:
569                 control = r->comp_speed_controllable ();
570                 break;
571         case CompMode:
572                 control = r->comp_mode_controllable ();
573                 reset_all = true;
574                 break;
575         case CompMakeup:
576                 control = r->comp_makeup_controllable ();
577                 break;
578         case CompRedux:
579                 control = r->comp_redux_controllable ();
580                 break;
581         case CompEnable:
582                 control = r->comp_enable_controllable ();
583                 break;
584         default:
585                 break;
586         }
587
588         if (propagate_mode && reset_all) {
589                 _surface->subview_mode_changed ();
590         }
591
592         if (control) {
593                 float val = control->get_value();
594                 do_parameter_display (type, val);
595                 /* update pot/encoder */
596                 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
597         }
598 }
599
600 void
601 Strip::notify_panner_azi_changed (bool force_update)
602 {
603         if (!_stripable) {
604                 return;
605         }
606
607         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
608
609         boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
610
611         if (!pan_control) {
612                 /* basically impossible, since we're here because that control
613                  *  changed, but sure, whatever.
614                  */
615                 return;
616         }
617
618         if (_vpot->control() != pan_control) {
619                 return;
620         }
621
622         double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
623         double internal_pos = pan_control->get_value();
624
625         if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
626
627                 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
628                 /* show actual internal value to user */
629                 do_parameter_display (PanAzimuthAutomation, internal_pos);
630
631                 _last_pan_azi_position_written = normalized_pos;
632         }
633 }
634
635 void
636 Strip::notify_panner_width_changed (bool force_update)
637 {
638         if (!_stripable) {
639                 return;
640         }
641
642         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
643
644         boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_width_control ();
645
646         if (!pan_control) {
647                 /* basically impossible, since we're here because that control
648                  *  changed, but sure, whatever.
649                  */
650                 return;
651         }
652
653         if (_vpot->control() != pan_control) {
654                 return;
655         }
656
657         double pos = pan_control->internal_to_interface (pan_control->get_value());
658
659         if (force_update || pos != _last_pan_width_position_written) {
660
661                 _surface->write (_vpot->set (pos, true, Pot::spread));
662                 do_parameter_display (PanWidthAutomation, pos);
663
664                 _last_pan_width_position_written = pos;
665         }
666 }
667
668 void
669 Strip::select_event (Button&, ButtonState bs)
670 {
671         DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
672
673         if (bs == press) {
674
675                 int ms = _surface->mcp().main_modifier_state();
676
677                 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
678                         _controls_locked = !_controls_locked;
679                         _surface->write (display (1,_controls_locked ?  "Locked" : "Unlock"));
680                         block_vpot_mode_display_for (1000);
681                         return;
682                 }
683
684                 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
685                 _surface->mcp().add_down_select_button (_surface->number(), _index);
686                 _surface->mcp().select_range ();
687
688         } else {
689                 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
690                 _surface->mcp().remove_down_select_button (_surface->number(), _index);
691         }
692 }
693
694 void
695 Strip::vselect_event (Button&, ButtonState bs)
696 {
697         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
698
699                 /* most subview modes: vpot press acts like a button for toggle parameters */
700
701                 if (bs != press) {
702                         return;
703                 }
704
705                 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
706
707                         boost::shared_ptr<AutomationControl> control = _vpot->control ();
708                         if (!control) {
709                                 return;
710                         }
711
712                         Controllable::GroupControlDisposition gcd;
713                         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
714                                 gcd = Controllable::InverseGroup;
715                         } else {
716                                 gcd = Controllable::UseGroup;
717                         }
718
719                         if (control->toggled()) {
720                                 if (control->toggled()) {
721                                         control->set_value (!control->get_value(), gcd);
722                                 }
723
724                         } else if (control->desc().enumeration || control->desc().integer_step) {
725
726                                 double val = control->get_value ();
727                                 if (val <= control->upper() - 1.0) {
728                                         control->set_value (val + 1.0, gcd);
729                                 } else {
730                                         control->set_value (control->lower(), gcd);
731                                 }
732                         }
733
734                 } else {
735
736                         /* Send mode: press enables/disables the relevant
737                          * send, but the vpot is bound to the send-level so we
738                          * need to lookup the enable/disable control
739                          * explicitly.
740                          */
741
742                         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
743
744                         if (r) {
745
746                                 const uint32_t global_pos = _surface->mcp().global_index (*this);
747                                 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
748
749                                 if (control) {
750                                         bool currently_enabled = (bool) control->get_value();
751                                         Controllable::GroupControlDisposition gcd;
752
753                                         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
754                                                 gcd = Controllable::InverseGroup;
755                                         } else {
756                                                 gcd = Controllable::UseGroup;
757                                         }
758
759                                         control->set_value (!currently_enabled, gcd);
760
761                                         if (currently_enabled) {
762                                                 /* we just turned it off */
763                                                 pending_display[1] = "off";
764                                         } else {
765                                                 /* we just turned it on, show the level
766                                                 */
767                                                 control = _stripable->send_level_controllable (global_pos);
768                                                 do_parameter_display (BusSendLevel, control->get_value());
769                                         }
770                                 }
771                         }
772                 }
773
774                 /* done with this event in subview mode */
775
776                 return;
777         }
778
779         if (bs == press) {
780
781                 int ms = _surface->mcp().main_modifier_state();
782
783                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
784
785                         boost::shared_ptr<AutomationControl> ac = _vpot->control ();
786
787                         if (ac) {
788
789                                 /* reset to default/normal value */
790                                 ac->set_value (ac->normal(), Controllable::NoGroup);
791                         }
792
793                 }  else {
794
795 #ifdef MIXBUS
796                         if (_stripable) {
797                                 boost::shared_ptr<AutomationControl> ac = _stripable->master_send_enable_controllable ();
798                                 if (ac) {
799                                         Controllable::GroupControlDisposition gcd;
800
801                                         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
802                                                 gcd = Controllable::InverseGroup;
803                                         } else {
804                                                 gcd = Controllable::UseGroup;
805                                         }
806
807                                         bool enabled = ac->get_value();
808                                         ac->set_value (!enabled, gcd);
809                                 }
810                         }
811 #else
812                         DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
813                         /* switch vpot to control next available parameter */
814                         next_pot_mode ();
815 #endif
816                 }
817
818         }
819 }
820
821 void
822 Strip::fader_touch_event (Button&, ButtonState bs)
823 {
824         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
825
826         if (bs == press) {
827
828                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
829
830                 _fader->set_in_use (true);
831                 _fader->start_touch (_surface->mcp().transport_frame());
832
833                 if (ac) {
834                         do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
835                 }
836
837         } else {
838
839                 _fader->set_in_use (false);
840                 _fader->stop_touch (_surface->mcp().transport_frame(), true);
841
842         }
843 }
844
845
846 void
847 Strip::handle_button (Button& button, ButtonState bs)
848 {
849         boost::shared_ptr<AutomationControl> control;
850
851         if (bs == press) {
852                 button.set_in_use (true);
853         } else {
854                 button.set_in_use (false);
855         }
856
857         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
858
859         switch (button.bid()) {
860         case Button::Select:
861                 select_event (button, bs);
862                 break;
863
864         case Button::VSelect:
865                 vselect_event (button, bs);
866                 break;
867
868         case Button::FaderTouch:
869                 fader_touch_event (button, bs);
870                 break;
871
872         default:
873                 if ((control = button.control ())) {
874                         if (bs == press) {
875                                 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
876                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
877
878                                 float new_value = control->get_value() ? 0.0 : 1.0;
879
880                                 /* get all controls that either have their
881                                  * button down or are within a range of
882                                  * several down buttons
883                                  */
884
885                                 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
886
887
888                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
889                                                                             controls.size(), control->parameter().type(), new_value));
890
891                                 /* apply change, with potential modifier semantics */
892
893                                 Controllable::GroupControlDisposition gcd;
894
895                                 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
896                                         gcd = Controllable::InverseGroup;
897                                 } else {
898                                         gcd = Controllable::UseGroup;
899                                 }
900
901                                 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
902                                         (*c)->set_value (new_value, gcd);
903                                 }
904
905                         } else {
906                                 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
907                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
908                         }
909                 }
910                 break;
911         }
912 }
913
914 void
915 Strip::do_parameter_display (AutomationType type, float val)
916 {
917         bool screen_hold = false;
918         char buf[16];
919
920         switch (type) {
921         case GainAutomation:
922                 if (val == 0.0) {
923                         pending_display[1] = " -inf ";
924                 } else {
925                         float dB = accurate_coefficient_to_dB (val);
926                         snprintf (buf, sizeof (buf), "%6.1f", dB);
927                         pending_display[1] = buf;
928                         screen_hold = true;
929                 }
930                 break;
931
932         case BusSendLevel:
933                 if (Profile->get_mixbus()) {  //Mixbus sends are already stored in dB
934                         snprintf (buf, sizeof (buf), "%2.1f", val);
935                         pending_display[1] = buf;
936                         screen_hold = true;
937                 } else {
938                         if (val == 0.0) {
939                                 pending_display[1] = " -inf ";
940                         } else {
941                                 float dB = accurate_coefficient_to_dB (val);
942                                 snprintf (buf, sizeof (buf), "%6.1f", dB);
943                                 pending_display[1] = buf;
944                                 screen_hold = true;
945                         }
946                 }
947                 break;
948
949         case PanAzimuthAutomation:
950                 if (Profile->get_mixbus()) {
951                         snprintf (buf, sizeof (buf), "%2.1f", val);
952                         pending_display[1] = buf;
953                         screen_hold = true;
954                 } else {
955                         if (_stripable) {
956                                 boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
957                                 if (pa) {
958                                         pending_display[1] = pa->get_user_string ();
959                                         screen_hold = true;
960                                 }
961                         }
962                 }
963                 break;
964
965         case PanWidthAutomation:
966                 if (_stripable) {
967                         snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
968                         pending_display[1] = buf;
969                         screen_hold = true;
970                 }
971                 break;
972
973         case TrimAutomation:
974                 if (_stripable) {
975                         float dB = accurate_coefficient_to_dB (val);
976                         snprintf (buf, sizeof (buf), "%6.1f", dB);
977                         pending_display[1] = buf;
978                         screen_hold = true;
979                 }
980                 break;
981
982         case PhaseAutomation:
983                 if (_stripable) {
984                         if (val < 0.5) {
985                                 pending_display[1] = "Normal";
986                         } else {
987                                 pending_display[1] = "Invert";
988                         }
989                         screen_hold = true;
990                 }
991                 break;
992
993         case EQGain:
994         case EQFrequency:
995         case EQQ:
996         case EQShape:
997         case EQHPF:
998         case CompThreshold:
999         case CompSpeed:
1000         case CompMakeup:
1001         case CompRedux:
1002                 snprintf (buf, sizeof (buf), "%6.1f", val);
1003                 pending_display[1] = buf;
1004                 screen_hold = true;
1005                 break;
1006         case EQEnable:
1007         case CompEnable:
1008                 if (val >= 0.5) {
1009                         pending_display[1] = "on";
1010                 } else {
1011                         pending_display[1] = "off";
1012                 }
1013                 break;
1014         case CompMode:
1015                 if (_surface->mcp().subview_stripable()) {
1016                         pending_display[1] = _surface->mcp().subview_stripable()->comp_mode_name (val);
1017                 }
1018                 break;
1019         case SoloSafeAutomation:
1020         case SoloIsolateAutomation:
1021                 if (val >= 0.5) {
1022                         pending_display[1] = "on";
1023                 } else {
1024                         pending_display[1] = "off";
1025                 }
1026                 break;
1027         case MonitoringAutomation:
1028                 switch (MonitorChoice ((int) val)) {
1029                 case MonitorAuto:
1030                         pending_display[1] = "auto";
1031                         break;
1032                 case MonitorInput:
1033                         pending_display[1] = "input";
1034                         break;
1035                 case MonitorDisk:
1036                         pending_display[1] = "disk";
1037                         break;
1038                 case MonitorCue: /* XXX not implemented as of jan 2016 */
1039                         pending_display[1] = "cue";
1040                         break;
1041                 }
1042                 break;
1043         default:
1044                 break;
1045         }
1046
1047         if (screen_hold) {
1048                 /* we just queued up a parameter to be displayed.
1049                    1 second from now, switch back to vpot mode display.
1050                 */
1051                 block_vpot_mode_display_for (1000);
1052         }
1053 }
1054
1055 void
1056 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1057 {
1058         if (touch_on) {
1059                 fader.start_touch (_surface->mcp().transport_frame());
1060         } else {
1061                 fader.stop_touch (_surface->mcp().transport_frame(), false);
1062         }
1063 }
1064
1065 void
1066 Strip::handle_fader (Fader& fader, float position)
1067 {
1068         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1069         boost::shared_ptr<AutomationControl> ac = fader.control();
1070         if (!ac) {
1071                 return;
1072         }
1073
1074         Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1075
1076         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1077                 gcd = Controllable::InverseGroup;
1078         }
1079
1080         fader.set_value (position, gcd);
1081
1082         /* From the Mackie Control MIDI implementation docs:
1083
1084            In order to ensure absolute synchronization with the host software,
1085            Mackie Control uses a closed-loop servo system for the faders,
1086            meaning the faders will always move to their last received position.
1087            When a host receives a Fader Position Message, it must then
1088            re-transmit that message to the Mackie Control or else the faders
1089            will return to their last position.
1090         */
1091
1092         _surface->write (fader.set_position (position));
1093 }
1094
1095 void
1096 Strip::handle_pot (Pot& pot, float delta)
1097 {
1098         /* Pots only emit events when they move, not when they
1099            stop moving. So to get a stop event, we need to use a timeout.
1100         */
1101
1102         boost::shared_ptr<AutomationControl> ac = pot.control();
1103         if (!ac) {
1104                 return;
1105         }
1106
1107         Controllable::GroupControlDisposition gcd;
1108
1109         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1110                 gcd = Controllable::InverseGroup;
1111         } else {
1112                 gcd = Controllable::UseGroup;
1113         }
1114
1115         if (ac->toggled()) {
1116
1117                 /* make it like a single-step, directional switch */
1118
1119                 if (delta > 0) {
1120                         ac->set_value (1.0, gcd);
1121                 } else {
1122                         ac->set_value (0.0, gcd);
1123                 }
1124
1125         } else if (ac->desc().enumeration || ac->desc().integer_step) {
1126
1127                 /* use Controllable::get_value() to avoid the
1128                  * "scaling-to-interface" that takes place in
1129                  * Control::get_value() via the pot member.
1130                  *
1131                  * an enumeration with 4 values will have interface values of
1132                  * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1133                  * deal with that.
1134                  */
1135
1136                 if (delta > 0) {
1137                         ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1138                 } else {
1139                         ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1140                 }
1141
1142         } else {
1143
1144                 double p = ac->get_interface();
1145
1146                 p += delta;
1147
1148                 p = max (0.0, p);
1149                 p = min (1.0, p);
1150
1151                 ac->set_value ( ac->interface_to_internal(p), gcd);
1152         }
1153 }
1154
1155 void
1156 Strip::periodic (ARDOUR::microseconds_t now)
1157 {
1158         update_meter ();
1159         update_automation ();
1160 }
1161
1162 void
1163 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1164 {
1165         if (_block_screen_redisplay_until >= now) {
1166                 /* no drawing allowed */
1167                 return;
1168         }
1169
1170         if (_block_screen_redisplay_until) {
1171                 /* we were blocked, but the time period has elapsed, so we must
1172                  * force a redraw.
1173                  */
1174                 force = true;
1175                 _block_screen_redisplay_until = 0;
1176         }
1177
1178         if (force || (current_display[0] != pending_display[0])) {
1179                 _surface->write (display (0, pending_display[0]));
1180                 current_display[0] = pending_display[0];
1181         }
1182
1183         if (return_to_vpot_mode_display_at <= now) {
1184                 return_to_vpot_mode_display_at = UINT64_MAX;
1185                 return_to_vpot_mode_display ();
1186         }
1187
1188         if (force || (current_display[1] != pending_display[1])) {
1189                 _surface->write (display (1, pending_display[1]));
1190                 current_display[1] = pending_display[1];
1191         }
1192 }
1193
1194 void
1195 Strip::update_automation ()
1196 {
1197         if (!_stripable) {
1198                 return;
1199         }
1200
1201         ARDOUR::AutoState state = _stripable->gain_control()->automation_state();
1202
1203         if (state == Touch || state == Play) {
1204                 notify_gain_changed (false);
1205         }
1206
1207         boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
1208         if (pan_control) {
1209                 state = pan_control->automation_state ();
1210                 if (state == Touch || state == Play) {
1211                         notify_panner_azi_changed (false);
1212                 }
1213         }
1214
1215         pan_control = _stripable->pan_width_control ();
1216         if (pan_control) {
1217                 state = pan_control->automation_state ();
1218                 if (state == Touch || state == Play) {
1219                         notify_panner_width_changed (false);
1220                 }
1221         }
1222 }
1223
1224 void
1225 Strip::update_meter ()
1226 {
1227         if (!_stripable) {
1228                 return;
1229         }
1230
1231         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1232                 return;
1233         }
1234
1235         if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
1236                 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
1237                 _meter->send_update (*_surface, dB);
1238                 return;
1239         }
1240 }
1241
1242 void
1243 Strip::zero ()
1244 {
1245         for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1246                 _surface->write ((*it)->zero ());
1247         }
1248
1249         _surface->write (blank_display (0));
1250         _surface->write (blank_display (1));
1251         pending_display[0] = string();
1252         pending_display[1] = string();
1253         current_display[0] = string();
1254         current_display[1] = string();
1255 }
1256
1257 MidiByteArray
1258 Strip::blank_display (uint32_t line_number)
1259 {
1260         return display (line_number, string());
1261 }
1262
1263 MidiByteArray
1264 Strip::display (uint32_t line_number, const std::string& line)
1265 {
1266         assert (line_number <= 1);
1267
1268         MidiByteArray retval;
1269
1270         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1271
1272         // sysex header
1273         retval << _surface->sysex_hdr();
1274
1275         // code for display
1276         retval << 0x12;
1277         // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1278         retval << (_index * 7 + (line_number * 0x38));
1279
1280         // ascii data to display. @param line is UTF-8
1281         string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1282         string::size_type len = ascii.length();
1283         if (len > 6) {
1284                 ascii = ascii.substr (0, 6);
1285                 len = 6;
1286         }
1287         retval << ascii;
1288         // pad with " " out to 6 chars
1289         for (int i = len; i < 6; ++i) {
1290                 retval << ' ';
1291         }
1292
1293         // column spacer, unless it's the right-hand column
1294         if (_index < 7) {
1295                 retval << ' ';
1296         }
1297
1298         // sysex trailer
1299         retval << MIDI::eox;
1300
1301         return retval;
1302 }
1303
1304 void
1305 Strip::lock_controls ()
1306 {
1307         _controls_locked = true;
1308 }
1309
1310 void
1311 Strip::unlock_controls ()
1312 {
1313         _controls_locked = false;
1314 }
1315
1316 void
1317 Strip::gui_selection_changed (const ARDOUR::StrongStripableNotificationList& rl)
1318 {
1319         for (ARDOUR::StrongStripableNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1320                 if ((*i) == _stripable) {
1321                         _surface->write (_select->set_state (on));
1322                         return;
1323                 }
1324         }
1325
1326         _surface->write (_select->set_state (off));
1327 }
1328
1329 string
1330 Strip::vpot_mode_string ()
1331 {
1332         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1333                 return string();
1334         }
1335
1336         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1337
1338         if (!ac) {
1339                 return string();
1340         }
1341
1342         switch (ac->desc().type) {
1343         case PanAzimuthAutomation:
1344                 return "Pan";
1345         case PanWidthAutomation:
1346                 return "Width";
1347         case PanElevationAutomation:
1348                 return "Elev";
1349         case PanFrontBackAutomation:
1350                 return "F/Rear";
1351         case PanLFEAutomation:
1352                 return "LFE";
1353         default:
1354                 break;
1355         }
1356
1357         return "???";
1358 }
1359
1360 void
1361 Strip::flip_mode_changed ()
1362 {
1363         if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1364
1365                 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1366                 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1367
1368                 if (pot_control && fader_control) {
1369                         _vpot->set_control (fader_control);
1370                         _fader->set_control (pot_control);
1371                 }
1372
1373                 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1374                         do_parameter_display (GainAutomation, fader_control->get_value());
1375                 } else {
1376                         do_parameter_display (BusSendLevel, fader_control->get_value());
1377                 }
1378
1379                 /* update fader */
1380
1381                 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1382
1383                 /* update pot */
1384
1385                 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1386
1387
1388         } else {
1389                 /* do nothing */
1390         }
1391 }
1392
1393 void
1394 Strip::block_screen_display_for (uint32_t msecs)
1395 {
1396         _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1397 }
1398
1399 void
1400 Strip::block_vpot_mode_display_for (uint32_t msecs)
1401 {
1402         return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1403 }
1404
1405 void
1406 Strip::return_to_vpot_mode_display ()
1407 {
1408         /* returns the second line of the two-line per-strip display
1409            back the mode where it shows what the VPot controls.
1410         */
1411
1412         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1413                 /* do nothing - second line shows value of current subview parameter */
1414                 return;
1415         } else if (_stripable) {
1416                 pending_display[1] = vpot_mode_string();
1417         } else {
1418                 pending_display[1] = string();
1419         }
1420 }
1421
1422 void
1423 Strip::next_pot_mode ()
1424 {
1425         vector<AutomationType>::iterator i;
1426
1427         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1428                 /* do not change vpot mode while in flipped mode */
1429                 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1430                 pending_display[1] = "Flip";
1431                 block_vpot_mode_display_for (1000);
1432                 return;
1433         }
1434
1435
1436         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1437
1438         if (!ac) {
1439                 return;
1440         }
1441
1442
1443         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1444                 return;
1445         }
1446
1447         if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1448                 return;
1449         }
1450
1451         for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1452                 if ((*i) == ac->parameter().type()) {
1453                         break;
1454                 }
1455         }
1456
1457         /* move to the next mode in the list, or back to the start (which will
1458            also happen if the current mode is not in the current pot mode list)
1459         */
1460
1461         if (i != possible_pot_parameters.end()) {
1462                 ++i;
1463         }
1464
1465         if (i == possible_pot_parameters.end()) {
1466                 i = possible_pot_parameters.begin();
1467         }
1468
1469         set_vpot_parameter (*i);
1470 }
1471
1472 void
1473 Strip::subview_mode_changed ()
1474 {
1475         boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
1476
1477         subview_connections.drop_connections ();
1478
1479         switch (_surface->mcp().subview_mode()) {
1480         case MackieControlProtocol::None:
1481                 set_vpot_parameter (_pan_mode);
1482                 /* need to show strip name again */
1483                 show_stripable_name ();
1484                 if (!_stripable) {
1485                         _surface->write (_vpot->set (0, true, Pot::wrap));
1486                         _surface->write (_fader->set_position (0.0));
1487                 }
1488                 notify_metering_state_changed ();
1489                 eq_band = -1;
1490                 break;
1491
1492         case MackieControlProtocol::EQ:
1493                 if (r) {
1494                         setup_eq_vpot (r);
1495                 } else {
1496                         /* leave it as it was */
1497                 }
1498                 break;
1499
1500         case MackieControlProtocol::Dynamics:
1501                 if (r) {
1502                         setup_dyn_vpot (r);
1503                 } else {
1504                         /* leave it as it was */
1505                 }
1506                 eq_band = -1;
1507                 break;
1508
1509         case MackieControlProtocol::Sends:
1510                 if (r) {
1511                         setup_sends_vpot (r);
1512                 } else {
1513                         /* leave it as it was */
1514                 }
1515                 eq_band = -1;
1516                 break;
1517         case MackieControlProtocol::TrackView:
1518                 if (r) {
1519                         setup_trackview_vpot (r);
1520                 } else {
1521                         /* leave it as it was */
1522                 }
1523                 eq_band = -1;
1524                 break;
1525         }
1526 }
1527
1528 void
1529 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
1530 {
1531         if (!r) {
1532                 return;
1533         }
1534
1535         boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1536         boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1537         boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1538         boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1539         boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1540         boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1541
1542         uint32_t pos = _surface->mcp().global_index (*this);
1543
1544         /* we will control the pos-th available parameter, from the list in the
1545          * order shown above.
1546          */
1547
1548         vector<boost::shared_ptr<AutomationControl> > available;
1549         vector<AutomationType> params;
1550
1551         if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1552         if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1553         if (mc) { available.push_back (mc); params.push_back (CompMode); }
1554         if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1555         if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1556         if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1557
1558         if (pos >= available.size()) {
1559                 /* this knob is not needed to control the available parameters */
1560                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1561                 pending_display[0] = string();
1562                 pending_display[1] = string();
1563                 return;
1564         }
1565
1566         boost::shared_ptr<AutomationControl> pc;
1567         AutomationType param;
1568
1569         pc = available[pos];
1570         param = params[pos];
1571
1572         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1573         _vpot->set_control (pc);
1574
1575         string pot_id;
1576
1577         switch (param) {
1578         case CompThreshold:
1579                 pot_id = "Thresh";
1580                 break;
1581         case CompSpeed:
1582                 if (mc) {
1583                         pot_id = r->comp_speed_name (mc->get_value());
1584                 } else {
1585                         pot_id = "Speed";
1586                 }
1587                 break;
1588         case CompMode:
1589                 pot_id = "Mode";
1590                 break;
1591         case CompMakeup:
1592                 pot_id = "Makeup";
1593                 break;
1594         case CompRedux:
1595                 pot_id = "Redux";
1596                 break;
1597         case CompEnable:
1598                 pot_id = "on/off";
1599                 break;
1600         default:
1601                 break;
1602         }
1603
1604         if (!pot_id.empty()) {
1605                 pending_display[0] = pot_id;
1606         } else {
1607                 pending_display[0] = string();
1608         }
1609
1610         notify_dyn_change (param, true, false);
1611 }
1612
1613 void
1614 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
1615 {
1616         uint32_t bands = r->eq_band_cnt ();
1617
1618         if (bands == 0) {
1619                 /* should never get here */
1620                 return;
1621         }
1622
1623         /* figure out how many params per band are available */
1624
1625         boost::shared_ptr<AutomationControl> pc;
1626         uint32_t params_per_band = 0;
1627
1628         if ((pc = r->eq_gain_controllable (0))) {
1629                 params_per_band += 1;
1630         }
1631         if ((pc = r->eq_freq_controllable (0))) {
1632                 params_per_band += 1;
1633         }
1634         if ((pc = r->eq_q_controllable (0))) {
1635                 params_per_band += 1;
1636         }
1637         if ((pc = r->eq_shape_controllable (0))) {
1638                 params_per_band += 1;
1639         }
1640
1641         /* pick the one for this strip, based on its global position across
1642          * all surfaces
1643          */
1644
1645         pc.reset ();
1646
1647         const uint32_t total_band_parameters = bands * params_per_band;
1648         const uint32_t global_pos = _surface->mcp().global_index (*this);
1649         AutomationType param = NullAutomation;
1650         string band_name;
1651
1652         eq_band = -1;
1653
1654         if (global_pos < total_band_parameters) {
1655
1656                 /* show a parameter for an EQ band */
1657
1658                 const uint32_t parameter = global_pos % params_per_band;
1659                 eq_band = global_pos / params_per_band;
1660                 band_name = r->eq_band_name (eq_band);
1661
1662                 switch (parameter) {
1663                 case 0:
1664                         pc = r->eq_gain_controllable (eq_band);
1665                         param = EQGain;
1666                         break;
1667                 case 1:
1668                         pc = r->eq_freq_controllable (eq_band);
1669                         param = EQFrequency;
1670                         break;
1671                 case 2:
1672                         pc = r->eq_q_controllable (eq_band);
1673                         param = EQQ;
1674                         break;
1675                 case 3:
1676                         pc = r->eq_shape_controllable (eq_band);
1677                         param = EQShape;
1678                         break;
1679                 }
1680
1681         } else {
1682
1683                 /* show a non-band parameter (HPF or enable)
1684                  */
1685
1686                 uint32_t parameter = global_pos - total_band_parameters;
1687
1688                 switch (parameter) {
1689                 case 0: /* first control after band parameters */
1690                         pc = r->eq_hpf_controllable();
1691                         param = EQHPF;
1692                         break;
1693                 case 1: /* second control after band parameters */
1694                         pc = r->eq_enable_controllable();
1695                         param = EQEnable;
1696                         break;
1697                 default:
1698                         /* nothing to control */
1699                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1700                         pending_display[0] = string();
1701                         pending_display[1] = string();
1702                         /* done */
1703                         return;
1704                         break;
1705                 }
1706
1707         }
1708
1709         if (pc) {
1710                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1711                 _vpot->set_control (pc);
1712
1713                 string pot_id;
1714
1715                 switch (param) {
1716                 case EQGain:
1717                         pot_id = band_name + "Gain";
1718                         break;
1719                 case EQFrequency:
1720                         pot_id = band_name + "Freq";
1721                         break;
1722                 case EQQ:
1723                         pot_id = band_name + " Q";
1724                         break;
1725                 case EQShape:
1726                         pot_id = band_name + " Shp";
1727                         break;
1728                 case EQHPF:
1729                         pot_id = "HPFreq";
1730                         break;
1731                 case EQEnable:
1732                         pot_id = "on/off";
1733                         break;
1734                 default:
1735                         break;
1736                 }
1737
1738                 if (!pot_id.empty()) {
1739                         pending_display[0] = pot_id;
1740                 } else {
1741                         pending_display[0] = string();
1742                 }
1743
1744                 notify_eq_change (param, eq_band, true);
1745         }
1746 }
1747
1748 void
1749 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1750 {
1751         if (!r) {
1752                 return;
1753         }
1754
1755         const uint32_t global_pos = _surface->mcp().global_index (*this);
1756
1757         boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1758
1759         if (!pc) {
1760                 pending_display[0] = string();
1761                 pending_display[1] = string();
1762                 return;
1763         }
1764
1765         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1766         _vpot->set_control (pc);
1767
1768         pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1769
1770         notify_send_level_change (BusSendLevel, global_pos, true);
1771 }
1772
1773 void
1774 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1775 {
1776         if (!r) {
1777                 return;
1778         }
1779
1780         const uint32_t global_pos = _surface->mcp().global_index (*this);
1781
1782         if (global_pos >= 8) {
1783                 pending_display[0] = string();
1784                 pending_display[1] = string();
1785                 return;
1786         }
1787
1788         boost::shared_ptr<AutomationControl> pc;
1789         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1790         string label;
1791
1792         switch (global_pos) {
1793         case 0:
1794                 pc = r->trim_control ();
1795                 if (pc) {
1796                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1797                         pending_display[0] = "Trim";
1798                         notify_trackview_change (TrimAutomation, global_pos, true);
1799                 }
1800                 break;
1801         case 1:
1802                 if (track) {
1803                         pc = track->monitoring_control();
1804                         if (pc) {
1805                                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1806                                 pending_display[0] = "Mon";
1807                                 notify_trackview_change (MonitoringAutomation, global_pos, true);
1808                         }
1809                 }
1810                 break;
1811         case 2:
1812                 pc = r->solo_isolate_control ();
1813                 if (pc) {
1814                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1815                         notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1816                         pending_display[0] = "S-Iso";
1817                 }
1818                 break;
1819         case 3:
1820                 pc = r->solo_safe_control ();
1821                 if (pc) {
1822                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1823                         notify_trackview_change (SoloSafeAutomation, global_pos, true);
1824                         pending_display[0] = "S-Safe";
1825                 }
1826                 break;
1827         case 4:
1828                 pc = r->phase_control();
1829                 if (pc) {
1830                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1831                         notify_trackview_change (PhaseAutomation, global_pos, true);
1832                         pending_display[0] = "Phase";
1833                 }
1834                 break;
1835         case 5:
1836                 // pc = r->trim_control ();
1837                 break;
1838         case 6:
1839                 // pc = r->trim_control ();
1840                 break;
1841         case 7:
1842                 // pc = r->trim_control ();
1843                 break;
1844         }
1845
1846         if (!pc) {
1847                 pending_display[0] = string();
1848                 pending_display[1] = string();
1849                 return;
1850         }
1851
1852         _vpot->set_control (pc);
1853 }
1854
1855 void
1856 Strip::set_vpot_parameter (AutomationType p)
1857 {
1858         if (!_stripable || (p == NullAutomation)) {
1859                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1860                 pending_display[1] = string();
1861                 return;
1862         }
1863
1864         boost::shared_ptr<AutomationControl> pan_control;
1865
1866         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1867
1868         reset_saved_values ();
1869
1870         switch (p) {
1871         case PanAzimuthAutomation:
1872                 pan_control = _stripable->pan_azimuth_control ();
1873                 break;
1874         case PanWidthAutomation:
1875                 pan_control = _stripable->pan_width_control ();
1876                 break;
1877         case PanElevationAutomation:
1878                 break;
1879         case PanFrontBackAutomation:
1880                 break;
1881         case PanLFEAutomation:
1882                 break;
1883         default:
1884                 return;
1885         }
1886
1887         if (pan_control) {
1888                 _pan_mode = p;
1889                 _vpot->set_control (pan_control);
1890         }
1891
1892         pending_display[1] = vpot_mode_string ();
1893 }
1894
1895 bool
1896 Strip::is_midi_track () const
1897 {
1898         return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1899 }
1900
1901 void
1902 Strip::reset_saved_values ()
1903 {
1904         _last_pan_azi_position_written = -1.0;
1905         _last_pan_width_position_written = -1.0;
1906         _last_gain_position_written = -1.0;
1907         _last_trim_position_written = -1.0;
1908
1909 }
1910
1911 void
1912 Strip::notify_metering_state_changed()
1913 {
1914         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1915                 return;
1916         }
1917
1918         if (!_stripable || !_meter) {
1919                 return;
1920         }
1921
1922         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1923         bool metering_active = _surface->mcp().metering_active ();
1924
1925         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1926                 return;
1927         }
1928
1929         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1930
1931         if (!transport_is_rolling || !metering_active) {
1932                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1933                 notify_panner_azi_changed (true);
1934         }
1935
1936         _transport_is_rolling = transport_is_rolling;
1937         _metering_active = metering_active;
1938 }