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