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);
220 std::cerr << "connected to route without a panner\n";
233 notify_solo_changed ();
234 notify_mute_changed ();
235 notify_gain_changed ();
236 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
237 notify_panner_azi_changed ();
238 notify_panner_width_changed ();
239 notify_record_enable_changed ();
243 Strip::notify_solo_changed ()
245 if (_route && _solo) {
246 _surface->write (_solo->set_state (_route->soloed() ? on : off));
251 Strip::notify_mute_changed ()
253 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
254 if (_route && _mute) {
255 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
256 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
258 _surface->write (_mute->set_state (_route->muted() ? on : off));
263 Strip::notify_record_enable_changed ()
265 if (_route && _recenable) {
266 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
271 Strip::notify_active_changed ()
273 _surface->mcp().refresh_current_bank();
277 Strip::notify_route_deleted ()
279 _surface->mcp().refresh_current_bank();
283 Strip::notify_gain_changed (bool force_update)
289 if (_surface->mcp().flip_mode()) {
296 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
298 float gain_coefficient = ac->get_value();
299 float normalized_position = ac->internal_to_interface (gain_coefficient);
301 if (force_update || normalized_position != _last_gain_position_written) {
303 if (_surface->mcp().flip_mode()) {
304 if (!control->in_use()) {
305 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
307 do_parameter_display (GainAutomation, gain_coefficient);
309 if (!control->in_use()) {
310 _surface->write (_fader->set_position (normalized_position));
312 do_parameter_display (GainAutomation, gain_coefficient);
315 queue_display_reset (2000);
316 _last_gain_position_written = normalized_position;
322 Strip::notify_property_changed (const PropertyChange& what_changed)
324 if (!what_changed.contains (ARDOUR::Properties::name)) {
330 string fullname = _route->name();
332 if (fullname.length() <= 6) {
335 line1 = PBD::short_version (fullname, 6);
338 _surface->write (display (0, line1));
343 Strip::notify_panner_azi_changed (bool force_update)
347 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
349 boost::shared_ptr<Pannable> pannable = _route->pannable();
352 _surface->write (_vpot->zero());
356 Control* control = control_by_parameter[PanAzimuthAutomation];
362 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
364 if (force_update || pos != _last_pan_azi_position_written) {
366 if (control == _fader) {
367 if (!_fader->in_use()) {
368 _surface->write (_fader->set_position (pos));
370 } else if (control == _vpot) {
371 _surface->write (_vpot->set (pos, true, Pot::dot));
374 do_parameter_display (PanAzimuthAutomation, pos);
375 queue_display_reset (2000);
376 _last_pan_azi_position_written = pos;
382 Strip::notify_panner_width_changed (bool force_update)
386 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
388 boost::shared_ptr<Pannable> pannable = _route->pannable();
391 _surface->write (_vpot->zero());
396 Control* control = control_by_parameter[PanWidthAutomation];
402 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
404 if (force_update || pos != _last_pan_azi_position_written) {
406 if (_surface->mcp().flip_mode()) {
408 if (control == _fader) {
409 if (!control->in_use()) {
410 _surface->write (_fader->set_position (pos));
414 } else if (control == _vpot) {
415 _surface->write (_vpot->set (pos, true, Pot::spread));
418 do_parameter_display (PanWidthAutomation, pos);
419 queue_display_reset (2000);
420 _last_pan_azi_position_written = pos;
426 Strip::select_event (Button& button, ButtonState bs)
428 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
432 int ms = _surface->mcp().modifier_state();
434 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
435 _controls_locked = !_controls_locked;
436 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
437 queue_display_reset (1000);
441 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
442 /* reset to default */
443 boost::shared_ptr<AutomationControl> ac = _fader->control ();
445 ac->set_value (ac->normal());
450 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
451 _surface->mcp().add_down_select_button (_surface->number(), _index);
452 _surface->mcp().select_range ();
455 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
456 _surface->mcp().remove_down_select_button (_surface->number(), _index);
461 Strip::vselect_event (Button& button, ButtonState bs)
466 int ms = _surface->mcp().modifier_state();
468 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
469 boost::shared_ptr<AutomationControl> ac = button.control ();
473 /* reset to default/normal value */
474 ac->set_value (ac->normal());
478 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
486 Strip::fader_touch_event (Button& button, ButtonState bs)
488 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
492 boost::shared_ptr<AutomationControl> ac = _fader->control ();
494 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
496 ac->set_value (ac->normal());
500 _fader->set_in_use (true);
501 _fader->start_touch (_surface->mcp().transport_frame());
504 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
505 queue_display_reset (2000);
511 _fader->set_in_use (false);
512 _fader->stop_touch (_surface->mcp().transport_frame(), true);
519 Strip::handle_button (Button& button, ButtonState bs)
521 boost::shared_ptr<AutomationControl> control;
524 button.set_in_use (true);
526 button.set_in_use (false);
529 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
531 switch (button.bid()) {
533 select_event (button, bs);
536 case Button::VSelect:
537 vselect_event (button, bs);
540 case Button::FaderTouch:
541 fader_touch_event (button, bs);
545 if ((control = button.control ())) {
547 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
548 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
551 int ms = _surface->mcp().modifier_state();
553 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
554 /* reset to default/normal value */
555 new_value = control->normal();
557 new_value = control->get_value() ? 0.0 : 1.0;
560 /* get all controls that either have their
561 * button down or are within a range of
562 * several down buttons
565 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
568 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
569 controls.size(), control->parameter().type(), new_value));
573 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
574 (*c)->set_value (new_value);
578 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
579 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
587 Strip::do_parameter_display (AutomationType type, float val)
592 _surface->write (display (1, " -inf "));
595 float dB = accurate_coefficient_to_dB (val);
596 snprintf (buf, sizeof (buf), "%6.1f", dB);
597 _surface->write (display (1, buf));
601 case PanAzimuthAutomation:
603 boost::shared_ptr<Pannable> p = _route->pannable();
604 if (p && p->panner()) {
605 string str = p->panner()->value_as_string (p->pan_azimuth_control);
606 _surface->write (display (1, str));
611 case PanWidthAutomation:
614 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
615 _surface->write (display (1, buf));
625 Strip::handle_fader (Fader& fader, float position)
627 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
629 fader.set_value (position);
630 fader.start_touch (_surface->mcp().transport_frame());
631 queue_display_reset (2000);
633 // must echo bytes back to slider now, because
634 // the notifier only works if the fader is not being
635 // touched. Which it is if we're getting input.
637 _surface->write (fader.set_position (position));
641 Strip::handle_pot (Pot& pot, float delta)
643 /* Pots only emit events when they move, not when they
644 stop moving. So to get a stop event, we need to use a timeout.
647 boost::shared_ptr<AutomationControl> ac = pot.control();
648 double p = pot.get_value ();
650 p = max (ac->lower(), p);
651 p = min (ac->upper(), p);
656 Strip::periodic (uint64_t usecs)
662 update_automation ();
665 if (_reset_display_at && _reset_display_at < usecs) {
671 Strip::update_automation ()
673 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
675 if (gain_state == Touch || gain_state == Play) {
676 notify_gain_changed (false);
679 if (_route->panner()) {
680 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
681 if (panner_state == Touch || panner_state == Play) {
682 notify_panner_azi_changed (false);
683 notify_panner_width_changed (false);
689 Strip::update_meter ()
692 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
693 _surface->write (_meter->update_message (dB));
700 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
701 _surface->write ((*it)->zero ());
704 _surface->write (blank_display (0));
705 _surface->write (blank_display (1));
709 Strip::blank_display (uint32_t line_number)
711 return display (line_number, string());
715 Strip::display (uint32_t line_number, const std::string& line)
717 assert (line_number <= 1);
719 MidiByteArray retval;
721 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
724 retval << _surface->sysex_hdr();
728 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
729 retval << (_index * 7 + (line_number * 0x38));
731 // ascii data to display
733 // pad with " " out to 6 chars
734 for (int i = line.length(); i < 6; ++i) {
738 // column spacer, unless it's the right-hand column
750 Strip::lock_controls ()
752 _controls_locked = true;
756 Strip::unlock_controls ()
758 _controls_locked = false;
762 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
764 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
765 if ((*i) == _route) {
766 _surface->write (_select->set_state (on));
771 _surface->write (_select->set_state (off));
775 Strip::vpot_mode_string () const
777 boost::shared_ptr<AutomationControl> ac = _vpot->control();
783 switch (ac->parameter().type()) {
786 case PanAzimuthAutomation:
788 case PanWidthAutomation:
790 case PanElevationAutomation:
792 case PanFrontBackAutomation:
794 case PanLFEAutomation:
802 Strip::flip_mode_changed (bool notify)
808 reset_saved_values ();
810 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
811 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
813 _fader->set_control (vpot_controllable);
814 _vpot->set_control (fader_controllable);
816 control_by_parameter[fader_controllable->parameter()] = _vpot;
817 control_by_parameter[vpot_controllable->parameter()] = _fader;
819 _surface->write (display (1, vpot_mode_string ()));
827 Strip::queue_display_reset (uint32_t msecs)
830 struct timeval delta;
832 gettimeofday (&now, 0);
834 delta.tv_sec = msecs/1000;
835 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
837 timeradd (&now, &delta, &when);
839 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
843 Strip::clear_display_reset ()
845 _reset_display_at = 0;
849 Strip::reset_display ()
852 _surface->write (display (1, vpot_mode_string()));
854 _surface->write (blank_display (1));
857 clear_display_reset ();
860 struct RouteCompareByName {
861 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
862 return a->name().compare (b->name()) < 0;
867 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
869 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
877 Strip::build_input_list (const ChanCount& channels)
879 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
881 input_bundles.clear ();
883 /* give user bundles first chance at being in the menu */
885 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
886 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
887 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
891 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
892 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
893 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
897 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
898 RouteList copy = *routes;
899 copy.sort (RouteCompareByName ());
901 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
902 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
908 Strip::build_output_list (const ChanCount& channels)
910 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
912 output_bundles.clear ();
914 /* give user bundles first chance at being in the menu */
916 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
917 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
918 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
922 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
923 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
924 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
928 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
929 RouteList copy = *routes;
930 copy.sort (RouteCompareByName ());
932 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
933 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
938 Strip::next_pot_mode ()
940 vector<Evoral::Parameter>::iterator i;
942 if (_surface->mcp().flip_mode()) {
943 /* do not change vpot mode while in flipped mode */
944 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
945 _surface->write (display (1, "Flip"));
946 queue_display_reset (1000);
950 boost::shared_ptr<AutomationControl> ac = _vpot->control();
956 for (i = current_pot_modes.begin(); i != current_pot_modes.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 != current_pot_modes.end()) {
970 if (i == current_pot_modes.end()) {
971 i = current_pot_modes.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;