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