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