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