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