Fix a -Wreorder
[ardour.git] / libs / surfaces / us2400 / strip.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3         Copyright (C) 2012 Paul Davis
4         Copyright (C) 2017 Ben Loftis
5
6         This program is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; either version 2 of the License, or
9         (at your option) any later version.
10
11         This program is distributed in the hope that it will be useful,
12         but WITHOUT ANY WARRANTY; without even the implied warranty of
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14         GNU General Public License for more details.
15
16         You should have received a copy of the GNU General Public License
17         along with this program; if not, write to the Free Software
18         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <sstream>
22 #include <vector>
23 #include <climits>
24
25 #include <stdint.h>
26
27 #include <sys/time.h>
28
29 #include <glibmm/convert.h>
30
31 #include "midi++/port.h"
32
33 #include "pbd/compose.h"
34 #include "pbd/convert.h"
35
36 #include "ardour/amp.h"
37 #include "ardour/bundle.h"
38 #include "ardour/debug.h"
39 #include "ardour/midi_ui.h"
40 #include "ardour/meter.h"
41 #include "ardour/monitor_control.h"
42 #include "ardour/plugin_insert.h"
43 #include "ardour/pannable.h"
44 #include "ardour/panner.h"
45 #include "ardour/panner_shell.h"
46 #include "ardour/phase_control.h"
47 #include "ardour/rc_configuration.h"
48 #include "ardour/record_enable_control.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/send.h"
52 #include "ardour/solo_isolate_control.h"
53 #include "ardour/track.h"
54 #include "ardour/midi_track.h"
55 #include "ardour/user_bundle.h"
56 #include "ardour/profile.h"
57 #include "ardour/value_as_string.h"
58
59 #include "us2400_control_protocol.h"
60 #include "surface_port.h"
61 #include "surface.h"
62 #include "strip.h"
63 #include "button.h"
64 #include "led.h"
65 #include "pot.h"
66 #include "fader.h"
67 #include "jog.h"
68 #include "meter.h"
69
70 using namespace std;
71 using namespace ARDOUR;
72 using namespace PBD;
73 using namespace ArdourSurface;
74 using namespace US2400;
75
76 #ifndef timeradd /// only avail with __USE_BSD
77 #define timeradd(a,b,result)                         \
78   do {                                               \
79     (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;    \
80     (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
81     if ((result)->tv_usec >= 1000000)                \
82     {                                                \
83       ++(result)->tv_sec;                            \
84       (result)->tv_usec -= 1000000;                  \
85     }                                                \
86   } while (0)
87 #endif
88
89 #define ui_context() US2400Protocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
90
91 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
92         : Group (name)
93         , _solo (0)
94         , _mute (0)
95         , _select (0)
96         , _fader_touch (0)
97         , _vpot (0)
98         , _fader (0)
99         , _meter (0)
100         , _index (index)
101         , _surface (&s)
102         , _controls_locked (false)
103         , _transport_is_rolling (false)
104         , _metering_active (true)
105         , _pan_mode (PanAzimuthAutomation)
106 {
107         _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
108         _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
109
110         if (s.mcp().device_info().has_meters()) {
111                 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
112         }
113
114         for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
115                 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
116                 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
117                                                                    _surface->number(), index, Button::id_to_name (bb->bid()),
118                                                                    bb->id(), b->second.base_id));
119         }
120
121         _trickle_counter = 0;
122 }
123
124 Strip::~Strip ()
125 {
126         /* surface is responsible for deleting all controls */
127 }
128
129 void
130 Strip::add (Control & control)
131 {
132         Button* button;
133
134         Group::add (control);
135
136         /* fader, vpot, meter were all set explicitly */
137
138         if ((button = dynamic_cast<Button*>(&control)) != 0) {
139                 switch (button->bid()) {
140                 case Button::Mute:
141                         _mute = button;
142                         break;
143                 case Button::Solo:
144                         _solo = button;
145                         break;
146                 case Button::Select:
147                         _select = button;
148                         break;
149                 case Button::FaderTouch:
150                         _fader_touch = button;
151                         break;
152                 default:
153                         break;
154                 }
155         }
156 }
157
158 void
159 Strip::set_stripable (boost::shared_ptr<Stripable> r, bool /*with_messages*/)
160 {
161         if (_controls_locked) {
162                 return;
163         }
164
165         stripable_connections.drop_connections ();
166
167         _solo->set_control (boost::shared_ptr<AutomationControl>());
168         _mute->set_control (boost::shared_ptr<AutomationControl>());
169         _select->set_control (boost::shared_ptr<AutomationControl>());
170
171         _fader->set_control (boost::shared_ptr<AutomationControl>());
172         _vpot->set_control (boost::shared_ptr<AutomationControl>());
173
174         _stripable = r;
175
176         mark_dirty ();
177
178         if (!r) {
179                 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
180                 zero ();
181                 return;
182         }
183
184         DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 strip %2 now mapping stripable %3\n",
185                                                            _surface->number(), _index, _stripable->name()));
186
187         _solo->set_control (_stripable->solo_control());
188         _mute->set_control (_stripable->mute_control());
189
190         _stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
191         _stripable->mute_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
192
193         boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control();
194         if (pan_control) {
195                 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
196         }
197
198         pan_control = _stripable->pan_width_control();
199         if (pan_control) {
200                 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
201         }
202
203         _stripable->gain_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
204         _stripable->PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
205         _stripable->presentation_info().PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
206
207         // TODO this works when a currently-banked stripable is made inactive, but not
208         // when a stripable is activated which should be currently banked.
209
210         _stripable->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_stripable_deleted, this), ui_context());
211
212         /* setup legal VPot modes for this stripable */
213
214         possible_pot_parameters.clear();
215
216         if (_stripable->pan_azimuth_control()) {
217                 possible_pot_parameters.push_back (PanAzimuthAutomation);
218         }
219         if (_stripable->pan_width_control()) {
220                 possible_pot_parameters.push_back (PanWidthAutomation);
221         }
222         if (_stripable->pan_elevation_control()) {
223                 possible_pot_parameters.push_back (PanElevationAutomation);
224         }
225         if (_stripable->pan_frontback_control()) {
226                 possible_pot_parameters.push_back (PanFrontBackAutomation);
227         }
228         if (_stripable->pan_lfe_control()) {
229                 possible_pot_parameters.push_back (PanLFEAutomation);
230         }
231
232         _pan_mode = PanAzimuthAutomation;
233
234         if (_surface->mcp().subview_mode() == US2400Protocol::None) {
235                 set_vpot_parameter (_pan_mode);
236         }
237
238         _fader->set_control (_stripable->gain_control());
239
240         notify_all ();
241 }
242
243 void
244 Strip::reset_stripable ()
245 {
246         stripable_connections.drop_connections ();
247
248         _solo->set_control (boost::shared_ptr<AutomationControl>());
249         _mute->set_control (boost::shared_ptr<AutomationControl>());
250         _select->set_control (boost::shared_ptr<AutomationControl>());
251
252         _fader->reset_control ();
253         _vpot->reset_control ();
254
255         _stripable.reset();
256
257         mark_dirty ();
258
259         notify_all ();
260 }
261
262
263 void
264 Strip::notify_all()
265 {
266 //      if (!_stripable) {
267 //              zero ();
268 //              return;
269 //      }
270         // The active V-pot control may not be active for this strip
271         // But if we zero it in the controls function it may erase
272         // the one we do want
273 //      _surface->write (_vpot->zero());
274
275         notify_solo_changed ();
276         notify_mute_changed ();
277         notify_gain_changed ();
278         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
279         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::selected));
280         notify_panner_azi_changed ();
281         notify_vpot_change ();
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         _solo->mark_dirty ();
295         _trickle_counter = 0;
296 }
297
298 void
299 Strip::notify_mute_changed ()
300 {
301         DEBUG_TRACE (DEBUG::US2400, string_compose ("Strip %1 mute changed\n", _index));
302 //      if (_stripable && _mute) {
303 //              DEBUG_TRACE (DEBUG::US2400, string_compose ("\tstripable muted ? %1\n", _stripable->mute_control()->muted()));
304 //              DEBUG_TRACE (DEBUG::US2400, string_compose ("mute message: %1\n", _mute->set_state (_stripable->mute_control()->muted() ? on : off)));
305 //
306 //              _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
307 //      } else {
308 //              _surface->write (_mute->zero());
309 //      }
310
311         _mute->mark_dirty ();
312         _trickle_counter = 0;
313 }
314
315 void
316 Strip::notify_record_enable_changed ()
317 {
318 }
319
320 void
321 Strip::notify_stripable_deleted ()
322 {
323         _surface->mcp().notify_stripable_removed ();
324         _surface->mcp().refresh_current_bank();
325 }
326
327 void
328 Strip::notify_gain_changed (bool force_update)
329 {
330         _fader->mark_dirty();
331         _trickle_counter = 0;
332 }
333
334 void
335 Strip::notify_processor_changed (bool force_update)
336 {
337 }
338
339 void
340 Strip::notify_property_changed (const PropertyChange& what_changed)
341 {
342 }
343
344 void
345 Strip::update_selection_state ()
346 {
347         _select->mark_dirty ();
348         _trickle_counter = 0;
349
350 //      if(_stripable) {
351 //              _surface->write (_select->set_state (_stripable->is_selected()));
352 //      }
353 }
354
355 void
356 Strip::show_stripable_name ()
357 {
358 }
359
360 void
361 Strip::notify_vpot_change ()
362 {
363         _vpot->mark_dirty();
364         _trickle_counter = 0;
365 }
366
367 void
368 Strip::notify_panner_azi_changed (bool force_update)
369 {
370         _vpot->mark_dirty();
371         _trickle_counter = 0;
372 }
373
374 void
375 Strip::notify_panner_width_changed (bool force_update)
376 {
377         _trickle_counter = 0;
378 }
379
380 void
381 Strip::select_event (Button&, ButtonState bs)
382 {
383         DEBUG_TRACE (DEBUG::US2400, "select button\n");
384
385         if (bs == press) {
386
387                 int ms = _surface->mcp().main_modifier_state();
388
389                 if (ms & US2400Protocol::MODIFIER_CMDALT) {
390                         _controls_locked = !_controls_locked;
391                         return;
392                 }
393
394                 DEBUG_TRACE (DEBUG::US2400, "add select button on press\n");
395                 _surface->mcp().add_down_select_button (_surface->number(), _index);
396                 _surface->mcp().select_range (_surface->mcp().global_index (*this));
397
398         } else {
399                 DEBUG_TRACE (DEBUG::US2400, "remove select button on release\n");
400                 _surface->mcp().remove_down_select_button (_surface->number(), _index);
401         }
402
403         _trickle_counter = 0;
404 }
405
406 void
407 Strip::vselect_event (Button&, ButtonState bs)
408 {
409 }
410
411 void
412 Strip::fader_touch_event (Button&, ButtonState bs)
413 {
414         DEBUG_TRACE (DEBUG::US2400, string_compose ("fader touch, press ? %1\n", (bs == press)));
415
416         if (bs == press) {
417
418                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
419
420                 _fader->set_in_use (true);
421                 _fader->start_touch (_surface->mcp().transport_frame());
422
423         } else {
424
425                 _fader->set_in_use (false);
426                 _fader->stop_touch (_surface->mcp().transport_frame());
427
428         }
429 }
430
431
432 void
433 Strip::handle_button (Button& button, ButtonState bs)
434 {
435         boost::shared_ptr<AutomationControl> control;
436
437         if (bs == press) {
438                 button.set_in_use (true);
439         } else {
440                 button.set_in_use (false);
441         }
442
443         DEBUG_TRACE (DEBUG::US2400, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
444
445         switch (button.bid()) {
446         case Button::Select:
447                 select_event (button, bs);
448                 break;
449
450         case Button::FaderTouch:
451                 fader_touch_event (button, bs);
452                 break;
453
454         default:
455                 if ((control = button.control ())) {
456                         if (bs == press) {
457                                 DEBUG_TRACE (DEBUG::US2400, "add button on press\n");
458                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
459
460                                 float new_value = control->get_value() ? 0.0 : 1.0;
461
462                                 /* get all controls that either have their
463                                  * button down or are within a range of
464                                  * several down buttons
465                                  */
466
467                                 US2400Protocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type(),
468                                                                                                              _surface->mcp().global_index(*this));
469
470
471                                 DEBUG_TRACE (DEBUG::US2400, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
472                                                                             controls.size(), control->parameter().type(), new_value));
473
474                                 /* apply change, with potential modifier semantics */
475
476                                 Controllable::GroupControlDisposition gcd;
477
478                                 if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
479                                         gcd = Controllable::InverseGroup;
480                                 } else {
481                                         gcd = Controllable::UseGroup;
482                                 }
483
484                                 for (US2400Protocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
485                                         (*c)->set_value (new_value, gcd);
486                                 }
487
488                         } else {
489                                 DEBUG_TRACE (DEBUG::US2400, "remove button on release\n");
490                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
491                         }
492                 }
493                 break;
494         }
495 }
496
497
498 void
499 Strip::handle_fader_touch (Fader& fader, bool touch_on)
500 {
501         if (touch_on) {
502                 fader.start_touch (_surface->mcp().transport_frame());
503         } else {
504                 fader.stop_touch (_surface->mcp().transport_frame());
505         }
506 }
507
508 void
509 Strip::handle_fader (Fader& fader, float position)
510 {
511         DEBUG_TRACE (DEBUG::US2400, string_compose ("fader to %1\n", position));
512         boost::shared_ptr<AutomationControl> ac = fader.control();
513         if (!ac) {
514                 return;
515         }
516
517         Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
518
519         if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
520                 gcd = Controllable::InverseGroup;
521         }
522
523         fader.set_value (position, gcd);
524
525         /* From the Mackie Control MIDI implementation docs:
526
527            In order to ensure absolute synchronization with the host software,
528            Mackie Control uses a closed-loop servo system for the faders,
529            meaning the faders will always move to their last received position.
530            When a host receives a Fader Position Message, it must then
531            re-transmit that message to the Mackie Control or else the faders
532            will return to their last position.
533         */
534
535         _surface->write (fader.set_position (position));
536 }
537
538 void
539 Strip::handle_pot (Pot& pot, float delta)
540 {
541         /* Pots only emit events when they move, not when they
542            stop moving. So to get a stop event, we need to use a timeout.
543         */
544
545         boost::shared_ptr<AutomationControl> ac = pot.control();
546         if (!ac) {
547                 return;
548         }
549
550         Controllable::GroupControlDisposition gcd;
551
552         if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
553                 gcd = Controllable::InverseGroup;
554         } else {
555                 gcd = Controllable::UseGroup;
556         }
557
558         if (ac->toggled()) {
559
560                 /* make it like a single-step, directional switch */
561
562                 if (delta > 0) {
563                         ac->set_value (1.0, gcd);
564                 } else {
565                         ac->set_value (0.0, gcd);
566                 }
567
568         } else if (ac->desc().enumeration || ac->desc().integer_step) {
569
570                 /* use Controllable::get_value() to avoid the
571                  * "scaling-to-interface" that takes place in
572                  * Control::get_value() via the pot member.
573                  *
574                  * an enumeration with 4 values will have interface values of
575                  * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
576                  * deal with that.
577                  */
578
579                 if (delta > 0) {
580                         ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
581                 } else {
582                         ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
583                 }
584
585         } else {
586
587                 double p = ac->get_interface();
588
589                 p += delta;
590
591                 p = max (0.0, p);
592                 p = min (1.0, p);
593
594                 ac->set_value ( ac->interface_to_internal(p), gcd);
595         }
596 }
597
598 void
599 Strip::periodic (ARDOUR::microseconds_t now)
600 {
601
602         update_meter ();
603
604         if ( _trickle_counter %24 == 0 ) {
605
606                 if ( _fader->control() ) {
607                         _surface->write (_fader->set_position (_fader->control()->internal_to_interface (_fader->control()->get_value ())));
608                 } else {
609                         _surface->write (_fader->set_position(0.0));
610                 }
611
612                 if ( _vpot->control() ) {
613                         _surface->write (_vpot->set (_vpot->control()->internal_to_interface (_vpot->control()->get_value ()), true));
614                 } else {
615                         _surface->write (_vpot->set(0.0, false));
616                 }
617
618                 if (_stripable) {
619                         _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
620                         _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
621                         _surface->write (_select->set_state (_stripable->is_selected()));
622                 } else {
623                         _surface->write (_solo->set_state (off));
624                         _surface->write (_mute->set_state (off));
625                         _surface->write (_select->set_state (off));
626                 }
627
628         }
629
630         //after a hard write, queue us for trickling data later
631         if (_trickle_counter == 0)
632                 _trickle_counter = global_index()+1;
633
634         _trickle_counter++;
635
636 }
637
638 void
639 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
640 {
641 }
642
643 void
644 Strip::update_automation ()
645 {
646 }
647
648 void
649 Strip::update_meter ()
650 {
651         if (!_stripable) {
652                 return;
653         }
654
655         if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
656                 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
657                 _meter->send_update (*_surface, dB);
658                 return;
659         }
660 }
661
662 void
663 Strip::zero ()
664 {
665         _trickle_counter = 0;
666 }
667
668 void
669 Strip::lock_controls ()
670 {
671         _controls_locked = true;
672 }
673
674 void
675 Strip::unlock_controls ()
676 {
677         _controls_locked = false;
678 }
679
680 string
681 Strip::vpot_mode_string ()
682 {
683         return "???";
684 }
685
686 void
687 Strip::next_pot_mode ()
688 {
689         vector<AutomationType>::iterator i;
690
691         boost::shared_ptr<AutomationControl> ac = _vpot->control();
692
693         if (!ac) {
694                 return;
695         }
696
697
698         if (_surface->mcp().subview_mode() != US2400Protocol::None) {
699                 return;
700         }
701
702         if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
703                 return;
704         }
705
706         for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
707                 if ((*i) == ac->parameter().type()) {
708                         break;
709                 }
710         }
711
712         /* move to the next mode in the list, or back to the start (which will
713            also happen if the current mode is not in the current pot mode list)
714         */
715
716         if (i != possible_pot_parameters.end()) {
717                 ++i;
718         }
719
720         if (i == possible_pot_parameters.end()) {
721                 i = possible_pot_parameters.begin();
722         }
723
724         set_vpot_parameter (*i);
725 }
726
727 void
728 /*
729  *
730  * name: Strip::subview_mode_changed
731  * @param
732  * @return
733  *
734  */
735 Strip::subview_mode_changed ()
736 {
737         switch (_surface->mcp().subview_mode()) {
738
739         case US2400Protocol::None:
740                 set_vpot_parameter (_pan_mode);
741                 notify_metering_state_changed ();
742                 break;
743
744         case US2400Protocol::TrackView:
745                 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
746                 if (r) {
747                         DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2- assigning trackview pot\n",  _surface->number(), _index));
748                         setup_trackview_vpot (r);
749                 } else {
750                         DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2 - no stripable\n",  _surface->number(), _index));
751                 }
752                 break;
753
754         }
755
756         _trickle_counter = 0;
757 }
758
759 void
760 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
761 {
762 }
763
764 void
765 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
766 {
767 }
768
769 void
770 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
771 {
772
773 }
774
775 void
776 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
777 {
778         subview_connections.drop_connections ();
779
780         if (!r) {
781                 return;
782         }
783
784
785         boost::shared_ptr<AutomationControl> pc;
786         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
787         string label;
788
789         _vpot->set_mode(Pot::wrap);
790
791 #ifdef MIXBUS
792         const uint32_t global_pos = _surface->mcp().global_index (*this);
793
794         //Trim & dynamics
795         switch (global_pos) {
796         case 0:
797                 pc = r->trim_control ();
798                 _vpot->set_mode(Pot::boost_cut);
799                 break;
800
801         case 1:
802                 pc = r->pan_azimuth_control ();
803                 _vpot->set_mode(Pot::dot);
804                 break;
805
806         case 2:
807                 pc = r->comp_threshold_controllable();
808                 break;
809
810         case 3:
811                 pc = r->comp_speed_controllable();
812                 break;
813
814         case 4:
815                 pc = r->comp_mode_controllable();
816                 _vpot->set_mode(Pot::wrap);
817                 break;
818
819         case 5:
820                 pc = r->comp_makeup_controllable();
821                 break;
822
823
824         }  //trim & dynamics
825
826
827         //EQ
828         int eq_band = -1;
829         if (r->mixbus () || r->is_master()) {
830
831                 switch (global_pos) {
832
833                         case 6:
834                                 pc = r->pan_width_control();
835                                 break;
836
837                         case 7:
838                                 pc = r->tape_drive_controllable();
839                                 break;
840
841                         case 8:
842                         case 9:
843                         case 10:
844                                 eq_band = (global_pos-8);
845                                 pc = r->eq_gain_controllable (eq_band);
846                                 _vpot->set_mode(Pot::boost_cut);
847                                 break;
848                 }
849
850         } else if (r->is_input_strip ()) {
851
852 #ifdef MIXBUS32C
853                 switch (global_pos) {
854                         case 6:
855                                 pc = r->filter_freq_controllable(true);
856                                 break;
857                         case 7:
858                                 pc = r->filter_freq_controllable(false);
859                                 break;
860                         case 8:
861                         case 10:
862                         case 12:
863                         case 14: {
864                                 eq_band = (global_pos-8) / 2;
865                                 pc = r->eq_freq_controllable (eq_band);
866                                 } break;
867                         case 9:
868                         case 11:
869                         case 13:
870                         case 15: {
871                                 eq_band = (global_pos-8) / 2;
872                                 pc = r->eq_gain_controllable (eq_band);
873                                 _vpot->set_mode(Pot::boost_cut);
874                                 } break;
875                 }
876
877 #else  //regular Mixbus channel EQ
878
879                 switch (global_pos) {
880                         case 7:
881                                 pc = r->filter_freq_controllable(true);
882                                 break;
883                         case 8:
884                         case 10:
885                         case 12:
886                                 eq_band = (global_pos-8) / 2;
887                                 pc = r->eq_gain_controllable (eq_band);
888                                 _vpot->set_mode(Pot::boost_cut);
889                                 break;
890                         case 9:
891                         case 11:
892                         case 13:
893                                 eq_band = (global_pos-8) / 2;
894                                 pc = r->eq_freq_controllable (eq_band);
895                                 break;
896                 }
897
898
899 #endif
900
901                 //mixbus sends
902                 switch (global_pos) {
903                 case 16:
904                 case 17:
905                 case 18:
906                 case 19:
907                 case 20:
908                 case 21:
909                 case 22:
910                 case 23:
911                         pc = r->send_level_controllable ( global_pos - 16 );
912                         break;
913                 }  //global_pos switch
914
915         } //if input_strip
916 #endif //ifdef MIXBUS
917
918         if (pc) {  //control found; set our knob to watch for changes in it
919                 _vpot->set_control (pc);
920                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_vpot_change, this), ui_context());
921         } else {  //no control, just set the knob to "empty"
922                 _vpot->reset_control ();
923         }
924
925         notify_vpot_change ();
926 }
927
928 void
929 Strip::set_vpot_parameter (AutomationType p)
930 {
931         if (!_stripable || (p == NullAutomation)) {
932                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
933                 return;
934         }
935
936         boost::shared_ptr<AutomationControl> pan_control;
937
938         DEBUG_TRACE (DEBUG::US2400, string_compose ("switch to vpot mode %1\n", p));
939
940         mark_dirty ();
941
942         switch (p) {
943         case PanAzimuthAutomation:
944                 pan_control = _stripable->pan_azimuth_control ();
945                 break;
946         case PanWidthAutomation:
947                 pan_control = _stripable->pan_width_control ();
948                 break;
949         case PanElevationAutomation:
950                 break;
951         case PanFrontBackAutomation:
952                 break;
953         case PanLFEAutomation:
954                 break;
955         default:
956                 return;
957         }
958
959         if (pan_control) {
960                 _pan_mode = p;
961                 _vpot->set_mode (Pot::dot);
962                 _vpot->set_control (pan_control);
963         }
964
965         notify_panner_azi_changed (true);
966 }
967
968 bool
969 Strip::is_midi_track () const
970 {
971         return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
972 }
973
974 void
975 Strip::mark_dirty ()
976 {
977         _fader->mark_dirty();
978         _vpot->mark_dirty();
979         _solo->mark_dirty();
980         _mute->mark_dirty();
981         _trickle_counter=0;
982 }
983
984 void
985 Strip::notify_metering_state_changed()
986 {
987         if (_surface->mcp().subview_mode() != US2400Protocol::None) {
988                 return;
989         }
990
991         if (!_stripable || !_meter) {
992                 return;
993         }
994
995         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
996         bool metering_active = _surface->mcp().metering_active ();
997
998         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
999                 return;
1000         }
1001
1002         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1003
1004         if (!transport_is_rolling || !metering_active) {
1005                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1006                 notify_panner_azi_changed (true);
1007         }
1008
1009         _transport_is_rolling = transport_is_rolling;
1010         _metering_active = metering_active;
1011 }