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