d7f37da571e32cf08eca8ddfb1575ce465e34338
[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 EQ 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, control->internal_to_interface (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_eq_change (AutomationType type, uint32_t band, 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::EQ) {
535                 /* no longer in EQ subview mode */
536                 return;
537         }
538
539         boost::shared_ptr<AutomationControl> control;
540
541         switch (type) {
542         case EQGain:
543                 control = r->eq_gain_controllable (band);
544                 break;
545         case EQFrequency:
546                 control = r->eq_freq_controllable (band);
547                 break;
548         case EQQ:
549                 control = r->eq_q_controllable (band);
550                 break;
551         case EQShape:
552                 control = r->eq_shape_controllable (band);
553                 break;
554         case EQHPF:
555                 control = r->eq_hpf_controllable ();
556                 break;
557         case EQEnable:
558                 control = r->eq_enable_controllable ();
559                 break;
560         default:
561                 break;
562         }
563
564         if (control) {
565                 float val = control->get_value();
566                 do_parameter_display (type, val);
567                 /* update pot/encoder */
568                 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
569         }
570 }
571
572 void
573 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
574 {
575         boost::shared_ptr<Route> r = _surface->mcp().subview_route();
576
577         if (!r) {
578                 /* not in subview mode */
579                 return;
580         }
581
582         if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
583                 /* no longer in EQ subview mode */
584                 return;
585         }
586
587         boost::shared_ptr<AutomationControl> control;
588         bool reset_all = false;
589
590         switch (type) {
591         case CompThreshold:
592                 control = r->comp_threshold_controllable ();
593                 break;
594         case CompSpeed:
595                 control = r->comp_speed_controllable ();
596                 break;
597         case CompMode:
598                 control = r->comp_mode_controllable ();
599                 reset_all = true;
600                 break;
601         case CompMakeup:
602                 control = r->comp_makeup_controllable ();
603                 break;
604         case CompRedux:
605                 control = r->comp_redux_controllable ();
606                 break;
607         case CompEnable:
608                 control = r->comp_enable_controllable ();
609                 break;
610         default:
611                 break;
612         }
613
614         if (propagate_mode && reset_all) {
615                 _surface->subview_mode_changed ();
616         }
617
618         if (control) {
619                 float val = control->get_value();
620                 do_parameter_display (type, val);
621                 /* update pot/encoder */
622                 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
623         }
624 }
625
626 void
627 Strip::notify_panner_azi_changed (bool force_update)
628 {
629         if (!_route) {
630                 return;
631         }
632
633         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
634
635         boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
636
637         if (!pan_control) {
638                 return;
639         }
640
641         Control* control = 0;
642         ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
643
644         if (i == control_by_parameter.end()) {
645                 return;
646         }
647
648         control = i->second;
649
650         double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
651         double internal_pos = pan_control->get_value();
652
653         if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
654
655                 if (control == _fader) {
656                         if (!_fader->in_use()) {
657                                 _surface->write (_fader->set_position (normalized_pos));
658                                 /* show actual internal value to user */
659                                 do_parameter_display (PanAzimuthAutomation, internal_pos);
660                         }
661                 } else if (control == _vpot) {
662                         _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
663                         /* show actual internal value to user */
664                         do_parameter_display (PanAzimuthAutomation, internal_pos);
665                 }
666
667                 _last_pan_azi_position_written = normalized_pos;
668         }
669 }
670
671 void
672 Strip::notify_panner_width_changed (bool force_update)
673 {
674         if (!_route) {
675                 return;
676         }
677
678         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
679
680         boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
681
682         if (!pan_control) {
683                 return;
684         }
685
686         Control* control = 0;
687         ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
688
689         if (i == control_by_parameter.end()) {
690                 return;
691         }
692
693         control = i->second;
694
695         double pos = pan_control->internal_to_interface (pan_control->get_value());
696
697         if (force_update || pos != _last_pan_width_position_written) {
698
699                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
700
701                         if (control == _fader) {
702                                 if (!control->in_use()) {
703                                         _surface->write (_fader->set_position (pos));
704                                         do_parameter_display (PanWidthAutomation, pos);
705                                 }
706                         }
707
708                 } else if (control == _vpot) {
709                         _surface->write (_vpot->set (pos, true, Pot::spread));
710                         do_parameter_display (PanWidthAutomation, pos);
711                 }
712
713                 _last_pan_width_position_written = pos;
714         }
715 }
716
717 void
718 Strip::select_event (Button&, ButtonState bs)
719 {
720         DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
721
722         if (bs == press) {
723
724                 int ms = _surface->mcp().main_modifier_state();
725
726                 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
727                         _controls_locked = !_controls_locked;
728                         _surface->write (display (1,_controls_locked ?  "Locked" : "Unlock"));
729                         block_vpot_mode_display_for (1000);
730                         return;
731                 }
732
733                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
734                         /* reset to default */
735                         boost::shared_ptr<AutomationControl> ac = _fader->control ();
736                         if (ac) {
737                                 ac->set_value (ac->normal(), Controllable::NoGroup);
738                         }
739                         return;
740                 }
741
742                 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
743                 _surface->mcp().add_down_select_button (_surface->number(), _index);
744                 _surface->mcp().select_range ();
745
746         } else {
747                 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
748                 _surface->mcp().remove_down_select_button (_surface->number(), _index);
749         }
750 }
751
752 void
753 Strip::vselect_event (Button&, ButtonState bs)
754 {
755         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
756
757                 /* most subview modes: vpot press acts like a button for toggle parameters */
758
759                 if (bs != press) {
760                         return;
761                 }
762
763                 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
764
765                         boost::shared_ptr<AutomationControl> control = _vpot->control ();
766                         if (!control) {
767                                 return;
768                         }
769
770                         if (control->toggled()) {
771                                 if (control->toggled()) {
772                                         control->set_value (!control->get_value(), Controllable::NoGroup);
773                                 }
774                         }
775                 } else {
776
777                         /* Send mode: press enables/disables the relevant send */
778
779                         boost::shared_ptr<Route> r = _surface->mcp().subview_route();
780
781                         if (r) {
782
783                                 const uint32_t global_pos = _surface->mcp().global_index (*this);
784                                 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
785
786                                 if (control) {
787                                         bool currently_enabled = (bool) control->get_value();
788                                         control->set_value (!currently_enabled, Controllable::UseGroup);
789
790                                         if (currently_enabled) {
791                                                 /* we just turned it off */
792                                                 pending_display[1] = "off";
793                                         } else {
794                                                 /* we just turned it on, show the level
795                                                 */
796                                                 control = _route->send_level_controllable (global_pos);
797                                                 do_parameter_display (BusSendLevel, control->get_value());
798                                         }
799                                 }
800                         }
801                 }
802
803                 /* done with this event in subview mode */
804
805                 return;
806         }
807
808         if (bs == press) {
809
810                 int ms = _surface->mcp().main_modifier_state();
811
812                 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
813
814                         boost::shared_ptr<AutomationControl> ac = _vpot->control ();
815
816                         if (ac) {
817
818                                 /* reset to default/normal value */
819                                 ac->set_value (ac->normal(), Controllable::NoGroup);
820                         }
821
822                 }  else {
823
824 #ifdef MIXBUS
825                         if (_route) {
826                                 boost::shared_ptr<AutomationControl> ac = _route->master_send_enable_controllable ();
827                                 if (ac) {
828                                         bool enabled = ac->get_value();
829                                         ac->set_value (!enabled, Controllable::UseGroup);
830                                 }
831 #else
832                         DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
833                         next_pot_mode ();
834 #endif
835                 }
836
837         }
838 }
839
840 void
841 Strip::fader_touch_event (Button&, ButtonState bs)
842 {
843         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
844
845         if (bs == press) {
846
847                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
848
849                 _fader->set_in_use (true);
850                 _fader->start_touch (_surface->mcp().transport_frame());
851
852                 if (ac) {
853                         do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
854                 }
855
856         } else {
857
858                 _fader->set_in_use (false);
859                 _fader->stop_touch (_surface->mcp().transport_frame(), true);
860
861         }
862 }
863
864
865 void
866 Strip::handle_button (Button& button, ButtonState bs)
867 {
868         boost::shared_ptr<AutomationControl> control;
869
870         if (bs == press) {
871                 button.set_in_use (true);
872         } else {
873                 button.set_in_use (false);
874         }
875
876         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
877
878         switch (button.bid()) {
879         case Button::Select:
880                 select_event (button, bs);
881                 break;
882
883         case Button::VSelect:
884                 vselect_event (button, bs);
885                 break;
886
887         case Button::FaderTouch:
888                 fader_touch_event (button, bs);
889                 break;
890
891         default:
892                 if ((control = button.control ())) {
893                         if (bs == press) {
894                                 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
895                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
896
897                                 float new_value = control->get_value() ? 0.0 : 1.0;
898
899                                 /* get all controls that either have their
900                                  * button down or are within a range of
901                                  * several down buttons
902                                  */
903
904                                 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
905
906
907                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
908                                                                             controls.size(), control->parameter().type(), new_value));
909
910                                 /* apply change, with potential modifier semantics */
911
912                                 Controllable::GroupControlDisposition gcd;
913
914                                 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
915                                         gcd = Controllable::NoGroup;
916                                 } else {
917                                         gcd = Controllable::UseGroup;
918                                 }
919
920                                 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
921                                         (*c)->set_value (new_value, gcd);
922                                 }
923
924                         } else {
925                                 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
926                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
927                         }
928                 }
929                 break;
930         }
931 }
932
933 void
934 Strip::do_parameter_display (AutomationType type, float val)
935 {
936         bool screen_hold = false;
937         char buf[16];
938
939         switch (type) {
940         case GainAutomation:
941                 if (val == 0.0) {
942                         pending_display[1] = " -inf ";
943                 } else {
944                         float dB = accurate_coefficient_to_dB (val);
945                         snprintf (buf, sizeof (buf), "%6.1f", dB);
946                         pending_display[1] = buf;
947                         screen_hold = true;
948                 }
949                 break;
950
951         case PanAzimuthAutomation:
952                 if (Profile->get_mixbus()) {
953                         snprintf (buf, sizeof (buf), "%2.1f", val);
954                         pending_display[1] = buf;
955                         screen_hold = true;
956                 } else {
957                         if (_route) {
958                                 boost::shared_ptr<Pannable> p = _route->pannable();
959                                 if (p && _route->panner()) {
960                                         pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
961                                         screen_hold = true;
962                                 }
963                         }
964                 }
965                 break;
966
967         case PanWidthAutomation:
968                 if (_route) {
969                         snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
970                         pending_display[1] = buf;
971                         screen_hold = true;
972                 }
973                 break;
974
975         case TrimAutomation:
976                 if (_route) {
977                         float dB = accurate_coefficient_to_dB (val);
978                         snprintf (buf, sizeof (buf), "%6.1f", dB);
979                         pending_display[1] = buf;
980                         screen_hold = true;
981                 }
982                 break;
983
984         case PhaseAutomation:
985                 if (_route) {
986                         if (_route->phase_control()->get_value() < 0.5) {
987                                 pending_display[1] = "Normal";
988                         } else {
989                                 pending_display[1] = "Invert";
990                         }
991                         screen_hold = true;
992                 }
993                 break;
994
995         case BusSendLevel:
996                 if (_route) {
997                         float dB = accurate_coefficient_to_dB (val);
998                         snprintf (buf, sizeof (buf), "%6.1f", dB);
999                         pending_display[1] = buf;
1000                         screen_hold = true;
1001                 }
1002                 break;
1003
1004         case EQGain:
1005         case EQFrequency:
1006         case EQQ:
1007         case EQShape:
1008         case EQHPF:
1009         case CompThreshold:
1010         case CompSpeed:
1011         case CompMakeup:
1012         case CompRedux:
1013                 snprintf (buf, sizeof (buf), "%6.1f", val);
1014                 pending_display[1] = buf;
1015                 screen_hold = true;
1016                 break;
1017         case EQEnable:
1018         case CompEnable:
1019                 if (val >= 0.5) {
1020                         pending_display[1] = "on";
1021                 } else {
1022                         pending_display[1] = "off";
1023                 }
1024                 break;
1025         case CompMode:
1026                 if (_surface->mcp().subview_route()) {
1027                         pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1028                 }
1029                 break;
1030         default:
1031                 break;
1032         }
1033
1034         if (screen_hold) {
1035                 /* we just queued up a parameter to be displayed.
1036                    1 second from now, switch back to vpot mode display.
1037                 */
1038                 block_vpot_mode_display_for (1000);
1039         }
1040 }
1041
1042 void
1043 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1044 {
1045         if (touch_on) {
1046                 fader.start_touch (_surface->mcp().transport_frame());
1047         } else {
1048                 fader.stop_touch (_surface->mcp().transport_frame(), false);
1049         }
1050 }
1051
1052 void
1053 Strip::handle_fader (Fader& fader, float position)
1054 {
1055         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1056         boost::shared_ptr<AutomationControl> ac = fader.control();
1057         if (!ac) {
1058                 return;
1059         }
1060
1061         Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1062
1063         if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1064                 gcd = Controllable::NoGroup;
1065         }
1066
1067         fader.set_value (position, gcd);
1068
1069         /* From the Mackie Control MIDI implementation docs:
1070
1071            In order to ensure absolute synchronization with the host software,
1072            Mackie Control uses a closed-loop servo system for the faders,
1073            meaning the faders will always move to their last received position.
1074            When a host receives a Fader Position Message, it must then
1075            re-transmit that message to the Mackie Control or else the faders
1076            will return to their last position.
1077         */
1078
1079         _surface->write (fader.set_position (position));
1080 }
1081
1082 void
1083 Strip::handle_pot (Pot& pot, float delta)
1084 {
1085         /* Pots only emit events when they move, not when they
1086            stop moving. So to get a stop event, we need to use a timeout.
1087         */
1088
1089         boost::shared_ptr<AutomationControl> ac = pot.control();
1090         if (!ac) {
1091                 return;
1092         }
1093         double p = pot.get_value ();
1094         p += delta;
1095         // fader and pot should be the same and fader is hard coded 0 -> 1
1096         p = max (0.0, p);
1097         p = min (1.0, p);
1098         pot.set_value (p);
1099 }
1100
1101 void
1102 Strip::periodic (ARDOUR::microseconds_t now)
1103 {
1104         update_meter ();
1105         update_automation ();
1106 }
1107
1108 void
1109 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1110 {
1111         if (_block_screen_redisplay_until >= now) {
1112                 /* no drawing allowed */
1113                 return;
1114         }
1115
1116         if (_block_screen_redisplay_until) {
1117                 /* we were blocked, but the time period has elapsed, so we must
1118                  * force a redraw.
1119                  */
1120                 force = true;
1121                 _block_screen_redisplay_until = 0;
1122         }
1123
1124         if (force || (current_display[0] != pending_display[0])) {
1125                 _surface->write (display (0, pending_display[0]));
1126                 current_display[0] = pending_display[0];
1127         }
1128
1129         if (return_to_vpot_mode_display_at <= now) {
1130                 return_to_vpot_mode_display_at = UINT64_MAX;
1131                 return_to_vpot_mode_display ();
1132         }
1133
1134         if (force || (current_display[1] != pending_display[1])) {
1135                 _surface->write (display (1, pending_display[1]));
1136                 current_display[1] = pending_display[1];
1137         }
1138 }
1139
1140 void
1141 Strip::update_automation ()
1142 {
1143         if (!_route) {
1144                 return;
1145         }
1146
1147         ARDOUR::AutoState state = _route->gain_control()->automation_state();
1148
1149         if (state == Touch || state == Play) {
1150                 notify_gain_changed (false);
1151         }
1152
1153         boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1154         if (pan_control) {
1155                 state = pan_control->automation_state ();
1156                 if (state == Touch || state == Play) {
1157                         notify_panner_azi_changed (false);
1158                 }
1159         }
1160
1161         pan_control = _route->pan_width_control ();
1162         if (pan_control) {
1163                 state = pan_control->automation_state ();
1164                 if (state == Touch || state == Play) {
1165                         notify_panner_width_changed (false);
1166                 }
1167         }
1168
1169         if (_route->trim() && route()->trim()->active()) {
1170                 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1171                 if (trim_state == Touch || trim_state == Play) {
1172                         notify_trim_changed (false);
1173                 }
1174         }
1175 }
1176
1177 void
1178 Strip::update_meter ()
1179 {
1180         if (!_route) {
1181                 return;
1182         }
1183
1184         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1185                 return;
1186         }
1187
1188         if (_meter && _transport_is_rolling && _metering_active) {
1189                 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1190                 _meter->send_update (*_surface, dB);
1191                 return;
1192         }
1193 }
1194
1195 void
1196 Strip::zero ()
1197 {
1198         for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1199                 _surface->write ((*it)->zero ());
1200         }
1201
1202         _surface->write (blank_display (0));
1203         _surface->write (blank_display (1));
1204         pending_display[0] = string();
1205         pending_display[1] = string();
1206         current_display[0] = string();
1207         current_display[1] = string();
1208 }
1209
1210 MidiByteArray
1211 Strip::blank_display (uint32_t line_number)
1212 {
1213         return display (line_number, string());
1214 }
1215
1216 MidiByteArray
1217 Strip::display (uint32_t line_number, const std::string& line)
1218 {
1219         assert (line_number <= 1);
1220
1221         MidiByteArray retval;
1222
1223         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1224
1225         // sysex header
1226         retval << _surface->sysex_hdr();
1227
1228         // code for display
1229         retval << 0x12;
1230         // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1231         retval << (_index * 7 + (line_number * 0x38));
1232
1233         // ascii data to display. @param line is UTF-8
1234         string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1235         string::size_type len = ascii.length();
1236         if (len > 6) {
1237                 ascii = ascii.substr (0, 6);
1238                 len = 6;
1239         }
1240         retval << ascii;
1241         // pad with " " out to 6 chars
1242         for (int i = len; i < 6; ++i) {
1243                 retval << ' ';
1244         }
1245
1246         // column spacer, unless it's the right-hand column
1247         if (_index < 7) {
1248                 retval << ' ';
1249         }
1250
1251         // sysex trailer
1252         retval << MIDI::eox;
1253
1254         return retval;
1255 }
1256
1257 void
1258 Strip::lock_controls ()
1259 {
1260         _controls_locked = true;
1261 }
1262
1263 void
1264 Strip::unlock_controls ()
1265 {
1266         _controls_locked = false;
1267 }
1268
1269 void
1270 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1271 {
1272         for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1273                 if ((*i) == _route) {
1274                         _surface->write (_select->set_state (on));
1275                         return;
1276                 }
1277         }
1278
1279         _surface->write (_select->set_state (off));
1280 }
1281
1282 string
1283 Strip::vpot_mode_string ()
1284 {
1285         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1286         if (!ac) {
1287                 return string();
1288         }
1289
1290         if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1291                 return "Fader";
1292         } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1293                 return "Trim";
1294         } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1295                 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1296         } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1297                 return "Pan";
1298         } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1299                 return "Width";
1300         } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1301                 return "Elev";
1302         } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1303                 return "F/Rear";
1304         } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1305                 return "LFE";
1306         }
1307
1308         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1309                 return string();
1310         }
1311
1312         return "???";
1313 }
1314
1315  void
1316 Strip::potmode_changed (bool notify)
1317 {
1318         if (!_route) {
1319                 return;
1320         }
1321
1322         // WIP
1323         int pm = _surface->mcp().pot_mode();
1324         switch (pm) {
1325         case MackieControlProtocol::Pan:
1326                 // This needs to set current pan mode (azimuth or width... or whatever)
1327                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1328                 set_vpot_parameter (_pan_mode);
1329                 break;
1330         }
1331
1332         if (notify) {
1333                 notify_all ();
1334         }
1335 }
1336
1337 void
1338 Strip::block_screen_display_for (uint32_t msecs)
1339 {
1340         _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1341 }
1342
1343 void
1344 Strip::block_vpot_mode_display_for (uint32_t msecs)
1345 {
1346         return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1347 }
1348
1349 void
1350 Strip::return_to_vpot_mode_display ()
1351 {
1352         /* returns the second line of the two-line per-strip display
1353            back the mode where it shows what the VPot controls.
1354         */
1355
1356         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1357                 /* do nothing - second line shows value of current subview parameter */
1358                 return;
1359         } else if (_route) {
1360                 pending_display[1] = vpot_mode_string();
1361         } else {
1362                 pending_display[1] = string();
1363         }
1364 }
1365
1366 void
1367 Strip::next_pot_mode ()
1368 {
1369         vector<AutomationType>::iterator i;
1370
1371         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1372                 /* do not change vpot mode while in flipped mode */
1373                 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1374                 pending_display[1] = "Flip";
1375                 block_vpot_mode_display_for (1000);
1376                 return;
1377         }
1378
1379
1380         boost::shared_ptr<AutomationControl> ac = _vpot->control();
1381
1382         if (!ac) {
1383                 return;
1384         }
1385
1386
1387         if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1388
1389                 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1390                         return;
1391                 }
1392
1393                 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1394                         if ((*i) == ac->parameter().type()) {
1395                                 break;
1396                         }
1397                 }
1398
1399                 /* move to the next mode in the list, or back to the start (which will
1400                 also happen if the current mode is not in the current pot mode list)
1401                 */
1402
1403                 if (i != possible_pot_parameters.end()) {
1404                         ++i;
1405                 }
1406
1407                 if (i == possible_pot_parameters.end()) {
1408                         i = possible_pot_parameters.begin();
1409                 }
1410
1411                 set_vpot_parameter (*i);
1412         }
1413 }
1414
1415 void
1416 Strip::subview_mode_changed ()
1417 {
1418         boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1419
1420         subview_connections.drop_connections ();
1421
1422         switch (_surface->mcp().subview_mode()) {
1423         case MackieControlProtocol::None:
1424                 set_vpot_parameter (vpot_parameter);
1425                 /* need to show strip name again */
1426                 show_route_name ();
1427                 notify_metering_state_changed ();
1428                 eq_band = -1;
1429                 break;
1430
1431         case MackieControlProtocol::EQ:
1432                 if (r) {
1433                         setup_eq_vpot (r);
1434                 } else {
1435                         /* leave it as it was */
1436                 }
1437                 break;
1438
1439         case MackieControlProtocol::Dynamics:
1440                 if (r) {
1441                         setup_dyn_vpot (r);
1442                 } else {
1443                         /* leave it as it was */
1444                 }
1445                 eq_band = -1;
1446                 break;
1447
1448         case MackieControlProtocol::Sends:
1449                 if (r) {
1450                         setup_sends_vpot (r);
1451                 } else {
1452                         /* leave it as it was */
1453                 }
1454                 eq_band = -1;
1455                 break;
1456         case MackieControlProtocol::TrackView:
1457                 if (r) {
1458                         setup_trackview_vpot (r);
1459                 } else {
1460                         /* leave it as it was */
1461                 }
1462                 eq_band = -1;
1463                 break;
1464         }
1465 }
1466
1467 void
1468 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1469 {
1470 }
1471
1472 void
1473 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1474 {
1475         if (!r) {
1476                 return;
1477         }
1478
1479         boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1480         boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1481         boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1482         boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1483         boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1484         boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1485
1486         uint32_t pos = _surface->mcp().global_index (*this);
1487
1488         /* we will control the pos-th available parameter, from the list in the
1489          * order shown above.
1490          */
1491
1492         vector<boost::shared_ptr<AutomationControl> > available;
1493         vector<AutomationType> params;
1494
1495         if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1496         if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1497         if (mc) { available.push_back (mc); params.push_back (CompMode); }
1498         if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1499         if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1500         if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1501
1502         if (pos >= available.size()) {
1503                 /* this knob is not needed to control the available parameters */
1504                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1505                 pending_display[0] = string();
1506                 pending_display[1] = string();
1507                 return;
1508         }
1509
1510         boost::shared_ptr<AutomationControl> pc;
1511         AutomationType param;
1512
1513         pc = available[pos];
1514         param = params[pos];
1515
1516         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1517         _vpot->set_control (pc);
1518
1519         string pot_id;
1520
1521         switch (param) {
1522         case CompThreshold:
1523                 pot_id = "Thresh";
1524                 break;
1525         case CompSpeed:
1526                 if (mc) {
1527                         pot_id = r->comp_speed_name (mc->get_value());
1528                 } else {
1529                         pot_id = "Speed";
1530                 }
1531                 break;
1532         case CompMode:
1533                 pot_id = "Mode";
1534                 break;
1535         case CompMakeup:
1536                 pot_id = "Makeup";
1537                 break;
1538         case CompRedux:
1539                 pot_id = "Redux";
1540                 break;
1541         case CompEnable:
1542                 pot_id = "on/off";
1543                 break;
1544         default:
1545                 break;
1546         }
1547
1548         if (!pot_id.empty()) {
1549                 pending_display[0] = pot_id;
1550         } else {
1551                 pending_display[0] = string();
1552         }
1553
1554         notify_dyn_change (param, true, false);
1555 }
1556
1557 void
1558 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1559 {
1560         uint32_t bands = r->eq_band_cnt ();
1561
1562         if (bands == 0) {
1563                 /* should never get here */
1564                 return;
1565         }
1566
1567         /* figure out how many params per band are available */
1568
1569         boost::shared_ptr<AutomationControl> pc;
1570         uint32_t params_per_band = 0;
1571
1572         if ((pc = r->eq_gain_controllable (0))) {
1573                 params_per_band += 1;
1574         }
1575         if ((pc = r->eq_freq_controllable (0))) {
1576                 params_per_band += 1;
1577         }
1578         if ((pc = r->eq_q_controllable (0))) {
1579                 params_per_band += 1;
1580         }
1581         if ((pc = r->eq_shape_controllable (0))) {
1582                 params_per_band += 1;
1583         }
1584
1585         /* pick the one for this strip, based on its global position across
1586          * all surfaces
1587          */
1588
1589         pc.reset ();
1590
1591         const uint32_t total_band_parameters = bands * params_per_band;
1592         const uint32_t global_pos = _surface->mcp().global_index (*this);
1593         AutomationType param = NullAutomation;
1594         string band_name;
1595
1596         eq_band = -1;
1597
1598         if (global_pos < total_band_parameters) {
1599
1600                 /* show a parameter for an EQ band */
1601
1602                 const uint32_t parameter = global_pos % params_per_band;
1603                 eq_band = global_pos / params_per_band;
1604                 band_name = r->eq_band_name (eq_band);
1605
1606                 switch (parameter) {
1607                 case 0:
1608                         pc = r->eq_gain_controllable (eq_band);
1609                         param = EQGain;
1610                         break;
1611                 case 1:
1612                         pc = r->eq_freq_controllable (eq_band);
1613                         param = EQFrequency;
1614                         break;
1615                 case 2:
1616                         pc = r->eq_q_controllable (eq_band);
1617                         param = EQQ;
1618                         break;
1619                 case 3:
1620                         pc = r->eq_shape_controllable (eq_band);
1621                         param = EQShape;
1622                         break;
1623                 }
1624
1625         } else {
1626
1627                 /* show a non-band parameter (HPF or enable)
1628                  */
1629
1630                 uint32_t parameter = global_pos - total_band_parameters;
1631
1632                 switch (parameter) {
1633                 case 0: /* first control after band parameters */
1634                         pc = r->eq_hpf_controllable();
1635                         param = EQHPF;
1636                         break;
1637                 case 1: /* second control after band parameters */
1638                         pc = r->eq_enable_controllable();
1639                         param = EQEnable;
1640                         break;
1641                 default:
1642                         /* nothing to control */
1643                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1644                         pending_display[0] = string();
1645                         pending_display[1] = string();
1646                         /* done */
1647                         return;
1648                         break;
1649                 }
1650
1651         }
1652
1653         if (pc) {
1654                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1655                 _vpot->set_control (pc);
1656
1657                 string pot_id;
1658
1659                 switch (param) {
1660                 case EQGain:
1661                         pot_id = band_name + "Gain";
1662                         break;
1663                 case EQFrequency:
1664                         pot_id = band_name + "Freq";
1665                         break;
1666                 case EQQ:
1667                         pot_id = band_name + " Q";
1668                         break;
1669                 case EQShape:
1670                         pot_id = band_name + " Shp";
1671                         break;
1672                 case EQHPF:
1673                         pot_id = "HPFreq";
1674                         break;
1675                 case EQEnable:
1676                         pot_id = "on/off";
1677                         break;
1678                 default:
1679                         break;
1680                 }
1681
1682                 if (!pot_id.empty()) {
1683                         pending_display[0] = pot_id;
1684                 } else {
1685                         pending_display[0] = string();
1686                 }
1687
1688                 notify_eq_change (param, eq_band, true);
1689         }
1690 }
1691
1692 void
1693 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1694 {
1695         if (!r) {
1696                 return;
1697         }
1698
1699         const uint32_t global_pos = _surface->mcp().global_index (*this);
1700
1701         boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1702
1703         if (!pc) {
1704                 pending_display[0] = string();
1705                 pending_display[1] = string();
1706                 return;
1707         }
1708
1709         pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1710         _vpot->set_control (pc);
1711
1712         pending_display[0] = r->send_name (global_pos);
1713
1714         notify_send_level_change (BusSendLevel, global_pos, true);
1715 }
1716
1717 void
1718 Strip::set_vpot_parameter (AutomationType p)
1719 {
1720         if (!_route || (p == NullAutomation)) {
1721                 control_by_parameter[vpot_parameter] = 0;
1722                 vpot_parameter = NullAutomation;
1723                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1724                 pending_display[1] = string();
1725                 return;
1726         }
1727
1728         boost::shared_ptr<AutomationControl> pan_control;
1729
1730         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1731
1732         reset_saved_values ();
1733
1734         /* unset any mapping between the vpot and any existing parameters */
1735
1736         for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1737
1738                 if (i != control_by_parameter.end() && i->second == _vpot) {
1739                         i->second = 0;
1740                 }
1741         }
1742
1743         switch (p) {
1744         case PanAzimuthAutomation:
1745                 if ((pan_control = _route->pan_azimuth_control ())) {
1746                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1747                                 _pan_mode = PanAzimuthAutomation;
1748                                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1749                                         /* gain to vpot, pan azi to fader */
1750                                         _vpot->set_control (_route->gain_control());
1751                                         vpot_parameter = GainAutomation;
1752                                         control_by_parameter[GainAutomation] = _vpot;
1753                                         _fader->set_control (pan_control);
1754                                         control_by_parameter[PanAzimuthAutomation] = _fader;
1755                                 } else {
1756                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1757                                         control_by_parameter[PanAzimuthAutomation] = 0;
1758                                 }
1759                         } else {
1760                                 /* gain to fader, pan azi to vpot */
1761                                 vpot_parameter = PanAzimuthAutomation;
1762                                 _fader->set_control (_route->gain_control());
1763                                 control_by_parameter[GainAutomation] = _fader;
1764                                 _vpot->set_control (pan_control);
1765                                 control_by_parameter[PanAzimuthAutomation] = _vpot;
1766                         }
1767                 } else {
1768                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1769                         control_by_parameter[PanAzimuthAutomation] = 0;
1770                 }
1771                 break;
1772
1773         case PanWidthAutomation:
1774                 if ((pan_control = _route->pan_width_control ())) {
1775                         if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1776                                 _pan_mode = PanWidthAutomation;
1777                                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1778                                         /* gain to vpot, pan width to fader */
1779                                         _vpot->set_control (_route->gain_control());
1780                                         vpot_parameter = GainAutomation;
1781                                         control_by_parameter[GainAutomation] = _vpot;
1782                                         _fader->set_control (pan_control);
1783                                         control_by_parameter[PanWidthAutomation] = _fader;
1784                                 } else {
1785                                         _fader->set_control (boost::shared_ptr<AutomationControl>());
1786                                         control_by_parameter[PanWidthAutomation] = 0;
1787                                 }
1788                         } else {
1789                                 /* gain to fader, pan width to vpot */
1790                                 vpot_parameter = PanWidthAutomation;
1791                                 _fader->set_control (_route->gain_control());
1792                                 control_by_parameter[GainAutomation] = _fader;
1793                                 _vpot->set_control (pan_control);
1794                                 control_by_parameter[PanWidthAutomation] = _vpot;
1795                         }
1796                 } else {
1797                         _vpot->set_control (boost::shared_ptr<AutomationControl>());
1798                         control_by_parameter[PanWidthAutomation] = 0;
1799                 }
1800                 break;
1801
1802         case PanElevationAutomation:
1803                 break;
1804         case PanFrontBackAutomation:
1805                 break;
1806         case PanLFEAutomation:
1807                 break;
1808         case TrimAutomation:
1809                 _trim_mode = TrimAutomation;
1810                 vpot_parameter = TrimAutomation;
1811                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1812                         /* gain to vpot, trim to fader */
1813                         _vpot->set_control (_route->gain_control());
1814                         control_by_parameter[GainAutomation] = _vpot;
1815                         if (_route->trim() && route()->trim()->active()) {
1816                                 _fader->set_control (_route->trim_control());
1817                                 control_by_parameter[TrimAutomation] = _fader;
1818                         } else {
1819                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1820                                 control_by_parameter[TrimAutomation] = 0;
1821                         }
1822                 } else {
1823                         /* gain to fader, trim to vpot */
1824                         _fader->set_control (_route->gain_control());
1825                         control_by_parameter[GainAutomation] = _fader;
1826                         if (_route->trim() && route()->trim()->active()) {
1827                                 _vpot->set_control (_route->trim_control());
1828                                 control_by_parameter[TrimAutomation] = _vpot;
1829                         } else {
1830                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1831                                 control_by_parameter[TrimAutomation] = 0;
1832                         }
1833                 }
1834                 break;
1835         case PhaseAutomation:
1836                 _trim_mode = PhaseAutomation;
1837                 vpot_parameter = PhaseAutomation;
1838                 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1839                         /* gain to vpot, phase to fader */
1840                         _vpot->set_control (_route->gain_control());
1841                         control_by_parameter[GainAutomation] = _vpot;
1842                         if (_route->phase_invert().size()) {
1843                                 _fader->set_control (_route->phase_control());
1844                                 control_by_parameter[PhaseAutomation] = _fader;
1845                         } else {
1846                                 _fader->set_control (boost::shared_ptr<AutomationControl>());
1847                                 control_by_parameter[PhaseAutomation] = 0;
1848                         }
1849                 } else {
1850                         /* gain to fader, phase to vpot */
1851                         _fader->set_control (_route->gain_control());
1852                         control_by_parameter[GainAutomation] = _fader;
1853                         if (_route->phase_invert().size()) {
1854                                 _vpot->set_control (_route->phase_control());
1855                                 control_by_parameter[PhaseAutomation] = _vpot;
1856                         } else {
1857                                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1858                                 control_by_parameter[PhaseAutomation] = 0;
1859                         }
1860                 }
1861                 break;
1862         default:
1863                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1864                 break;
1865
1866         }
1867
1868         pending_display[1] = vpot_mode_string ();
1869 }
1870
1871 bool
1872 Strip::is_midi_track () const
1873 {
1874         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1875 }
1876
1877 void
1878 Strip::reset_saved_values ()
1879 {
1880         _last_pan_azi_position_written = -1.0;
1881         _last_pan_width_position_written = -1.0;
1882         _last_gain_position_written = -1.0;
1883         _last_trim_position_written = -1.0;
1884
1885 }
1886
1887 void
1888 Strip::notify_metering_state_changed()
1889 {
1890         if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1891                 return;
1892         }
1893
1894         if (!_route || !_meter) {
1895                 return;
1896         }
1897
1898         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1899         bool metering_active = _surface->mcp().metering_active ();
1900
1901         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1902                 return;
1903         }
1904
1905         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1906
1907         if (!transport_is_rolling || !metering_active) {
1908                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1909                 notify_panner_azi_changed (true);
1910         }
1911
1912         _transport_is_rolling = transport_is_rolling;
1913         _metering_active = metering_active;
1914 }