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