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& 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& button, ButtonState bs)
461 int ms = _surface->mcp().modifier_state();
463 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
464 boost::shared_ptr<AutomationControl> ac = button.control ();
468 /* reset to default/normal value */
469 ac->set_value (ac->normal());
473 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
481 Strip::fader_touch_event (Button& button, ButtonState bs)
483 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
487 boost::shared_ptr<AutomationControl> ac = _fader->control ();
489 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
491 ac->set_value (ac->normal());
495 _fader->set_in_use (true);
496 _fader->start_touch (_surface->mcp().transport_frame());
499 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
500 queue_display_reset (2000);
506 _fader->set_in_use (false);
507 _fader->stop_touch (_surface->mcp().transport_frame(), true);
514 Strip::handle_button (Button& button, ButtonState bs)
516 boost::shared_ptr<AutomationControl> control;
519 button.set_in_use (true);
521 button.set_in_use (false);
524 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
526 switch (button.bid()) {
528 select_event (button, bs);
531 case Button::VSelect:
532 vselect_event (button, bs);
535 case Button::FaderTouch:
536 fader_touch_event (button, bs);
540 if ((control = button.control ())) {
542 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
543 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
546 int ms = _surface->mcp().modifier_state();
548 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
549 /* reset to default/normal value */
550 new_value = control->normal();
552 new_value = control->get_value() ? 0.0 : 1.0;
555 /* get all controls that either have their
556 * button down or are within a range of
557 * several down buttons
560 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
563 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
564 controls.size(), control->parameter().type(), new_value));
568 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
569 (*c)->set_value (new_value);
573 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
574 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
582 Strip::do_parameter_display (AutomationType type, float val)
587 _surface->write (display (1, " -inf "));
590 float dB = accurate_coefficient_to_dB (val);
591 snprintf (buf, sizeof (buf), "%6.1f", dB);
592 _surface->write (display (1, buf));
596 case PanAzimuthAutomation:
598 boost::shared_ptr<Pannable> p = _route->pannable();
599 if (p && p->panner()) {
600 string str = p->panner()->value_as_string (p->pan_azimuth_control);
601 _surface->write (display (1, str));
606 case PanWidthAutomation:
609 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
610 _surface->write (display (1, buf));
620 Strip::handle_fader (Fader& fader, float position)
622 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
624 fader.set_value (position);
625 fader.start_touch (_surface->mcp().transport_frame());
626 queue_display_reset (2000);
628 // must echo bytes back to slider now, because
629 // the notifier only works if the fader is not being
630 // touched. Which it is if we're getting input.
632 _surface->write (fader.set_position (position));
636 Strip::handle_pot (Pot& pot, float delta)
638 /* Pots only emit events when they move, not when they
639 stop moving. So to get a stop event, we need to use a timeout.
642 boost::shared_ptr<AutomationControl> ac = pot.control();
643 double p = pot.get_value ();
645 p = max (ac->lower(), p);
646 p = min (ac->upper(), p);
651 Strip::periodic (uint64_t usecs)
657 update_automation ();
660 if (_reset_display_at && _reset_display_at < usecs) {
666 Strip::update_automation ()
668 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
670 if (gain_state == Touch || gain_state == Play) {
671 notify_gain_changed (false);
674 if (_route->panner()) {
675 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
676 if (panner_state == Touch || panner_state == Play) {
677 notify_panner_azi_changed (false);
678 notify_panner_width_changed (false);
684 Strip::update_meter ()
687 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
688 _surface->write (_meter->update_message (dB));
695 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
696 _surface->write ((*it)->zero ());
699 _surface->write (blank_display (0));
700 _surface->write (blank_display (1));
704 Strip::blank_display (uint32_t line_number)
706 return display (line_number, string());
710 Strip::display (uint32_t line_number, const std::string& line)
712 assert (line_number <= 1);
714 MidiByteArray retval;
716 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
719 retval << _surface->sysex_hdr();
723 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
724 retval << (_index * 7 + (line_number * 0x38));
726 // ascii data to display
728 // pad with " " out to 6 chars
729 for (int i = line.length(); i < 6; ++i) {
733 // column spacer, unless it's the right-hand column
745 Strip::lock_controls ()
747 _controls_locked = true;
751 Strip::unlock_controls ()
753 _controls_locked = false;
757 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
759 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
760 if ((*i) == _route) {
761 _surface->write (_select->set_state (on));
766 _surface->write (_select->set_state (off));
770 Strip::vpot_mode_string () const
772 boost::shared_ptr<AutomationControl> ac = _vpot->control();
778 switch (ac->parameter().type()) {
781 case PanAzimuthAutomation:
783 case PanWidthAutomation:
785 case PanElevationAutomation:
787 case PanFrontBackAutomation:
789 case PanLFEAutomation:
797 Strip::flip_mode_changed (bool notify)
803 reset_saved_values ();
805 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
806 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
808 _fader->set_control (vpot_controllable);
809 _vpot->set_control (fader_controllable);
811 control_by_parameter[fader_controllable->parameter()] = _vpot;
812 control_by_parameter[vpot_controllable->parameter()] = _fader;
814 _surface->write (display (1, vpot_mode_string ()));
822 Strip::queue_display_reset (uint32_t msecs)
825 struct timeval delta;
827 gettimeofday (&now, 0);
829 delta.tv_sec = msecs/1000;
830 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
832 timeradd (&now, &delta, &when);
834 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
838 Strip::clear_display_reset ()
840 _reset_display_at = 0;
844 Strip::reset_display ()
847 _surface->write (display (1, vpot_mode_string()));
849 _surface->write (blank_display (1));
852 clear_display_reset ();
855 struct RouteCompareByName {
856 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
857 return a->name().compare (b->name()) < 0;
862 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
864 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
872 Strip::build_input_list (const ChanCount& channels)
874 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
876 input_bundles.clear ();
878 /* give user bundles first chance at being in the menu */
880 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
881 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
882 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
886 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
887 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
888 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
892 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
893 RouteList copy = *routes;
894 copy.sort (RouteCompareByName ());
896 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
897 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
903 Strip::build_output_list (const ChanCount& channels)
905 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
907 output_bundles.clear ();
909 /* give user bundles first chance at being in the menu */
911 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
912 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
913 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
917 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
918 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
919 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
923 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
924 RouteList copy = *routes;
925 copy.sort (RouteCompareByName ());
927 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
928 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
933 Strip::next_pot_mode ()
935 vector<Evoral::Parameter>::iterator i;
937 if (_surface->mcp().flip_mode()) {
938 /* do not change vpot mode while in flipped mode */
939 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
940 _surface->write (display (1, "Flip"));
941 queue_display_reset (1000);
946 boost::shared_ptr<AutomationControl> ac = _vpot->control();
952 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
956 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
957 if ((*i) == ac->parameter()) {
962 /* move to the next mode in the list, or back to the start (which will
963 also happen if the current mode is not in the current pot mode list)
966 if (i != possible_pot_parameters.end()) {
970 if (i == possible_pot_parameters.end()) {
971 i = possible_pot_parameters.begin();
974 set_vpot_parameter (*i);
978 Strip::set_vpot_parameter (Evoral::Parameter p)
980 boost::shared_ptr<Pannable> pannable;
982 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
984 reset_saved_values ();
987 case PanAzimuthAutomation:
988 pannable = _route->pannable ();
990 if (_surface->mcp().flip_mode()) {
991 /* gain to vpot, pan azi to fader */
992 _vpot->set_control (_route->gain_control());
993 control_by_parameter[GainAutomation] = _vpot;
995 _fader->set_control (pannable->pan_azimuth_control);
996 control_by_parameter[PanAzimuthAutomation] = _fader;
998 _fader->set_control (boost::shared_ptr<AutomationControl>());
999 control_by_parameter[PanAzimuthAutomation] = 0;
1002 /* gain to fader, pan azi to vpot */
1003 _fader->set_control (_route->gain_control());
1004 control_by_parameter[GainAutomation] = _fader;
1006 _vpot->set_control (pannable->pan_azimuth_control);
1007 control_by_parameter[PanAzimuthAutomation] = _vpot;
1009 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1010 control_by_parameter[PanAzimuthAutomation] = 0;
1015 case PanWidthAutomation:
1016 pannable = _route->pannable ();
1018 if (_surface->mcp().flip_mode()) {
1019 /* gain to vpot, pan width to fader */
1020 _vpot->set_control (_route->gain_control());
1021 control_by_parameter[GainAutomation] = _vpot;
1023 _fader->set_control (pannable->pan_width_control);
1024 control_by_parameter[PanWidthAutomation] = _fader;
1026 _fader->set_control (boost::shared_ptr<AutomationControl>());
1027 control_by_parameter[PanWidthAutomation] = 0;
1030 /* gain to fader, pan width to vpot */
1031 _fader->set_control (_route->gain_control());
1032 control_by_parameter[GainAutomation] = _fader;
1034 _vpot->set_control (pannable->pan_width_control);
1035 control_by_parameter[PanWidthAutomation] = _vpot;
1037 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1038 control_by_parameter[PanWidthAutomation] = 0;
1043 case PanElevationAutomation:
1045 case PanFrontBackAutomation:
1047 case PanLFEAutomation:
1051 _surface->write (display (1, vpot_mode_string()));
1055 Strip::reset_saved_values ()
1057 _last_pan_azi_position_written = -1.0;
1058 _last_pan_width_position_written = -1.0;
1059 _last_gain_position_written = -1.0;