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