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