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 */
62 #define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
64 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
76 , _controls_locked (false)
77 , _reset_display_at (0)
78 , _last_gain_position_written (-1.0)
79 , _last_pan_azi_position_written (-1.0)
80 , _last_pan_width_position_written (-1.0)
82 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
83 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
84 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
87 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
88 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
89 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
90 _surface->number(), index, Button::id_to_name (bb->bid()),
91 bb->id(), b->second.base_id));
98 /* surface is responsible for deleting all controls */
102 Strip::add (Control & control)
106 Group::add (control);
108 /* fader, vpot, meter were all set explicitly */
110 if ((button = dynamic_cast<Button*>(&control)) != 0) {
111 switch (button->bid()) {
112 case Button::RecEnable:
124 case Button::VSelect:
127 case Button::FaderTouch:
128 _fader_touch = button;
136 Strip::set_route (boost::shared_ptr<Route> r, bool with_messages)
138 if (_controls_locked) {
142 route_connections.drop_connections ();
144 _solo->set_control (boost::shared_ptr<AutomationControl>());
145 _mute->set_control (boost::shared_ptr<AutomationControl>());
146 _select->set_control (boost::shared_ptr<AutomationControl>());
147 _recenable->set_control (boost::shared_ptr<AutomationControl>());
148 _fader->set_control (boost::shared_ptr<AutomationControl>());
149 _vpot->set_control (boost::shared_ptr<AutomationControl>());
153 control_by_parameter.clear ();
154 reset_saved_values ();
160 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
161 _surface->number(), _index, _route->name()));
163 _solo->set_control (_route->solo_control());
164 _mute->set_control (_route->mute_control());
166 set_vpot_parameter (PanAzimuthAutomation);
168 _route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_solo_changed, this), ui_context());
169 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_mute_changed, this), ui_context());
171 boost::shared_ptr<Pannable> pannable = _route->pannable();
174 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
175 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_panner_width_changed, this, false), ui_context());
177 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
178 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_property_changed, this, _1), ui_context());
180 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
183 _recenable->set_control (trk->rec_enable_control());
184 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_record_enable_changed, this), ui_context());
189 // TODO this works when a currently-banked route is made inactive, but not
190 // when a route is activated which should be currently banked.
192 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_active_changed, this), ui_context());
193 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_route_deleted, this), ui_context());
199 /* setup legal VPot modes for this route */
201 build_input_list (_route->input()->n_ports());
202 build_output_list (_route->output()->n_ports());
204 current_pot_modes.clear();
207 boost::shared_ptr<Panner> panner = pannable->panner();
209 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
210 set<Evoral::Parameter>::iterator a;
212 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
213 current_pot_modes.push_back (PanAzimuthAutomation);
216 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
217 current_pot_modes.push_back (PanWidthAutomation);
231 notify_solo_changed ();
232 notify_mute_changed ();
233 notify_gain_changed ();
234 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
235 notify_panner_azi_changed ();
236 notify_panner_width_changed ();
237 notify_record_enable_changed ();
241 Strip::notify_solo_changed ()
243 if (_route && _solo) {
244 _surface->write (_solo->set_state (_route->soloed() ? on : off));
249 Strip::notify_mute_changed ()
251 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
252 if (_route && _mute) {
253 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
254 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
256 _surface->write (_mute->set_state (_route->muted() ? on : off));
261 Strip::notify_record_enable_changed ()
263 if (_route && _recenable) {
264 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
269 Strip::notify_active_changed ()
271 _surface->mcp().refresh_current_bank();
275 Strip::notify_route_deleted ()
277 _surface->mcp().refresh_current_bank();
281 Strip::notify_gain_changed (bool force_update)
287 if (_surface->mcp().flip_mode()) {
294 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
296 float gain_coefficient = ac->get_value();
297 float normalized_position = ac->internal_to_interface (gain_coefficient);
299 if (force_update || normalized_position != _last_gain_position_written) {
301 if (_surface->mcp().flip_mode()) {
302 if (!control->in_use()) {
303 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
305 do_parameter_display (GainAutomation, gain_coefficient);
307 if (!control->in_use()) {
308 _surface->write (_fader->set_position (normalized_position));
310 do_parameter_display (GainAutomation, gain_coefficient);
313 queue_display_reset (2000);
314 _last_gain_position_written = normalized_position;
320 Strip::notify_property_changed (const PropertyChange& what_changed)
322 if (!what_changed.contains (ARDOUR::Properties::name)) {
328 string fullname = _route->name();
330 if (fullname.length() <= 6) {
333 line1 = PBD::short_version (fullname, 6);
336 _surface->write (display (0, line1));
341 Strip::notify_panner_azi_changed (bool force_update)
345 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
347 boost::shared_ptr<Pannable> pannable = _route->pannable();
350 _surface->write (_vpot->zero());
354 Control* control = control_by_parameter[PanAzimuthAutomation];
360 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
362 if (force_update || pos != _last_pan_azi_position_written) {
364 if (control == _fader) {
365 if (!_fader->in_use()) {
366 _surface->write (_fader->set_position (pos));
368 } else if (control == _vpot) {
369 _surface->write (_vpot->set (pos, true, Pot::dot));
372 do_parameter_display (PanAzimuthAutomation, pos);
373 queue_display_reset (2000);
374 _last_pan_azi_position_written = pos;
380 Strip::notify_panner_width_changed (bool force_update)
384 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
386 boost::shared_ptr<Pannable> pannable = _route->pannable();
389 _surface->write (_vpot->zero());
394 Control* control = control_by_parameter[PanWidthAutomation];
400 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
402 if (force_update || pos != _last_pan_azi_position_written) {
404 if (_surface->mcp().flip_mode()) {
406 if (control == _fader) {
407 if (!control->in_use()) {
408 _surface->write (_fader->set_position (pos));
412 } else if (control == _vpot) {
413 _surface->write (_vpot->set (pos, true, Pot::spread));
416 do_parameter_display (PanWidthAutomation, pos);
417 queue_display_reset (2000);
418 _last_pan_azi_position_written = pos;
424 Strip::select_event (Button& button, ButtonState bs)
426 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
430 int ms = _surface->mcp().modifier_state();
432 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
433 _controls_locked = !_controls_locked;
434 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
435 queue_display_reset (1000);
439 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
440 /* reset to default */
441 boost::shared_ptr<AutomationControl> ac = _fader->control ();
443 ac->set_value (ac->normal());
448 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
449 _surface->mcp().add_down_select_button (_surface->number(), _index);
450 _surface->mcp().select_range ();
453 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
454 _surface->mcp().remove_down_select_button (_surface->number(), _index);
459 Strip::vselect_event (Button& button, ButtonState bs)
464 int ms = _surface->mcp().modifier_state();
466 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
467 boost::shared_ptr<AutomationControl> ac = button.control ();
471 /* reset to default/normal value */
472 ac->set_value (ac->normal());
476 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
484 Strip::fader_touch_event (Button& button, ButtonState bs)
486 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
490 boost::shared_ptr<AutomationControl> ac = _fader->control ();
492 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
494 ac->set_value (ac->normal());
498 _fader->set_in_use (true);
499 _fader->start_touch (_surface->mcp().transport_frame());
502 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
503 queue_display_reset (2000);
509 _fader->set_in_use (false);
510 _fader->stop_touch (_surface->mcp().transport_frame(), true);
517 Strip::handle_button (Button& button, ButtonState bs)
519 boost::shared_ptr<AutomationControl> control;
522 button.set_in_use (true);
524 button.set_in_use (false);
527 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
529 switch (button.bid()) {
531 select_event (button, bs);
534 case Button::VSelect:
535 vselect_event (button, bs);
538 case Button::FaderTouch:
539 fader_touch_event (button, bs);
543 if ((control = button.control ())) {
545 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
546 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
549 int ms = _surface->mcp().modifier_state();
551 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
552 /* reset to default/normal value */
553 new_value = control->normal();
555 new_value = control->get_value() ? 0.0 : 1.0;
558 /* get all controls that either have their
559 * button down or are within a range of
560 * several down buttons
563 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
566 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
567 controls.size(), control->parameter().type(), new_value));
571 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
572 (*c)->set_value (new_value);
576 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
577 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
585 Strip::do_parameter_display (AutomationType type, float val)
590 _surface->write (display (1, " -inf "));
593 float dB = accurate_coefficient_to_dB (val);
594 snprintf (buf, sizeof (buf), "%6.1f", dB);
595 _surface->write (display (1, buf));
599 case PanAzimuthAutomation:
601 boost::shared_ptr<Pannable> p = _route->pannable();
602 if (p && p->panner()) {
603 string str = p->panner()->value_as_string (p->pan_azimuth_control);
604 _surface->write (display (1, str));
609 case PanWidthAutomation:
612 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
613 _surface->write (display (1, buf));
623 Strip::handle_fader (Fader& fader, float position)
625 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
627 fader.set_value (position);
628 fader.start_touch (_surface->mcp().transport_frame());
629 queue_display_reset (2000);
631 // must echo bytes back to slider now, because
632 // the notifier only works if the fader is not being
633 // touched. Which it is if we're getting input.
635 _surface->write (fader.set_position (position));
639 Strip::handle_pot (Pot& pot, float delta)
641 /* Pots only emit events when they move, not when they
642 stop moving. So to get a stop event, we need to use a timeout.
645 boost::shared_ptr<AutomationControl> ac = pot.control();
646 double p = pot.get_value ();
648 p = max (ac->lower(), p);
649 p = min (ac->upper(), p);
654 Strip::periodic (uint64_t usecs)
660 update_automation ();
663 if (_reset_display_at && _reset_display_at < usecs) {
669 Strip::update_automation ()
671 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
673 if (gain_state == Touch || gain_state == Play) {
674 notify_gain_changed (false);
677 if (_route->panner()) {
678 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
679 if (panner_state == Touch || panner_state == Play) {
680 notify_panner_azi_changed (false);
681 notify_panner_width_changed (false);
687 Strip::update_meter ()
690 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
691 _surface->write (_meter->update_message (dB));
698 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
699 _surface->write ((*it)->zero ());
702 _surface->write (blank_display (0));
703 _surface->write (blank_display (1));
707 Strip::blank_display (uint32_t line_number)
709 return display (line_number, string());
713 Strip::display (uint32_t line_number, const std::string& line)
715 assert (line_number <= 1);
717 MidiByteArray retval;
719 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
722 retval << _surface->sysex_hdr();
726 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
727 retval << (_index * 7 + (line_number * 0x38));
729 // ascii data to display
731 // pad with " " out to 6 chars
732 for (int i = line.length(); i < 6; ++i) {
736 // column spacer, unless it's the right-hand column
748 Strip::lock_controls ()
750 _controls_locked = true;
754 Strip::unlock_controls ()
756 _controls_locked = false;
760 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
762 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
763 if ((*i) == _route) {
764 _surface->write (_select->set_state (on));
769 _surface->write (_select->set_state (off));
773 Strip::vpot_mode_string () const
775 boost::shared_ptr<AutomationControl> ac = _vpot->control();
781 switch (ac->parameter().type()) {
784 case PanAzimuthAutomation:
786 case PanWidthAutomation:
788 case PanElevationAutomation:
790 case PanFrontBackAutomation:
792 case PanLFEAutomation:
800 Strip::flip_mode_changed (bool notify)
806 reset_saved_values ();
808 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
809 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
811 _fader->set_control (vpot_controllable);
812 _vpot->set_control (fader_controllable);
814 control_by_parameter[fader_controllable->parameter()] = _vpot;
815 control_by_parameter[vpot_controllable->parameter()] = _fader;
817 _surface->write (display (1, vpot_mode_string ()));
825 Strip::queue_display_reset (uint32_t msecs)
828 struct timeval delta;
830 gettimeofday (&now, 0);
832 delta.tv_sec = msecs/1000;
833 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
835 timeradd (&now, &delta, &when);
837 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
841 Strip::clear_display_reset ()
843 _reset_display_at = 0;
847 Strip::reset_display ()
850 _surface->write (display (1, vpot_mode_string()));
852 _surface->write (blank_display (1));
855 clear_display_reset ();
858 struct RouteCompareByName {
859 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
860 return a->name().compare (b->name()) < 0;
865 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
867 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
875 Strip::build_input_list (const ChanCount& channels)
877 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
879 input_bundles.clear ();
881 /* give user bundles first chance at being in the menu */
883 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
884 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
885 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
889 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
890 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
891 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
895 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
896 RouteList copy = *routes;
897 copy.sort (RouteCompareByName ());
899 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
900 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
906 Strip::build_output_list (const ChanCount& channels)
908 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
910 output_bundles.clear ();
912 /* give user bundles first chance at being in the menu */
914 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
915 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
916 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
920 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
921 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
922 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
926 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
927 RouteList copy = *routes;
928 copy.sort (RouteCompareByName ());
930 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
931 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
936 Strip::next_pot_mode ()
938 vector<Evoral::Parameter>::iterator i;
940 if (_surface->mcp().flip_mode()) {
941 /* do not change vpot mode while in flipped mode */
942 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
943 _surface->write (display (1, "Flip"));
944 queue_display_reset (1000);
948 boost::shared_ptr<AutomationControl> ac = _vpot->control();
954 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
955 if ((*i) == ac->parameter()) {
960 /* move to the next mode in the list, or back to the start (which will
961 also happen if the current mode is not in the current pot mode list)
964 if (i != current_pot_modes.end()) {
968 if (i == current_pot_modes.end()) {
969 i = current_pot_modes.begin();
972 set_vpot_parameter (*i);
976 Strip::set_vpot_parameter (Evoral::Parameter p)
978 boost::shared_ptr<Pannable> pannable;
980 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
982 reset_saved_values ();
985 case PanAzimuthAutomation:
986 pannable = _route->pannable ();
988 if (_surface->mcp().flip_mode()) {
989 /* gain to vpot, pan azi to fader */
990 _vpot->set_control (_route->gain_control());
991 control_by_parameter[GainAutomation] = _vpot;
993 _fader->set_control (pannable->pan_azimuth_control);
994 control_by_parameter[PanAzimuthAutomation] = _fader;
996 _fader->set_control (boost::shared_ptr<AutomationControl>());
997 control_by_parameter[PanAzimuthAutomation] = 0;
1000 /* gain to fader, pan azi to vpot */
1001 _fader->set_control (_route->gain_control());
1002 control_by_parameter[GainAutomation] = _fader;
1004 _vpot->set_control (pannable->pan_azimuth_control);
1005 control_by_parameter[PanAzimuthAutomation] = _vpot;
1007 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1008 control_by_parameter[PanAzimuthAutomation] = 0;
1013 case PanWidthAutomation:
1014 pannable = _route->pannable ();
1016 if (_surface->mcp().flip_mode()) {
1017 /* gain to vpot, pan width to fader */
1018 _vpot->set_control (_route->gain_control());
1019 control_by_parameter[GainAutomation] = _vpot;
1021 _fader->set_control (pannable->pan_width_control);
1022 control_by_parameter[PanWidthAutomation] = _fader;
1024 _fader->set_control (boost::shared_ptr<AutomationControl>());
1025 control_by_parameter[PanWidthAutomation] = 0;
1028 /* gain to fader, pan width to vpot */
1029 _fader->set_control (_route->gain_control());
1030 control_by_parameter[GainAutomation] = _fader;
1032 _vpot->set_control (pannable->pan_width_control);
1033 control_by_parameter[PanWidthAutomation] = _vpot;
1035 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1036 control_by_parameter[PanWidthAutomation] = 0;
1041 case PanElevationAutomation:
1043 case PanFrontBackAutomation:
1045 case PanLFEAutomation:
1049 _surface->write (display (1, vpot_mode_string()));
1053 Strip::reset_saved_values ()
1055 _last_pan_azi_position_written = -1.0;
1056 _last_pan_width_position_written = -1.0;
1057 _last_gain_position_written = -1.0;