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