NO-OP: <tab> after <space> fixes in libs
[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 0
267         if (!_stripable) {
268                 zero ();
269                 return;
270         }
271 #endif
272         // The active V-pot control may not be active for this strip
273         // But if we zero it in the controls function it may erase
274         // the one we do want
275 #if 0
276         _surface->write (_vpot->zero());
277 #endif
278
279         notify_solo_changed ();
280         notify_mute_changed ();
281         notify_gain_changed ();
282         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
283         notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::selected));
284         notify_panner_azi_changed ();
285         notify_vpot_change ();
286         notify_panner_width_changed ();
287         notify_record_enable_changed ();
288 #if 0
289         notify_processor_changed ();
290 #endif
291 }
292
293 void
294 Strip::notify_solo_changed ()
295 {
296 #if 0
297         if (_stripable && _solo) {
298                 _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
299         }
300 #endif
301
302         _solo->mark_dirty ();
303         _trickle_counter = 0;
304 }
305
306 void
307 Strip::notify_mute_changed ()
308 {
309         DEBUG_TRACE (DEBUG::US2400, string_compose ("Strip %1 mute changed\n", _index));
310 #if 0
311         if (_stripable && _mute) {
312                 DEBUG_TRACE (DEBUG::US2400, string_compose ("\tstripable muted ? %1\n", _stripable->mute_control()->muted()));
313                 DEBUG_TRACE (DEBUG::US2400, string_compose ("mute message: %1\n", _mute->set_state (_stripable->mute_control()->muted() ? on : off)));
314
315                 _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
316         } else {
317                 _surface->write (_mute->zero());
318         }
319 #endif
320
321         _mute->mark_dirty ();
322         _trickle_counter = 0;
323 }
324
325 void
326 Strip::notify_record_enable_changed ()
327 {
328 }
329
330 void
331 Strip::notify_stripable_deleted ()
332 {
333         _surface->mcp().notify_stripable_removed ();
334         _surface->mcp().refresh_current_bank();
335 }
336
337 void
338 Strip::notify_gain_changed (bool force_update)
339 {
340         _fader->mark_dirty();
341         _trickle_counter = 0;
342 }
343
344 void
345 Strip::notify_processor_changed (bool force_update)
346 {
347 }
348
349 void
350 Strip::notify_property_changed (const PropertyChange& what_changed)
351 {
352 }
353
354 void
355 Strip::update_selection_state ()
356 {
357         _select->mark_dirty ();
358         _trickle_counter = 0;
359 #if 0
360         if(_stripable) {
361                 _surface->write (_select->set_state (_stripable->is_selected()));
362         }
363 #endif
364 }
365
366 void
367 Strip::show_stripable_name ()
368 {
369 }
370
371 void
372 Strip::notify_vpot_change ()
373 {
374         _vpot->mark_dirty();
375         _trickle_counter = 0;
376 }
377
378 void
379 Strip::notify_panner_azi_changed (bool force_update)
380 {
381         _vpot->mark_dirty();
382         _trickle_counter = 0;
383 }
384
385 void
386 Strip::notify_panner_width_changed (bool force_update)
387 {
388         _trickle_counter = 0;
389 }
390
391 void
392 Strip::select_event (Button&, ButtonState bs)
393 {
394         DEBUG_TRACE (DEBUG::US2400, "select button\n");
395
396         if (bs == press) {
397
398                 int ms = _surface->mcp().main_modifier_state();
399
400                 if (ms & US2400Protocol::MODIFIER_CMDALT) {
401                         _controls_locked = !_controls_locked;
402                         return;
403                 }
404
405                 DEBUG_TRACE (DEBUG::US2400, "add select button on press\n");
406                 _surface->mcp().add_down_select_button (_surface->number(), _index);
407                 _surface->mcp().select_range (_surface->mcp().global_index (*this));
408
409         } else {
410                 DEBUG_TRACE (DEBUG::US2400, "remove select button on release\n");
411                 _surface->mcp().remove_down_select_button (_surface->number(), _index);
412         }
413
414         _trickle_counter = 0;
415 }
416
417 void
418 Strip::vselect_event (Button&, ButtonState bs)
419 {
420 }
421
422 void
423 Strip::fader_touch_event (Button&, ButtonState bs)
424 {
425         DEBUG_TRACE (DEBUG::US2400, string_compose ("fader touch, press ? %1\n", (bs == press)));
426
427         if (bs == press) {
428
429                 boost::shared_ptr<AutomationControl> ac = _fader->control ();
430
431                 _fader->set_in_use (true);
432                 _fader->start_touch (_surface->mcp().transport_frame());
433
434         } else {
435
436                 _fader->set_in_use (false);
437                 _fader->stop_touch (_surface->mcp().transport_frame());
438
439         }
440 }
441
442
443 void
444 Strip::handle_button (Button& button, ButtonState bs)
445 {
446         boost::shared_ptr<AutomationControl> control;
447
448         if (bs == press) {
449                 button.set_in_use (true);
450         } else {
451                 button.set_in_use (false);
452         }
453
454         DEBUG_TRACE (DEBUG::US2400, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
455
456         switch (button.bid()) {
457         case Button::Select:
458                 select_event (button, bs);
459                 break;
460
461         case Button::FaderTouch:
462                 fader_touch_event (button, bs);
463                 break;
464
465         default:
466                 if ((control = button.control ())) {
467                         if (bs == press) {
468                                 DEBUG_TRACE (DEBUG::US2400, "add button on press\n");
469                                 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
470
471                                 float new_value = control->get_value() ? 0.0 : 1.0;
472
473                                 /* get all controls that either have their
474                                  * button down or are within a range of
475                                  * several down buttons
476                                  */
477
478                                 US2400Protocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type(),
479                                                                                                              _surface->mcp().global_index(*this));
480
481
482                                 DEBUG_TRACE (DEBUG::US2400, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
483                                                                             controls.size(), control->parameter().type(), new_value));
484
485                                 /* apply change, with potential modifier semantics */
486
487                                 Controllable::GroupControlDisposition gcd;
488
489                                 if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
490                                         gcd = Controllable::InverseGroup;
491                                 } else {
492                                         gcd = Controllable::UseGroup;
493                                 }
494
495                                 for (US2400Protocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
496                                         (*c)->set_value (new_value, gcd);
497                                 }
498
499                         } else {
500                                 DEBUG_TRACE (DEBUG::US2400, "remove button on release\n");
501                                 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
502                         }
503                 }
504                 break;
505         }
506 }
507
508
509 void
510 Strip::handle_fader_touch (Fader& fader, bool touch_on)
511 {
512         if (touch_on) {
513                 fader.start_touch (_surface->mcp().transport_frame());
514         } else {
515                 fader.stop_touch (_surface->mcp().transport_frame());
516         }
517 }
518
519 void
520 Strip::handle_fader (Fader& fader, float position)
521 {
522         DEBUG_TRACE (DEBUG::US2400, string_compose ("fader to %1\n", position));
523         boost::shared_ptr<AutomationControl> ac = fader.control();
524         if (!ac) {
525                 return;
526         }
527
528         Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
529
530         if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
531                 gcd = Controllable::InverseGroup;
532         }
533
534         fader.set_value (position, gcd);
535
536         /* From the Mackie Control MIDI implementation docs:
537
538            In order to ensure absolute synchronization with the host software,
539            Mackie Control uses a closed-loop servo system for the faders,
540            meaning the faders will always move to their last received position.
541            When a host receives a Fader Position Message, it must then
542            re-transmit that message to the Mackie Control or else the faders
543            will return to their last position.
544         */
545
546         _surface->write (fader.set_position (position));
547 }
548
549 void
550 Strip::handle_pot (Pot& pot, float delta)
551 {
552         /* Pots only emit events when they move, not when they
553            stop moving. So to get a stop event, we need to use a timeout.
554         */
555
556         boost::shared_ptr<AutomationControl> ac = pot.control();
557         if (!ac) {
558                 return;
559         }
560
561         Controllable::GroupControlDisposition gcd;
562
563         if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
564                 gcd = Controllable::InverseGroup;
565         } else {
566                 gcd = Controllable::UseGroup;
567         }
568
569         if (ac->toggled()) {
570
571                 /* make it like a single-step, directional switch */
572
573                 if (delta > 0) {
574                         ac->set_value (1.0, gcd);
575                 } else {
576                         ac->set_value (0.0, gcd);
577                 }
578
579         } else if (ac->desc().enumeration || ac->desc().integer_step) {
580
581                 /* use Controllable::get_value() to avoid the
582                  * "scaling-to-interface" that takes place in
583                  * Control::get_value() via the pot member.
584                  *
585                  * an enumeration with 4 values will have interface values of
586                  * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
587                  * deal with that.
588                  */
589
590                 if (delta > 0) {
591                         ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
592                 } else {
593                         ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
594                 }
595
596         } else {
597
598                 double p = ac->get_interface();
599
600                 p += delta;
601
602                 p = max (0.0, p);
603                 p = min (1.0, p);
604
605                 ac->set_value ( ac->interface_to_internal(p), gcd);
606         }
607 }
608
609 void
610 Strip::periodic (ARDOUR::microseconds_t now)
611 {
612
613         update_meter ();
614
615         if ( _trickle_counter %24 == 0 ) {
616
617                 if ( _fader->control() ) {
618                         _surface->write (_fader->set_position (_fader->control()->internal_to_interface (_fader->control()->get_value ())));
619                 } else {
620                         _surface->write (_fader->set_position(0.0));
621                 }
622
623                 if ( _vpot->control() ) {
624                         _surface->write (_vpot->set (_vpot->control()->internal_to_interface (_vpot->control()->get_value ()), true));
625                 } else {
626                         _surface->write (_vpot->set(0.0, false));
627                 }
628
629                 if (_stripable) {
630                         _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
631                         _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
632                         _surface->write (_select->set_state (_stripable->is_selected()));
633                 } else {
634                         _surface->write (_solo->set_state (off));
635                         _surface->write (_mute->set_state (off));
636                         _surface->write (_select->set_state (off));
637                 }
638
639         }
640
641         //after a hard write, queue us for trickling data later
642         if (_trickle_counter == 0)
643                 _trickle_counter = global_index()+1;
644
645         _trickle_counter++;
646
647 }
648
649 void
650 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
651 {
652 }
653
654 void
655 Strip::update_automation ()
656 {
657 }
658
659 void
660 Strip::update_meter ()
661 {
662         if (!_stripable) {
663                 return;
664         }
665
666         if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
667                 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
668                 _meter->send_update (*_surface, dB);
669                 return;
670         }
671 }
672
673 void
674 Strip::zero ()
675 {
676         _trickle_counter = 0;
677 }
678
679 void
680 Strip::lock_controls ()
681 {
682         _controls_locked = true;
683 }
684
685 void
686 Strip::unlock_controls ()
687 {
688         _controls_locked = false;
689 }
690
691 string
692 Strip::vpot_mode_string ()
693 {
694         return "???";
695 }
696
697 void
698 Strip::next_pot_mode ()
699 {
700         vector<AutomationType>::iterator i;
701
702         boost::shared_ptr<AutomationControl> ac = _vpot->control();
703
704         if (!ac) {
705                 return;
706         }
707
708
709         if (_surface->mcp().subview_mode() != US2400Protocol::None) {
710                 return;
711         }
712
713         if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
714                 return;
715         }
716
717         for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
718                 if ((*i) == ac->parameter().type()) {
719                         break;
720                 }
721         }
722
723         /* move to the next mode in the list, or back to the start (which will
724            also happen if the current mode is not in the current pot mode list)
725         */
726
727         if (i != possible_pot_parameters.end()) {
728                 ++i;
729         }
730
731         if (i == possible_pot_parameters.end()) {
732                 i = possible_pot_parameters.begin();
733         }
734
735         set_vpot_parameter (*i);
736 }
737
738 void
739 /*
740  *
741  * name: Strip::subview_mode_changed
742  * @param
743  * @return
744  *
745  */
746 Strip::subview_mode_changed ()
747 {
748         switch (_surface->mcp().subview_mode()) {
749
750         case US2400Protocol::None:
751                 set_vpot_parameter (_pan_mode);
752                 notify_metering_state_changed ();
753                 break;
754
755         case US2400Protocol::TrackView:
756                 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
757                 if (r) {
758                         DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2- assigning trackview pot\n",  _surface->number(), _index));
759                         setup_trackview_vpot (r);
760                 } else {
761                         DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2 - no stripable\n",  _surface->number(), _index));
762                 }
763                 break;
764
765         }
766
767         _trickle_counter = 0;
768 }
769
770 void
771 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
772 {
773 }
774
775 void
776 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
777 {
778 }
779
780 void
781 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
782 {
783
784 }
785
786 void
787 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
788 {
789         subview_connections.drop_connections ();
790
791         if (!r) {
792                 return;
793         }
794
795
796         boost::shared_ptr<AutomationControl> pc;
797         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
798         string label;
799
800         _vpot->set_mode(Pot::wrap);
801
802 #ifdef MIXBUS
803         const uint32_t global_pos = _surface->mcp().global_index (*this);
804
805         //Trim & dynamics
806         switch (global_pos) {
807         case 0:
808                 pc = r->trim_control ();
809                 _vpot->set_mode(Pot::boost_cut);
810                 break;
811
812         case 1:
813                 pc = r->pan_azimuth_control ();
814                 _vpot->set_mode(Pot::dot);
815                 break;
816
817         case 2:
818                 pc = r->comp_threshold_controllable();
819                 break;
820
821         case 3:
822                 pc = r->comp_speed_controllable();
823                 break;
824
825         case 4:
826                 pc = r->comp_mode_controllable();
827                 _vpot->set_mode(Pot::wrap);
828                 break;
829
830         case 5:
831                 pc = r->comp_makeup_controllable();
832                 break;
833
834
835         }  //trim & dynamics
836
837
838         //EQ
839         int eq_band = -1;
840         if (r->mixbus () || r->is_master()) {
841
842                 switch (global_pos) {
843
844                         case 6:
845                                 pc = r->pan_width_control();
846                                 break;
847
848                         case 7:
849                                 pc = r->tape_drive_controllable();
850                                 break;
851
852                         case 8:
853                         case 9:
854                         case 10:
855                                 eq_band = (global_pos-8);
856                                 pc = r->eq_gain_controllable (eq_band);
857                                 _vpot->set_mode(Pot::boost_cut);
858                                 break;
859                 }
860
861         } else if (r->is_input_strip ()) {
862
863 #ifdef MIXBUS32C
864                 switch (global_pos) {
865                         case 6:
866                                 pc = r->filter_freq_controllable(true);
867                                 break;
868                         case 7:
869                                 pc = r->filter_freq_controllable(false);
870                                 break;
871                         case 8:
872                         case 10:
873                         case 12:
874                         case 14: {
875                                 eq_band = (global_pos-8) / 2;
876                                 pc = r->eq_freq_controllable (eq_band);
877                                 } break;
878                         case 9:
879                         case 11:
880                         case 13:
881                         case 15: {
882                                 eq_band = (global_pos-8) / 2;
883                                 pc = r->eq_gain_controllable (eq_band);
884                                 _vpot->set_mode(Pot::boost_cut);
885                                 } break;
886                 }
887
888 #else  //regular Mixbus channel EQ
889
890                 switch (global_pos) {
891                         case 7:
892                                 pc = r->filter_freq_controllable(true);
893                                 break;
894                         case 8:
895                         case 10:
896                         case 12:
897                                 eq_band = (global_pos-8) / 2;
898                                 pc = r->eq_gain_controllable (eq_band);
899                                 _vpot->set_mode(Pot::boost_cut);
900                                 break;
901                         case 9:
902                         case 11:
903                         case 13:
904                                 eq_band = (global_pos-8) / 2;
905                                 pc = r->eq_freq_controllable (eq_band);
906                                 break;
907                 }
908
909
910 #endif
911
912                 //mixbus sends
913                 switch (global_pos) {
914                 case 16:
915                 case 17:
916                 case 18:
917                 case 19:
918                 case 20:
919                 case 21:
920                 case 22:
921                 case 23:
922                         pc = r->send_level_controllable ( global_pos - 16 );
923                         break;
924                 }  //global_pos switch
925
926         } //if input_strip
927 #endif //ifdef MIXBUS
928
929         if (pc) {  //control found; set our knob to watch for changes in it
930                 _vpot->set_control (pc);
931                 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_vpot_change, this), ui_context());
932         } else {  //no control, just set the knob to "empty"
933                 _vpot->reset_control ();
934         }
935
936         notify_vpot_change ();
937 }
938
939 void
940 Strip::set_vpot_parameter (AutomationType p)
941 {
942         if (!_stripable || (p == NullAutomation)) {
943                 _vpot->set_control (boost::shared_ptr<AutomationControl>());
944                 return;
945         }
946
947         boost::shared_ptr<AutomationControl> pan_control;
948
949         DEBUG_TRACE (DEBUG::US2400, string_compose ("switch to vpot mode %1\n", p));
950
951         mark_dirty ();
952
953         switch (p) {
954         case PanAzimuthAutomation:
955                 pan_control = _stripable->pan_azimuth_control ();
956                 break;
957         case PanWidthAutomation:
958                 pan_control = _stripable->pan_width_control ();
959                 break;
960         case PanElevationAutomation:
961                 break;
962         case PanFrontBackAutomation:
963                 break;
964         case PanLFEAutomation:
965                 break;
966         default:
967                 return;
968         }
969
970         if (pan_control) {
971                 _pan_mode = p;
972                 _vpot->set_mode (Pot::dot);
973                 _vpot->set_control (pan_control);
974         }
975
976         notify_panner_azi_changed (true);
977 }
978
979 bool
980 Strip::is_midi_track () const
981 {
982         return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
983 }
984
985 void
986 Strip::mark_dirty ()
987 {
988         _fader->mark_dirty();
989         _vpot->mark_dirty();
990         _solo->mark_dirty();
991         _mute->mark_dirty();
992         _trickle_counter=0;
993 }
994
995 void
996 Strip::notify_metering_state_changed()
997 {
998         if (_surface->mcp().subview_mode() != US2400Protocol::None) {
999                 return;
1000         }
1001
1002         if (!_stripable || !_meter) {
1003                 return;
1004         }
1005
1006         bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1007         bool metering_active = _surface->mcp().metering_active ();
1008
1009         if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1010                 return;
1011         }
1012
1013         _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1014
1015         if (!transport_is_rolling || !metering_active) {
1016                 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1017                 notify_panner_azi_changed (true);
1018         }
1019
1020         _transport_is_rolling = transport_is_rolling;
1021         _metering_active = metering_active;
1022 }