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