2 Copyright (C) 2006,2007 John Anderson
3 Copyright (C) 2012 Paul Davis
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.
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.
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.
26 #include "midi++/port.h"
28 #include "pbd/compose.h"
29 #include "pbd/convert.h"
31 #include "ardour/amp.h"
32 #include "ardour/bundle.h"
33 #include "ardour/debug.h"
34 #include "ardour/midi_ui.h"
35 #include "ardour/meter.h"
36 #include "ardour/pannable.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/route.h"
41 #include "ardour/session.h"
42 #include "ardour/send.h"
43 #include "ardour/track.h"
44 #include "ardour/user_bundle.h"
46 #include "mackie_control_protocol.h"
47 #include "surface_port.h"
56 using namespace Mackie;
58 using namespace ARDOUR;
61 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
63 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
75 , _controls_locked (false)
76 , _reset_display_at (0)
77 , _last_gain_position_written (-1.0)
78 , _last_pan_azi_position_written (-1.0)
79 , _last_pan_width_position_written (-1.0)
81 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
82 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
83 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
85 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
86 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
87 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
88 _surface->number(), index, Button::id_to_name (bb->bid()),
89 bb->id(), b->second.base_id));
95 /* surface is responsible for deleting all controls */
99 Strip::add (Control & control)
103 Group::add (control);
105 /* fader, vpot, meter were all set explicitly */
107 if ((button = dynamic_cast<Button*>(&control)) != 0) {
108 switch (button->bid()) {
109 case Button::RecEnable:
121 case Button::VSelect:
124 case Button::FaderTouch:
125 _fader_touch = button;
133 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
135 if (_controls_locked) {
139 route_connections.drop_connections ();
141 _solo->set_control (boost::shared_ptr<AutomationControl>());
142 _mute->set_control (boost::shared_ptr<AutomationControl>());
143 _select->set_control (boost::shared_ptr<AutomationControl>());
144 _recenable->set_control (boost::shared_ptr<AutomationControl>());
145 _fader->set_control (boost::shared_ptr<AutomationControl>());
146 _vpot->set_control (boost::shared_ptr<AutomationControl>());
150 control_by_parameter.clear ();
151 reset_saved_values ();
158 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
159 _surface->number(), _index, _route->name()));
161 _solo->set_control (_route->solo_control());
162 _mute->set_control (_route->mute_control());
164 set_vpot_parameter (PanAzimuthAutomation);
166 _route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
167 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
169 boost::shared_ptr<Pannable> pannable = _route->pannable();
171 if (pannable && pannable->panner()) {
172 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
173 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
175 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
176 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
178 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
181 _recenable->set_control (trk->rec_enable_control());
182 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
187 // TODO this works when a currently-banked route is made inactive, but not
188 // when a route is activated which should be currently banked.
190 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
191 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
197 /* setup legal VPot modes for this route */
199 build_input_list (_route->input()->n_ports());
200 build_output_list (_route->output()->n_ports());
202 possible_pot_parameters.clear();
205 boost::shared_ptr<Panner> panner = pannable->panner();
207 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
208 set<Evoral::Parameter>::iterator a;
210 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
211 possible_pot_parameters.push_back (PanAzimuthAutomation);
214 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
215 possible_pot_parameters.push_back (PanWidthAutomation);
229 notify_solo_changed ();
230 notify_mute_changed ();
231 notify_gain_changed ();
232 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
233 notify_panner_azi_changed ();
234 notify_panner_width_changed ();
235 notify_record_enable_changed ();
239 Strip::notify_solo_changed ()
241 if (_route && _solo) {
242 _surface->write (_solo->set_state (_route->soloed() ? on : off));
247 Strip::notify_mute_changed ()
249 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
250 if (_route && _mute) {
251 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
252 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
254 _surface->write (_mute->set_state (_route->muted() ? on : off));
259 Strip::notify_record_enable_changed ()
261 if (_route && _recenable) {
262 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
267 Strip::notify_active_changed ()
269 _surface->mcp().refresh_current_bank();
273 Strip::notify_route_deleted ()
275 _surface->mcp().refresh_current_bank();
279 Strip::notify_gain_changed (bool force_update)
285 if (_surface->mcp().flip_mode()) {
292 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
294 float gain_coefficient = ac->get_value();
295 float normalized_position = ac->internal_to_interface (gain_coefficient);
297 if (force_update || normalized_position != _last_gain_position_written) {
299 if (_surface->mcp().flip_mode()) {
300 if (!control->in_use()) {
301 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
303 do_parameter_display (GainAutomation, gain_coefficient);
305 if (!control->in_use()) {
306 _surface->write (_fader->set_position (normalized_position));
308 do_parameter_display (GainAutomation, gain_coefficient);
311 queue_display_reset (2000);
312 _last_gain_position_written = normalized_position;
318 Strip::notify_property_changed (const PropertyChange& what_changed)
320 if (!what_changed.contains (ARDOUR::Properties::name)) {
326 string fullname = _route->name();
328 if (fullname.length() <= 6) {
331 line1 = PBD::short_version (fullname, 6);
334 _surface->write (display (0, line1));
339 Strip::notify_panner_azi_changed (bool force_update)
343 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
345 boost::shared_ptr<Pannable> pannable = _route->pannable();
347 if (!pannable || !pannable->panner()) {
348 _surface->write (_vpot->zero());
352 Control* control = control_by_parameter[PanAzimuthAutomation];
358 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
360 if (force_update || pos != _last_pan_azi_position_written) {
362 if (control == _fader) {
363 if (!_fader->in_use()) {
364 _surface->write (_fader->set_position (pos));
366 } else if (control == _vpot) {
367 _surface->write (_vpot->set (pos, true, Pot::dot));
370 do_parameter_display (PanAzimuthAutomation, pos);
371 queue_display_reset (2000);
372 _last_pan_azi_position_written = pos;
378 Strip::notify_panner_width_changed (bool force_update)
382 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
384 boost::shared_ptr<Pannable> pannable = _route->pannable();
386 if (!pannable || !pannable->panner()) {
387 _surface->write (_vpot->zero());
392 Control* control = control_by_parameter[PanWidthAutomation];
398 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
400 if (force_update || pos != _last_pan_azi_position_written) {
402 if (_surface->mcp().flip_mode()) {
404 if (control == _fader) {
405 if (!control->in_use()) {
406 _surface->write (_fader->set_position (pos));
410 } else if (control == _vpot) {
411 _surface->write (_vpot->set (pos, true, Pot::spread));
414 do_parameter_display (PanWidthAutomation, pos);
415 queue_display_reset (2000);
416 _last_pan_azi_position_written = pos;
422 Strip::select_event (Button&, ButtonState bs)
424 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
428 int ms = _surface->mcp().modifier_state();
430 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
431 _controls_locked = !_controls_locked;
432 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
433 queue_display_reset (1000);
437 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
438 /* reset to default */
439 boost::shared_ptr<AutomationControl> ac = _fader->control ();
441 ac->set_value (ac->normal());
446 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
447 _surface->mcp().add_down_select_button (_surface->number(), _index);
448 _surface->mcp().select_range ();
451 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
452 _surface->mcp().remove_down_select_button (_surface->number(), _index);
457 Strip::vselect_event (Button&, ButtonState bs)
461 int ms = _surface->mcp().modifier_state();
463 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
465 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
469 /* reset to default/normal value */
470 ac->set_value (ac->normal());
475 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
483 Strip::fader_touch_event (Button&, ButtonState bs)
485 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
489 boost::shared_ptr<AutomationControl> ac = _fader->control ();
491 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
493 ac->set_value (ac->normal());
497 _fader->set_in_use (true);
498 _fader->start_touch (_surface->mcp().transport_frame());
501 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
502 queue_display_reset (2000);
508 _fader->set_in_use (false);
509 _fader->stop_touch (_surface->mcp().transport_frame(), true);
516 Strip::handle_button (Button& button, ButtonState bs)
518 boost::shared_ptr<AutomationControl> control;
521 button.set_in_use (true);
523 button.set_in_use (false);
526 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
528 switch (button.bid()) {
530 select_event (button, bs);
533 case Button::VSelect:
534 vselect_event (button, bs);
537 case Button::FaderTouch:
538 fader_touch_event (button, bs);
542 if ((control = button.control ())) {
544 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
545 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
548 int ms = _surface->mcp().modifier_state();
550 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
551 /* reset to default/normal value */
552 new_value = control->normal();
554 new_value = control->get_value() ? 0.0 : 1.0;
557 /* get all controls that either have their
558 * button down or are within a range of
559 * several down buttons
562 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
565 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
566 controls.size(), control->parameter().type(), new_value));
570 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
571 (*c)->set_value (new_value);
575 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
576 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
584 Strip::do_parameter_display (AutomationType type, float val)
589 _surface->write (display (1, " -inf "));
592 float dB = accurate_coefficient_to_dB (val);
593 snprintf (buf, sizeof (buf), "%6.1f", dB);
594 _surface->write (display (1, buf));
598 case PanAzimuthAutomation:
600 boost::shared_ptr<Pannable> p = _route->pannable();
601 if (p && p->panner()) {
602 string str = p->panner()->value_as_string (p->pan_azimuth_control);
603 _surface->write (display (1, str));
608 case PanWidthAutomation:
611 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
612 _surface->write (display (1, buf));
622 Strip::handle_fader (Fader& fader, float position)
624 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
626 fader.set_value (position);
627 fader.start_touch (_surface->mcp().transport_frame());
628 queue_display_reset (2000);
630 // must echo bytes back to slider now, because
631 // the notifier only works if the fader is not being
632 // touched. Which it is if we're getting input.
634 _surface->write (fader.set_position (position));
638 Strip::handle_pot (Pot& pot, float delta)
640 /* Pots only emit events when they move, not when they
641 stop moving. So to get a stop event, we need to use a timeout.
644 boost::shared_ptr<AutomationControl> ac = pot.control();
645 double p = pot.get_value ();
647 p = max (ac->lower(), p);
648 p = min (ac->upper(), p);
653 Strip::periodic (uint64_t usecs)
659 update_automation ();
662 if (_reset_display_at && _reset_display_at < usecs) {
668 Strip::update_automation ()
670 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
672 if (gain_state == Touch || gain_state == Play) {
673 notify_gain_changed (false);
676 if (_route->panner()) {
677 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
678 if (panner_state == Touch || panner_state == Play) {
679 notify_panner_azi_changed (false);
680 notify_panner_width_changed (false);
686 Strip::update_meter ()
689 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
690 _surface->write (_meter->update_message (dB));
697 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
698 _surface->write ((*it)->zero ());
701 _surface->write (blank_display (0));
702 _surface->write (blank_display (1));
706 Strip::blank_display (uint32_t line_number)
708 return display (line_number, string());
712 Strip::display (uint32_t line_number, const std::string& line)
714 assert (line_number <= 1);
716 MidiByteArray retval;
718 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
721 retval << _surface->sysex_hdr();
725 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
726 retval << (_index * 7 + (line_number * 0x38));
728 // ascii data to display
730 // pad with " " out to 6 chars
731 for (int i = line.length(); i < 6; ++i) {
735 // column spacer, unless it's the right-hand column
747 Strip::lock_controls ()
749 _controls_locked = true;
753 Strip::unlock_controls ()
755 _controls_locked = false;
759 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
761 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
762 if ((*i) == _route) {
763 _surface->write (_select->set_state (on));
768 _surface->write (_select->set_state (off));
772 Strip::vpot_mode_string () const
774 boost::shared_ptr<AutomationControl> ac = _vpot->control();
780 switch (ac->parameter().type()) {
783 case PanAzimuthAutomation:
785 case PanWidthAutomation:
787 case PanElevationAutomation:
789 case PanFrontBackAutomation:
791 case PanLFEAutomation:
799 Strip::flip_mode_changed (bool notify)
805 reset_saved_values ();
807 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
808 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
810 _fader->set_control (vpot_controllable);
811 _vpot->set_control (fader_controllable);
813 control_by_parameter[fader_controllable->parameter()] = _vpot;
814 control_by_parameter[vpot_controllable->parameter()] = _fader;
816 _surface->write (display (1, vpot_mode_string ()));
824 Strip::queue_display_reset (uint32_t msecs)
827 struct timeval delta;
829 gettimeofday (&now, 0);
831 delta.tv_sec = msecs/1000;
832 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
834 timeradd (&now, &delta, &when);
836 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
840 Strip::clear_display_reset ()
842 _reset_display_at = 0;
846 Strip::reset_display ()
849 _surface->write (display (1, vpot_mode_string()));
851 _surface->write (blank_display (1));
854 clear_display_reset ();
857 struct RouteCompareByName {
858 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
859 return a->name().compare (b->name()) < 0;
864 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
866 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
874 Strip::build_input_list (const ChanCount& channels)
876 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
878 input_bundles.clear ();
880 /* give user bundles first chance at being in the menu */
882 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
883 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
884 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
888 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
889 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
890 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
894 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
895 RouteList copy = *routes;
896 copy.sort (RouteCompareByName ());
898 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
899 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
905 Strip::build_output_list (const ChanCount& channels)
907 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
909 output_bundles.clear ();
911 /* give user bundles first chance at being in the menu */
913 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
914 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
915 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
919 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
920 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
921 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
925 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
926 RouteList copy = *routes;
927 copy.sort (RouteCompareByName ());
929 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
930 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
935 Strip::next_pot_mode ()
937 vector<Evoral::Parameter>::iterator i;
939 if (_surface->mcp().flip_mode()) {
940 /* do not change vpot mode while in flipped mode */
941 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
942 _surface->write (display (1, "Flip"));
943 queue_display_reset (1000);
948 boost::shared_ptr<AutomationControl> ac = _vpot->control();
954 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
958 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
959 if ((*i) == ac->parameter()) {
964 /* move to the next mode in the list, or back to the start (which will
965 also happen if the current mode is not in the current pot mode list)
968 if (i != possible_pot_parameters.end()) {
972 if (i == possible_pot_parameters.end()) {
973 i = possible_pot_parameters.begin();
976 set_vpot_parameter (*i);
980 Strip::set_vpot_parameter (Evoral::Parameter p)
982 boost::shared_ptr<Pannable> pannable;
984 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
986 reset_saved_values ();
989 case PanAzimuthAutomation:
990 pannable = _route->pannable ();
992 if (_surface->mcp().flip_mode()) {
993 /* gain to vpot, pan azi to fader */
994 _vpot->set_control (_route->gain_control());
995 control_by_parameter[GainAutomation] = _vpot;
997 _fader->set_control (pannable->pan_azimuth_control);
998 control_by_parameter[PanAzimuthAutomation] = _fader;
1000 _fader->set_control (boost::shared_ptr<AutomationControl>());
1001 control_by_parameter[PanAzimuthAutomation] = 0;
1004 /* gain to fader, pan azi to vpot */
1005 _fader->set_control (_route->gain_control());
1006 control_by_parameter[GainAutomation] = _fader;
1008 _vpot->set_control (pannable->pan_azimuth_control);
1009 control_by_parameter[PanAzimuthAutomation] = _vpot;
1011 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1012 control_by_parameter[PanAzimuthAutomation] = 0;
1017 case PanWidthAutomation:
1018 pannable = _route->pannable ();
1020 if (_surface->mcp().flip_mode()) {
1021 /* gain to vpot, pan width to fader */
1022 _vpot->set_control (_route->gain_control());
1023 control_by_parameter[GainAutomation] = _vpot;
1025 _fader->set_control (pannable->pan_width_control);
1026 control_by_parameter[PanWidthAutomation] = _fader;
1028 _fader->set_control (boost::shared_ptr<AutomationControl>());
1029 control_by_parameter[PanWidthAutomation] = 0;
1032 /* gain to fader, pan width to vpot */
1033 _fader->set_control (_route->gain_control());
1034 control_by_parameter[GainAutomation] = _fader;
1036 _vpot->set_control (pannable->pan_width_control);
1037 control_by_parameter[PanWidthAutomation] = _vpot;
1039 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1040 control_by_parameter[PanWidthAutomation] = 0;
1045 case PanElevationAutomation:
1047 case PanFrontBackAutomation:
1049 case PanLFEAutomation:
1053 _surface->write (display (1, vpot_mode_string()));
1057 Strip::reset_saved_values ()
1059 _last_pan_azi_position_written = -1.0;
1060 _last_pan_width_position_written = -1.0;
1061 _last_gain_position_written = -1.0;