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