e7f928f02f9e04134f9dcb09c451e70c03327285
[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), gcd);
1236                 } else {
1237                         ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1238                 }
1239
1240         } else {
1241
1242                 double p = ac->get_value();
1243
1244                 p += delta;
1245
1246                 p = max (ac->lower(), p);
1247                 p = min (ac->upper(), p);
1248
1249                 ac->set_value (p, gcd);
1250         }
1251 }
1252
1253 void
1254 Strip::periodic (ARDOUR::microseconds_t now)
1255 {
1256         update_meter ();
1257         update_automation ();
1258 }
1259
1260 void
1261 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1262 {
1263         if (_block_screen_redisplay_until >= now) {
1264                 /* no drawing allowed */
1265                 return;
1266         }
1267
1268         if (_block_screen_redisplay_until) {
1269                 /* we were blocked, but the time period has elapsed, so we must
1270                  * force a redraw.
1271                  */
1272                 force = true;
1273                 _block_screen_redisplay_until = 0;
1274         }
1275
1276         if (force || (current_display[0] != pending_display[0])) {
1277                 _surface->write (display (0, pending_display[0]));
1278                 current_display[0] = pending_display[0];
1279         }
1280
1281         if (return_to_vpot_mode_display_at <= now) {
1282                 return_to_vpot_mode_display_at = UINT64_MAX;
1283                 return_to_vpot_mode_display ();
1284         }
1285
1286         if (force || (current_display[1] != pending_display[1])) {
1287                 _surface->write (display (1, pending_display[1]));
1288                 current_display[1] = pending_display[1];
1289         }
1290 }
1291
1292 void
1293 Strip::update_automation ()
1294 {
1295         if (!_route) {
1296                 return;
1297         }
1298
1299         ARDOUR::AutoState state = _route->gain_control()->automation_state();
1300
1301         if (state == Touch || state == Play) {
1302                 notify_gain_changed (false);
1303         }
1304
1305         boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1306         if (pan_control) {
1307                 state = pan_control->automation_state ();
1308                 if (state == Touch || state == Play) {
1309                         notify_panner_azi_changed (false);
1310                 }
1311         }
1312
1313         pan_control = _route->pan_width_control ();
1314         if (pan_control) {
1315                 state = pan_control->automation_state ();
1316                 if (state == Touch || state == Play) {
1317                         notify_panner_width_changed (false);
1318                 }
1319         }
1320
1321         if (_route->trim() && route()->trim()->active()) {
1322                 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1323                 if (trim_state == Touch || trim_state == Play) {
1324                         notify_trim_changed (false);
1325                 }
1326         }
1327 }
1328
1329 void
1330 Strip::update_meter ()
1331 {
1332         if (!_route) {
1333                 return;
1334         }
1335
1336         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1337                 return;
1338         }
1339
1340         if (_meter && _transport_is_rolling && _metering_active) {
1341                 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1342                 _meter->send_update (*_surface, dB);
1343                 return;
1344         }
1345 }
1346
1347 void
1348 Strip::zero ()
1349 {
1350         for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1351                 _surface->write ((*it)->zero ());
1352         }
1353
1354         _surface->write (blank_display (0));
1355         _surface->write (blank_display (1));
1356         pending_display[0] = string();
1357         pending_display[1] = string();
1358         current_display[0] = string();
1359         current_display[1] = string();
1360 }
1361
1362 MidiByteArray
1363 Strip::blank_display (uint32_t line_number)
1364 {
1365         return display (line_number, string());
1366 }
1367
1368 MidiByteArray
1369 Strip::display (uint32_t line_number, const std::string& line)
1370 {
1371         assert (line_number <= 1);
1372
1373         MidiByteArray retval;
1374
1375         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1376
1377         // sysex header
1378         retval << _surface->sysex_hdr();
1379
1380         // code for display
1381         retval << 0x12;
1382         // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1383         retval << (_index * 7 + (line_number * 0x38));
1384
1385         // ascii data to display. @param line is UTF-8
1386         string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1387         string::size_type len = ascii.length();
1388         if (len > 6) {
1389                 ascii = ascii.substr (0, 6);
1390                 len = 6;
1391         }
1392         retval << ascii;
1393         // pad with " " out to 6 chars
1394         for (int i = len; i < 6; ++i) {
1395                 retval << ' ';
1396         }
1397
1398         // column spacer, unless it's the right-hand column
1399         if (_index < 7) {
1400                 retval << ' ';
1401         }
1402
1403         // sysex trailer
1404         retval << MIDI::eox;
1405
1406         return retval;
1407 }
1408
1409 void
1410 Strip::lock_controls ()
1411 {
1412         _controls_locked = true;
1413 }
1414
1415 void
1416 Strip::unlock_controls ()
1417 {
1418         _controls_locked = false;
1419 }
1420
1421 void
1422 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1423 {
1424         for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1425                 if ((*i) == _route) {
1426                         _surface->write (_select->set_state (on));
1427                         return;
1428                 }
1429         }
1430
1431         _surface->write (_select->set_state (off));
1432 }
1433
1434 string
1435 Strip::vpot_mode_string ()
1436 {
1437         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1438         if (!ac) {
1439                 return string();
1440         }
1441
1442         if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1443                 return "Fader";
1444         } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1445                 return "Trim";
1446         } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1447                 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1448         } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1449                 return "Pan";
1450         } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1451                 return "Width";
1452         } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1453                 return "Elev";
1454         } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1455                 return "F/Rear";
1456         } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1457                 return "LFE";
1458         }
1459
1460         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1461                 return string();
1462         }
1463
1464         return "???";
1465 }
1466
1467  void
1468 Strip::potmode_changed (bool notify)
1469 {
1470         if (!_route) {
1471                 return;
1472         }
1473
1474         // WIP
1475         int pm = _surface->mcp().pot_mode();
1476         switch (pm) {
1477         case MackieControlProtocol::Pan:
1478                 // This needs to set current pan mode (azimuth or width... or whatever)
1479                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1480                 set_vpot_parameter (_pan_mode);
1481                 break;
1482         }
1483
1484         if (notify) {
1485                 notify_all ();
1486         }
1487 }
1488
1489 void
1490 Strip::block_screen_display_for (uint32_t msecs)
1491 {
1492         _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1493 }
1494
1495 void
1496 Strip::block_vpot_mode_display_for (uint32_t msecs)
1497 {
1498         return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1499 }
1500
1501 void
1502 Strip::return_to_vpot_mode_display ()
1503 {
1504         /* returns the second line of the two-line per-strip display
1505            back the mode where it shows what the VPot controls.
1506         */
1507
1508         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1509                 /* do nothing - second line shows value of current subview parameter */
1510                 return;
1511         } else if (_route) {
1512                 pending_display[1] = vpot_mode_string();
1513         } else {
1514                 pending_display[1] = string();
1515         }
1516 }
1517
1518 void
1519 Strip::next_pot_mode ()
1520 {
1521         vector<AutomationType>::iterator i;
1522
1523         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1524                 /* do not change vpot mode while in flipped mode */
1525                 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1526                 pending_display[1] = "Flip";
1527                 block_vpot_mode_display_for (1000);
1528                 return;
1529         }
1530
1531
1532         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1533
1534         if (!ac) {
1535                 return;
1536         }
1537
1538
1539         if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1540
1541                 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1542                         return;
1543                 }
1544
1545                 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1546                         if ((*i) == ac->parameter().type()) {
1547                                 break;
1548                         }
1549                 }
1550
1551                 /* move to the next mode in the list, or back to the start (which will
1552                 also happen if the current mode is not in the current pot mode list)
1553                 */
1554
1555                 if (i != possible_pot_parameters.end()) {
1556                         ++i;
1557                 }
1558
1559                 if (i == possible_pot_parameters.end()) {
1560                         i = possible_pot_parameters.begin();
1561                 }
1562
1563                 set_vpot_parameter (*i);
1564         }
1565 }
1566
1567 void
1568 Strip::subview_mode_changed ()
1569 {
1570         boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1571
1572         subview_connections.drop_connections ();
1573
1574         switch (_surface->mcp().subview_mode()) {
1575         case MackieControlProtocol::None:
1576                 set_vpot_parameter (vpot_parameter);
1577                 /* need to show strip name again */
1578                 show_route_name ();
1579                 notify_metering_state_changed ();
1580                 eq_band = -1;
1581                 break;
1582
1583         case MackieControlProtocol::EQ:
1584                 if (r) {
1585                         setup_eq_vpot (r);
1586                 } else {
1587                         /* leave it as it was */
1588                 }
1589                 break;
1590
1591         case MackieControlProtocol::Dynamics:
1592                 if (r) {
1593                         setup_dyn_vpot (r);
1594                 } else {
1595                         /* leave it as it was */
1596                 }
1597                 eq_band = -1;
1598                 break;
1599
1600         case MackieControlProtocol::Sends:
1601                 if (r) {
1602                         setup_sends_vpot (r);
1603                 } else {
1604                         /* leave it as it was */
1605                 }
1606                 eq_band = -1;
1607                 break;
1608         case MackieControlProtocol::TrackView:
1609                 if (r) {
1610                         setup_trackview_vpot (r);
1611                 } else {
1612                         /* leave it as it was */
1613                 }
1614                 eq_band = -1;
1615                 break;
1616         }
1617 }
1618
1619 void
1620 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1621 {
1622         if (!r) {
1623                 return;
1624         }
1625
1626         boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1627         boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1628         boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1629         boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1630         boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1631         boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1632
1633         uint32_t pos = _surface->mcp().global_index (*this);
1634
1635         /* we will control the pos-th available parameter, from the list in the
1636          * order shown above.
1637          */
1638
1639         vector<boost::shared_ptr<AutomationControl> > available;
1640         vector<AutomationType> params;
1641
1642         if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1643         if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1644         if (mc) { available.push_back (mc); params.push_back (CompMode); }
1645         if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1646         if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1647         if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1648
1649         if (pos >= available.size()) {
1650                 /* this knob is not needed to control the available parameters */
1651                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1652                 pending_display[0] = string();
1653                 pending_display[1] = string();
1654                 return;
1655         }
1656
1657         boost::shared_ptr<AutomationControl> pc;
1658         AutomationType param;
1659
1660         pc = available[pos];
1661         param = params[pos];
1662
1663         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1664         _vpot->set_control (pc);
1665
1666         string pot_id;
1667
1668         switch (param) {
1669         case CompThreshold:
1670                 pot_id = "Thresh";
1671                 break;
1672         case CompSpeed:
1673                 if (mc) {
1674                         pot_id = r->comp_speed_name (mc->get_value());
1675                 } else {
1676                         pot_id = "Speed";
1677                 }
1678                 break;
1679         case CompMode:
1680                 pot_id = "Mode";
1681                 break;
1682         case CompMakeup:
1683                 pot_id = "Makeup";
1684                 break;
1685         case CompRedux:
1686                 pot_id = "Redux";
1687                 break;
1688         case CompEnable:
1689                 pot_id = "on/off";
1690                 break;
1691         default:
1692                 break;
1693         }
1694
1695         if (!pot_id.empty()) {
1696                 pending_display[0] = pot_id;
1697         } else {
1698                 pending_display[0] = string();
1699         }
1700
1701         notify_dyn_change (param, true, false);
1702 }
1703
1704 void
1705 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1706 {
1707         uint32_t bands = r->eq_band_cnt ();
1708
1709         if (bands == 0) {
1710                 /* should never get here */
1711                 return;
1712         }
1713
1714         /* figure out how many params per band are available */
1715
1716         boost::shared_ptr<AutomationControl> pc;
1717         uint32_t params_per_band = 0;
1718
1719         if ((pc = r->eq_gain_controllable (0))) {
1720                 params_per_band += 1;
1721         }
1722         if ((pc = r->eq_freq_controllable (0))) {
1723                 params_per_band += 1;
1724         }
1725         if ((pc = r->eq_q_controllable (0))) {
1726                 params_per_band += 1;
1727         }
1728         if ((pc = r->eq_shape_controllable (0))) {
1729                 params_per_band += 1;
1730         }
1731
1732         /* pick the one for this strip, based on its global position across
1733          * all surfaces
1734          */
1735
1736         pc.reset ();
1737
1738         const uint32_t total_band_parameters = bands * params_per_band;
1739         const uint32_t global_pos = _surface->mcp().global_index (*this);
1740         AutomationType param = NullAutomation;
1741         string band_name;
1742
1743         eq_band = -1;
1744
1745         if (global_pos < total_band_parameters) {
1746
1747                 /* show a parameter for an EQ band */
1748
1749                 const uint32_t parameter = global_pos % params_per_band;
1750                 eq_band = global_pos / params_per_band;
1751                 band_name = r->eq_band_name (eq_band);
1752
1753                 switch (parameter) {
1754                 case 0:
1755                         pc = r->eq_gain_controllable (eq_band);
1756                         param = EQGain;
1757                         break;
1758                 case 1:
1759                         pc = r->eq_freq_controllable (eq_band);
1760                         param = EQFrequency;
1761                         break;
1762                 case 2:
1763                         pc = r->eq_q_controllable (eq_band);
1764                         param = EQQ;
1765                         break;
1766                 case 3:
1767                         pc = r->eq_shape_controllable (eq_band);
1768                         param = EQShape;
1769                         break;
1770                 }
1771
1772         } else {
1773
1774                 /* show a non-band parameter (HPF or enable)
1775                  */
1776
1777                 uint32_t parameter = global_pos - total_band_parameters;
1778
1779                 switch (parameter) {
1780                 case 0: /* first control after band parameters */
1781                         pc = r->eq_hpf_controllable();
1782                         param = EQHPF;
1783                         break;
1784                 case 1: /* second control after band parameters */
1785                         pc = r->eq_enable_controllable();
1786                         param = EQEnable;
1787                         break;
1788                 default:
1789                         /* nothing to control */
1790                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1791                         pending_display[0] = string();
1792                         pending_display[1] = string();
1793                         /* done */
1794                         return;
1795                         break;
1796                 }
1797
1798         }
1799
1800         if (pc) {
1801                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1802                 _vpot->set_control (pc);
1803
1804                 string pot_id;
1805
1806                 switch (param) {
1807                 case EQGain:
1808                         pot_id = band_name + "Gain";
1809                         break;
1810                 case EQFrequency:
1811                         pot_id = band_name + "Freq";
1812                         break;
1813                 case EQQ:
1814                         pot_id = band_name + " Q";
1815                         break;
1816                 case EQShape:
1817                         pot_id = band_name + " Shp";
1818                         break;
1819                 case EQHPF:
1820                         pot_id = "HPFreq";
1821                         break;
1822                 case EQEnable:
1823                         pot_id = "on/off";
1824                         break;
1825                 default:
1826                         break;
1827                 }
1828
1829                 if (!pot_id.empty()) {
1830                         pending_display[0] = pot_id;
1831                 } else {
1832                         pending_display[0] = string();
1833                 }
1834
1835                 notify_eq_change (param, eq_band, true);
1836         }
1837 }
1838
1839 void
1840 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1841 {
1842         if (!r) {
1843                 return;
1844         }
1845
1846         const uint32_t global_pos = _surface->mcp().global_index (*this);
1847
1848         boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1849
1850         if (!pc) {
1851                 pending_display[0] = string();
1852                 pending_display[1] = string();
1853                 return;
1854         }
1855
1856         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1857         _vpot->set_control (pc);
1858
1859         pending_display[0] = r->send_name (global_pos);
1860
1861         notify_send_level_change (BusSendLevel, global_pos, true);
1862 }
1863
1864 void
1865 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1866 {
1867         if (!r) {
1868                 return;
1869         }
1870
1871         const uint32_t global_pos = _surface->mcp().global_index (*this);
1872
1873         if (global_pos >= 8) {
1874                 pending_display[0] = string();
1875                 pending_display[1] = string();
1876                 return;
1877         }
1878
1879         boost::shared_ptr<AutomationControl> pc;
1880         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1881         string label;
1882
1883         switch (global_pos) {
1884         case 0:
1885                 pc = r->trim_control ();
1886                 if (pc) {
1887                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1888                         pending_display[0] = "Trim";
1889                         notify_trackview_change (TrimAutomation, global_pos, true);
1890                 }
1891                 break;
1892         case 1:
1893                 if (track) {
1894                         pc = track->monitoring_control();
1895                         if (pc) {
1896                                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1897                                 pending_display[0] = "Mon";
1898                                 notify_trackview_change (MonitoringAutomation, global_pos, true);
1899                         }
1900                 }
1901                 break;
1902         case 2:
1903                 pc = r->solo_isolate_control ();
1904                 if (pc) {
1905                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1906                         notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1907                         pending_display[0] = "S-Iso";
1908                 }
1909                 break;
1910         case 3:
1911                 pc = r->solo_safe_control ();
1912                 if (pc) {
1913                         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1914                         notify_trackview_change (SoloSafeAutomation, global_pos, true);
1915                         pending_display[0] = "S-Safe";
1916                 }
1917                 break;
1918         case 4:
1919                 //pc = r->trim_control ();
1920                 break;
1921         case 5:
1922                 // pc = r->trim_control ();
1923                 break;
1924         case 6:
1925                 // pc = r->trim_control ();
1926                 break;
1927         case 7:
1928                 // pc = r->trim_control ();
1929                 break;
1930         }
1931
1932         if (!pc) {
1933                 pending_display[0] = string();
1934                 pending_display[1] = string();
1935                 return;
1936         }
1937
1938         _vpot->set_control (pc);
1939 }
1940
1941 void
1942 Strip::set_vpot_parameter (AutomationType p)
1943 {
1944         if (!_route || (p == NullAutomation)) {
1945                 control_by_parameter[vpot_parameter] = 0;
1946                 vpot_parameter = NullAutomation;
1947                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1948                 pending_display[1] = string();
1949                 return;
1950         }
1951
1952         boost::shared_ptr<AutomationControl> pan_control;
1953
1954         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1955
1956         reset_saved_values ();
1957
1958         /* unset any mapping between the vpot and any existing parameters */
1959
1960         for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1961
1962                 if (i != control_by_parameter.end() && i->second == _vpot) {
1963                         i->second = 0;
1964                 }
1965         }
1966
1967         switch (p) {
1968         case PanAzimuthAutomation:
1969                 if ((pan_control = _route->pan_azimuth_control ())) {
1970                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1971                                 _pan_mode = PanAzimuthAutomation;
1972                                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1973                                         /* gain to vpot, pan azi to fader */
1974                                         _vpot->set_control (_route->gain_control());
1975                                         vpot_parameter = GainAutomation;
1976                                         control_by_parameter[GainAutomation] = _vpot;
1977                                         _fader->set_control (pan_control);
1978                                         control_by_parameter[PanAzimuthAutomation] = _fader;
1979                                 } else {
1980                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1981                                         control_by_parameter[PanAzimuthAutomation] = 0;
1982                                 }
1983                         } else {
1984                                 /* gain to fader, pan azi to vpot */
1985                                 vpot_parameter = PanAzimuthAutomation;
1986                                 _fader->set_control (_route->gain_control());
1987                                 control_by_parameter[GainAutomation] = _fader;
1988                                 _vpot->set_control (pan_control);
1989                                 control_by_parameter[PanAzimuthAutomation] = _vpot;
1990                         }
1991                 } else {
1992                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1993                         control_by_parameter[PanAzimuthAutomation] = 0;
1994                 }
1995                 break;
1996
1997         case PanWidthAutomation:
1998                 if ((pan_control = _route->pan_width_control ())) {
1999                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
2000                                 _pan_mode = PanWidthAutomation;
2001                                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
2002                                         /* gain to vpot, pan width to fader */
2003                                         _vpot->set_control (_route->gain_control());
2004                                         vpot_parameter = GainAutomation;
2005                                         control_by_parameter[GainAutomation] = _vpot;
2006                                         _fader->set_control (pan_control);
2007                                         control_by_parameter[PanWidthAutomation] = _fader;
2008                                 } else {
2009                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
2010                                         control_by_parameter[PanWidthAutomation] = 0;
2011                                 }
2012                         } else {
2013                                 /* gain to fader, pan width to vpot */
2014                                 vpot_parameter = PanWidthAutomation;
2015                                 _fader->set_control (_route->gain_control());
2016                                 control_by_parameter[GainAutomation] = _fader;
2017                                 _vpot->set_control (pan_control);
2018                                 control_by_parameter[PanWidthAutomation] = _vpot;
2019                         }
2020                 } else {
2021                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
2022                         control_by_parameter[PanWidthAutomation] = 0;
2023                 }
2024                 break;
2025
2026         case PanElevationAutomation:
2027                 break;
2028         case PanFrontBackAutomation:
2029                 break;
2030         case PanLFEAutomation:
2031                 break;
2032         case TrimAutomation:
2033                 _trim_mode = TrimAutomation;
2034                 vpot_parameter = TrimAutomation;
2035                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
2036                         /* gain to vpot, trim to fader */
2037                         _vpot->set_control (_route->gain_control());
2038                         control_by_parameter[GainAutomation] = _vpot;
2039                         if (_route->trim() && route()->trim()->active()) {
2040                                 _fader->set_control (_route->trim_control());
2041                                 control_by_parameter[TrimAutomation] = _fader;
2042                         } else {
2043                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
2044                                 control_by_parameter[TrimAutomation] = 0;
2045                         }
2046                 } else {
2047                         /* gain to fader, trim to vpot */
2048                         _fader->set_control (_route->gain_control());
2049                         control_by_parameter[GainAutomation] = _fader;
2050                         if (_route->trim() && route()->trim()->active()) {
2051                                 _vpot->set_control (_route->trim_control());
2052                                 control_by_parameter[TrimAutomation] = _vpot;
2053                         } else {
2054                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
2055                                 control_by_parameter[TrimAutomation] = 0;
2056                         }
2057                 }
2058                 break;
2059         case PhaseAutomation:
2060                 _trim_mode = PhaseAutomation;
2061                 vpot_parameter = PhaseAutomation;
2062                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
2063                         /* gain to vpot, phase to fader */
2064                         _vpot->set_control (_route->gain_control());
2065                         control_by_parameter[GainAutomation] = _vpot;
2066                         if (_route->phase_invert().size()) {
2067                                 _fader->set_control (_route->phase_control());
2068                                 control_by_parameter[PhaseAutomation] = _fader;
2069                         } else {
2070                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
2071                                 control_by_parameter[PhaseAutomation] = 0;
2072                         }
2073                 } else {
2074                         /* gain to fader, phase to vpot */
2075                         _fader->set_control (_route->gain_control());
2076                         control_by_parameter[GainAutomation] = _fader;
2077                         if (_route->phase_invert().size()) {
2078                                 _vpot->set_control (_route->phase_control());
2079                                 control_by_parameter[PhaseAutomation] = _vpot;
2080                         } else {
2081                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
2082                                 control_by_parameter[PhaseAutomation] = 0;
2083                         }
2084                 }
2085                 break;
2086         default:
2087                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
2088                 break;
2089
2090         }
2091
2092         pending_display[1] = vpot_mode_string ();
2093 }
2094
2095 bool
2096 Strip::is_midi_track () const
2097 {
2098         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
2099 }
2100
2101 void
2102 Strip::reset_saved_values ()
2103 {
2104         _last_pan_azi_position_written = -1.0;
2105         _last_pan_width_position_written = -1.0;
2106         _last_gain_position_written = -1.0;
2107         _last_trim_position_written = -1.0;
2108
2109 }
2110
2111 void
2112 Strip::notify_metering_state_changed()
2113 {
2114         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
2115                 return;
2116         }
2117
2118         if (!_route || !_meter) {
2119                 return;
2120         }
2121
2122         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
2123         bool metering_active = _surface->mcp().metering_active ();
2124
2125         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
2126                 return;
2127         }
2128
2129         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
2130
2131         if (!transport_is_rolling || !metering_active) {
2132                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
2133                 notify_panner_azi_changed (true);
2134         }
2135
2136         _transport_is_rolling = transport_is_rolling;
2137         _metering_active = metering_active;
2138 }