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