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