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 ();
157 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
158 _surface->number(), _index, _route->name()));
160 _solo->set_control (_route->solo_control());
161 _mute->set_control (_route->mute_control());
163 set_vpot_parameter (PanAzimuthAutomation);
165 _route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
166 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
168 boost::shared_ptr<Pannable> pannable = _route->pannable();
171 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
172 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
174 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
175 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
177 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
180 _recenable->set_control (trk->rec_enable_control());
181 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
186 // TODO this works when a currently-banked route is made inactive, but not
187 // when a route is activated which should be currently banked.
189 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
190 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
196 /* setup legal VPot modes for this route */
198 build_input_list (_route->input()->n_ports());
199 build_output_list (_route->output()->n_ports());
201 current_pot_modes.clear();
204 boost::shared_ptr<Panner> panner = pannable->panner();
206 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
207 set<Evoral::Parameter>::iterator a;
209 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
210 current_pot_modes.push_back (PanAzimuthAutomation);
213 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
214 current_pot_modes.push_back (PanWidthAutomation);
217 std::cerr << "connected to route without a panner\n";
230 notify_solo_changed ();
231 notify_mute_changed ();
232 notify_gain_changed ();
233 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
234 notify_panner_azi_changed ();
235 notify_panner_width_changed ();
236 notify_record_enable_changed ();
240 Strip::notify_solo_changed ()
242 if (_route && _solo) {
243 _surface->write (_solo->set_state (_route->soloed() ? on : off));
248 Strip::notify_mute_changed ()
250 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
251 if (_route && _mute) {
252 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
253 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
255 _surface->write (_mute->set_state (_route->muted() ? on : off));
260 Strip::notify_record_enable_changed ()
262 if (_route && _recenable) {
263 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
268 Strip::notify_active_changed ()
270 _surface->mcp().refresh_current_bank();
274 Strip::notify_route_deleted ()
276 _surface->mcp().refresh_current_bank();
280 Strip::notify_gain_changed (bool force_update)
286 if (_surface->mcp().flip_mode()) {
293 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
295 float gain_coefficient = ac->get_value();
296 float normalized_position = ac->internal_to_interface (gain_coefficient);
298 if (force_update || normalized_position != _last_gain_position_written) {
300 if (_surface->mcp().flip_mode()) {
301 if (!control->in_use()) {
302 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
304 do_parameter_display (GainAutomation, gain_coefficient);
306 if (!control->in_use()) {
307 _surface->write (_fader->set_position (normalized_position));
309 do_parameter_display (GainAutomation, gain_coefficient);
312 queue_display_reset (2000);
313 _last_gain_position_written = normalized_position;
319 Strip::notify_property_changed (const PropertyChange& what_changed)
321 if (!what_changed.contains (ARDOUR::Properties::name)) {
327 string fullname = _route->name();
329 if (fullname.length() <= 6) {
332 line1 = PBD::short_version (fullname, 6);
335 _surface->write (display (0, line1));
340 Strip::notify_panner_azi_changed (bool force_update)
344 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
346 boost::shared_ptr<Pannable> pannable = _route->pannable();
349 _surface->write (_vpot->zero());
353 Control* control = control_by_parameter[PanAzimuthAutomation];
359 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
361 if (force_update || pos != _last_pan_azi_position_written) {
363 if (control == _fader) {
364 if (!_fader->in_use()) {
365 _surface->write (_fader->set_position (pos));
367 } else if (control == _vpot) {
368 _surface->write (_vpot->set (pos, true, Pot::dot));
371 do_parameter_display (PanAzimuthAutomation, pos);
372 queue_display_reset (2000);
373 _last_pan_azi_position_written = pos;
379 Strip::notify_panner_width_changed (bool force_update)
383 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
385 boost::shared_ptr<Pannable> pannable = _route->pannable();
388 _surface->write (_vpot->zero());
393 Control* control = control_by_parameter[PanWidthAutomation];
399 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
401 if (force_update || pos != _last_pan_azi_position_written) {
403 if (_surface->mcp().flip_mode()) {
405 if (control == _fader) {
406 if (!control->in_use()) {
407 _surface->write (_fader->set_position (pos));
411 } else if (control == _vpot) {
412 _surface->write (_vpot->set (pos, true, Pot::spread));
415 do_parameter_display (PanWidthAutomation, pos);
416 queue_display_reset (2000);
417 _last_pan_azi_position_written = pos;
423 Strip::select_event (Button& button, ButtonState bs)
425 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
429 int ms = _surface->mcp().modifier_state();
431 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
432 _controls_locked = !_controls_locked;
433 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
434 queue_display_reset (1000);
438 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
439 /* reset to default */
440 boost::shared_ptr<AutomationControl> ac = _fader->control ();
442 ac->set_value (ac->normal());
447 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
448 _surface->mcp().add_down_select_button (_surface->number(), _index);
449 _surface->mcp().select_range ();
452 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
453 _surface->mcp().remove_down_select_button (_surface->number(), _index);
458 Strip::vselect_event (Button& button, ButtonState bs)
463 int ms = _surface->mcp().modifier_state();
465 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
466 boost::shared_ptr<AutomationControl> ac = button.control ();
470 /* reset to default/normal value */
471 ac->set_value (ac->normal());
475 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
483 Strip::fader_touch_event (Button& 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 (ARDOUR::RouteNotificationListPtr rl)
761 for (ARDOUR::RouteNotificationList::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);
947 boost::shared_ptr<AutomationControl> ac = _vpot->control();
953 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
954 if ((*i) == ac->parameter()) {
959 /* move to the next mode in the list, or back to the start (which will
960 also happen if the current mode is not in the current pot mode list)
963 if (i != current_pot_modes.end()) {
967 if (i == current_pot_modes.end()) {
968 i = current_pot_modes.begin();
971 set_vpot_parameter (*i);
975 Strip::set_vpot_parameter (Evoral::Parameter p)
977 boost::shared_ptr<Pannable> pannable;
979 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
981 reset_saved_values ();
984 case PanAzimuthAutomation:
985 pannable = _route->pannable ();
987 if (_surface->mcp().flip_mode()) {
988 /* gain to vpot, pan azi to fader */
989 _vpot->set_control (_route->gain_control());
990 control_by_parameter[GainAutomation] = _vpot;
992 _fader->set_control (pannable->pan_azimuth_control);
993 control_by_parameter[PanAzimuthAutomation] = _fader;
995 _fader->set_control (boost::shared_ptr<AutomationControl>());
996 control_by_parameter[PanAzimuthAutomation] = 0;
999 /* gain to fader, pan azi to vpot */
1000 _fader->set_control (_route->gain_control());
1001 control_by_parameter[GainAutomation] = _fader;
1003 _vpot->set_control (pannable->pan_azimuth_control);
1004 control_by_parameter[PanAzimuthAutomation] = _vpot;
1006 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1007 control_by_parameter[PanAzimuthAutomation] = 0;
1012 case PanWidthAutomation:
1013 pannable = _route->pannable ();
1015 if (_surface->mcp().flip_mode()) {
1016 /* gain to vpot, pan width to fader */
1017 _vpot->set_control (_route->gain_control());
1018 control_by_parameter[GainAutomation] = _vpot;
1020 _fader->set_control (pannable->pan_width_control);
1021 control_by_parameter[PanWidthAutomation] = _fader;
1023 _fader->set_control (boost::shared_ptr<AutomationControl>());
1024 control_by_parameter[PanWidthAutomation] = 0;
1027 /* gain to fader, pan width to vpot */
1028 _fader->set_control (_route->gain_control());
1029 control_by_parameter[GainAutomation] = _fader;
1031 _vpot->set_control (pannable->pan_width_control);
1032 control_by_parameter[PanWidthAutomation] = _vpot;
1034 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1035 control_by_parameter[PanWidthAutomation] = 0;
1040 case PanElevationAutomation:
1042 case PanFrontBackAutomation:
1044 case PanLFEAutomation:
1048 _surface->write (display (1, vpot_mode_string()));
1052 Strip::reset_saved_values ()
1054 _last_pan_azi_position_written = -1.0;
1055 _last_pan_width_position_written = -1.0;
1056 _last_gain_position_written = -1.0;