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