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