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));
84 if (s.mcp().device_info().has_meters()) {
85 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
88 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
89 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
90 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
91 _surface->number(), index, Button::id_to_name (bb->bid()),
92 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 ();
161 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
162 _surface->number(), _index, _route->name()));
164 _solo->set_control (_route->solo_control());
165 _mute->set_control (_route->mute_control());
167 set_vpot_parameter (PanAzimuthAutomation);
169 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
170 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
172 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
174 boost::shared_ptr<Pannable> pannable = _route->pannable();
176 if (pannable && pannable->panner()) {
177 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
178 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
180 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
181 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
183 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
186 _recenable->set_control (trk->rec_enable_control());
187 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
192 // TODO this works when a currently-banked route is made inactive, but not
193 // when a route is activated which should be currently banked.
195 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
196 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
202 /* setup legal VPot modes for this route */
204 build_input_list (_route->input()->n_ports());
205 build_output_list (_route->output()->n_ports());
207 possible_pot_parameters.clear();
210 boost::shared_ptr<Panner> panner = pannable->panner();
212 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
213 set<Evoral::Parameter>::iterator a;
215 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
216 possible_pot_parameters.push_back (PanAzimuthAutomation);
219 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
220 possible_pot_parameters.push_back (PanWidthAutomation);
234 notify_solo_changed ();
235 notify_mute_changed ();
236 notify_gain_changed ();
237 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
238 notify_panner_azi_changed ();
239 notify_panner_width_changed ();
240 notify_record_enable_changed ();
244 Strip::notify_solo_changed ()
246 if (_route && _solo) {
247 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
252 Strip::notify_mute_changed ()
254 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
255 if (_route && _mute) {
256 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
257 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
259 _surface->write (_mute->set_state (_route->muted() ? on : off));
264 Strip::notify_record_enable_changed ()
266 if (_route && _recenable) {
267 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
272 Strip::notify_active_changed ()
274 _surface->mcp().refresh_current_bank();
278 Strip::notify_route_deleted ()
280 _surface->mcp().refresh_current_bank();
284 Strip::notify_gain_changed (bool force_update)
290 if (_surface->mcp().flip_mode()) {
297 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
299 float gain_coefficient = ac->get_value();
300 float normalized_position = ac->internal_to_interface (gain_coefficient);
302 if (force_update || normalized_position != _last_gain_position_written) {
304 if (_surface->mcp().flip_mode()) {
305 if (!control->in_use()) {
306 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
308 do_parameter_display (GainAutomation, gain_coefficient);
310 if (!control->in_use()) {
311 _surface->write (_fader->set_position (normalized_position));
313 do_parameter_display (GainAutomation, gain_coefficient);
316 queue_display_reset (2000);
317 _last_gain_position_written = normalized_position;
323 Strip::notify_property_changed (const PropertyChange& what_changed)
325 if (!what_changed.contains (ARDOUR::Properties::name)) {
331 string fullname = _route->name();
333 if (fullname.length() <= 6) {
336 line1 = PBD::short_version (fullname, 6);
339 _surface->write (display (0, line1));
344 Strip::notify_panner_azi_changed (bool force_update)
348 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
350 boost::shared_ptr<Pannable> pannable = _route->pannable();
352 if (!pannable || !pannable->panner()) {
353 _surface->write (_vpot->zero());
357 Control* control = control_by_parameter[PanAzimuthAutomation];
363 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
365 if (force_update || pos != _last_pan_azi_position_written) {
367 if (control == _fader) {
368 if (!_fader->in_use()) {
369 _surface->write (_fader->set_position (pos));
371 } else if (control == _vpot) {
372 _surface->write (_vpot->set (pos, true, Pot::dot));
375 do_parameter_display (PanAzimuthAutomation, pos);
376 queue_display_reset (2000);
377 _last_pan_azi_position_written = pos;
383 Strip::notify_panner_width_changed (bool force_update)
387 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
389 boost::shared_ptr<Pannable> pannable = _route->pannable();
391 if (!pannable || !pannable->panner()) {
392 _surface->write (_vpot->zero());
397 Control* control = control_by_parameter[PanWidthAutomation];
403 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
405 if (force_update || pos != _last_pan_azi_position_written) {
407 if (_surface->mcp().flip_mode()) {
409 if (control == _fader) {
410 if (!control->in_use()) {
411 _surface->write (_fader->set_position (pos));
415 } else if (control == _vpot) {
416 _surface->write (_vpot->set (pos, true, Pot::spread));
419 do_parameter_display (PanWidthAutomation, pos);
420 queue_display_reset (2000);
421 _last_pan_azi_position_written = pos;
427 Strip::select_event (Button&, ButtonState bs)
429 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
433 int ms = _surface->mcp().modifier_state();
435 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
436 _controls_locked = !_controls_locked;
437 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
438 queue_display_reset (1000);
442 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
443 /* reset to default */
444 boost::shared_ptr<AutomationControl> ac = _fader->control ();
446 ac->set_value (ac->normal());
451 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
452 _surface->mcp().add_down_select_button (_surface->number(), _index);
453 _surface->mcp().select_range ();
456 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
457 _surface->mcp().remove_down_select_button (_surface->number(), _index);
462 Strip::vselect_event (Button&, ButtonState bs)
466 int ms = _surface->mcp().modifier_state();
468 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
470 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
474 /* reset to default/normal value */
475 ac->set_value (ac->normal());
480 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
488 Strip::fader_touch_event (Button&, ButtonState bs)
490 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
494 boost::shared_ptr<AutomationControl> ac = _fader->control ();
496 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
498 ac->set_value (ac->normal());
502 _fader->set_in_use (true);
503 _fader->start_touch (_surface->mcp().transport_frame());
506 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
507 queue_display_reset (2000);
513 _fader->set_in_use (false);
514 _fader->stop_touch (_surface->mcp().transport_frame(), true);
521 Strip::handle_button (Button& button, ButtonState bs)
523 boost::shared_ptr<AutomationControl> control;
526 button.set_in_use (true);
528 button.set_in_use (false);
531 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
533 switch (button.bid()) {
535 select_event (button, bs);
538 case Button::VSelect:
539 vselect_event (button, bs);
542 case Button::FaderTouch:
543 fader_touch_event (button, bs);
547 if ((control = button.control ())) {
549 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
550 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
553 int ms = _surface->mcp().modifier_state();
555 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
556 /* reset to default/normal value */
557 new_value = control->normal();
559 new_value = control->get_value() ? 0.0 : 1.0;
562 /* get all controls that either have their
563 * button down or are within a range of
564 * several down buttons
567 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
570 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
571 controls.size(), control->parameter().type(), new_value));
575 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
576 (*c)->set_value (new_value);
580 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
581 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
589 Strip::do_parameter_display (AutomationType type, float val)
594 _surface->write (display (1, " -inf "));
597 float dB = accurate_coefficient_to_dB (val);
598 snprintf (buf, sizeof (buf), "%6.1f", dB);
599 _surface->write (display (1, buf));
603 case PanAzimuthAutomation:
605 boost::shared_ptr<Pannable> p = _route->pannable();
606 if (p && p->panner()) {
607 string str = p->panner()->value_as_string (p->pan_azimuth_control);
608 _surface->write (display (1, str));
613 case PanWidthAutomation:
616 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
617 _surface->write (display (1, buf));
627 Strip::handle_fader (Fader& fader, float position)
629 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
631 fader.set_value (position);
632 fader.start_touch (_surface->mcp().transport_frame());
633 queue_display_reset (2000);
635 // must echo bytes back to slider now, because
636 // the notifier only works if the fader is not being
637 // touched. Which it is if we're getting input.
639 _surface->write (fader.set_position (position));
643 Strip::handle_pot (Pot& pot, float delta)
645 /* Pots only emit events when they move, not when they
646 stop moving. So to get a stop event, we need to use a timeout.
649 boost::shared_ptr<AutomationControl> ac = pot.control();
650 double p = pot.get_value ();
652 p = max (ac->lower(), p);
653 p = min (ac->upper(), p);
658 Strip::periodic (uint64_t usecs)
664 update_automation ();
667 if (_reset_display_at && _reset_display_at < usecs) {
673 Strip::update_automation ()
675 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
677 if (gain_state == Touch || gain_state == Play) {
678 notify_gain_changed (false);
681 if (_route->panner()) {
682 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
683 if (panner_state == Touch || panner_state == Play) {
684 notify_panner_azi_changed (false);
685 notify_panner_width_changed (false);
691 Strip::update_meter ()
694 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
695 _meter->send_update (*_surface, dB);
702 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
703 _surface->write ((*it)->zero ());
706 _surface->write (blank_display (0));
707 _surface->write (blank_display (1));
711 Strip::blank_display (uint32_t line_number)
713 return display (line_number, string());
717 Strip::display (uint32_t line_number, const std::string& line)
719 assert (line_number <= 1);
721 MidiByteArray retval;
723 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
726 retval << _surface->sysex_hdr();
730 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
731 retval << (_index * 7 + (line_number * 0x38));
733 // ascii data to display
735 // pad with " " out to 6 chars
736 for (int i = line.length(); i < 6; ++i) {
740 // column spacer, unless it's the right-hand column
752 Strip::lock_controls ()
754 _controls_locked = true;
758 Strip::unlock_controls ()
760 _controls_locked = false;
764 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
766 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
767 if ((*i) == _route) {
768 _surface->write (_select->set_state (on));
773 _surface->write (_select->set_state (off));
777 Strip::vpot_mode_string () const
779 boost::shared_ptr<AutomationControl> ac = _vpot->control();
785 switch (ac->parameter().type()) {
788 case PanAzimuthAutomation:
790 case PanWidthAutomation:
792 case PanElevationAutomation:
794 case PanFrontBackAutomation:
796 case PanLFEAutomation:
804 Strip::flip_mode_changed (bool notify)
810 reset_saved_values ();
812 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
813 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
815 _fader->set_control (vpot_controllable);
816 _vpot->set_control (fader_controllable);
818 control_by_parameter[fader_controllable->parameter()] = _vpot;
819 control_by_parameter[vpot_controllable->parameter()] = _fader;
821 _surface->write (display (1, vpot_mode_string ()));
829 Strip::queue_display_reset (uint32_t msecs)
832 struct timeval delta;
834 gettimeofday (&now, 0);
836 delta.tv_sec = msecs/1000;
837 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
839 timeradd (&now, &delta, &when);
841 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
845 Strip::clear_display_reset ()
847 _reset_display_at = 0;
851 Strip::reset_display ()
854 _surface->write (display (1, vpot_mode_string()));
856 _surface->write (blank_display (1));
859 clear_display_reset ();
862 struct RouteCompareByName {
863 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
864 return a->name().compare (b->name()) < 0;
869 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
871 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
879 Strip::build_input_list (const ChanCount& channels)
881 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
883 input_bundles.clear ();
885 /* give user bundles first chance at being in the menu */
887 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
888 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
889 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
893 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
894 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
895 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
899 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
900 RouteList copy = *routes;
901 copy.sort (RouteCompareByName ());
903 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
904 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
910 Strip::build_output_list (const ChanCount& channels)
912 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
914 output_bundles.clear ();
916 /* give user bundles first chance at being in the menu */
918 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
919 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
920 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
924 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
925 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
926 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
930 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
931 RouteList copy = *routes;
932 copy.sort (RouteCompareByName ());
934 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
935 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
940 Strip::next_pot_mode ()
942 vector<Evoral::Parameter>::iterator i;
944 if (_surface->mcp().flip_mode()) {
945 /* do not change vpot mode while in flipped mode */
946 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
947 _surface->write (display (1, "Flip"));
948 queue_display_reset (1000);
953 boost::shared_ptr<AutomationControl> ac = _vpot->control();
959 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
963 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
964 if ((*i) == ac->parameter()) {
969 /* move to the next mode in the list, or back to the start (which will
970 also happen if the current mode is not in the current pot mode list)
973 if (i != possible_pot_parameters.end()) {
977 if (i == possible_pot_parameters.end()) {
978 i = possible_pot_parameters.begin();
981 set_vpot_parameter (*i);
985 Strip::set_vpot_parameter (Evoral::Parameter p)
987 boost::shared_ptr<Pannable> pannable;
989 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
991 reset_saved_values ();
994 case PanAzimuthAutomation:
995 pannable = _route->pannable ();
997 if (_surface->mcp().flip_mode()) {
998 /* gain to vpot, pan azi to fader */
999 _vpot->set_control (_route->gain_control());
1000 control_by_parameter[GainAutomation] = _vpot;
1002 _fader->set_control (pannable->pan_azimuth_control);
1003 control_by_parameter[PanAzimuthAutomation] = _fader;
1005 _fader->set_control (boost::shared_ptr<AutomationControl>());
1006 control_by_parameter[PanAzimuthAutomation] = 0;
1009 /* gain to fader, pan azi to vpot */
1010 _fader->set_control (_route->gain_control());
1011 control_by_parameter[GainAutomation] = _fader;
1013 _vpot->set_control (pannable->pan_azimuth_control);
1014 control_by_parameter[PanAzimuthAutomation] = _vpot;
1016 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1017 control_by_parameter[PanAzimuthAutomation] = 0;
1022 case PanWidthAutomation:
1023 pannable = _route->pannable ();
1025 if (_surface->mcp().flip_mode()) {
1026 /* gain to vpot, pan width to fader */
1027 _vpot->set_control (_route->gain_control());
1028 control_by_parameter[GainAutomation] = _vpot;
1030 _fader->set_control (pannable->pan_width_control);
1031 control_by_parameter[PanWidthAutomation] = _fader;
1033 _fader->set_control (boost::shared_ptr<AutomationControl>());
1034 control_by_parameter[PanWidthAutomation] = 0;
1037 /* gain to fader, pan width to vpot */
1038 _fader->set_control (_route->gain_control());
1039 control_by_parameter[GainAutomation] = _fader;
1041 _vpot->set_control (pannable->pan_width_control);
1042 control_by_parameter[PanWidthAutomation] = _vpot;
1044 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1045 control_by_parameter[PanWidthAutomation] = 0;
1050 case PanElevationAutomation:
1052 case PanFrontBackAutomation:
1054 case PanLFEAutomation:
1058 _surface->write (display (1, vpot_mode_string()));
1062 Strip::reset_saved_values ()
1064 _last_pan_azi_position_written = -1.0;
1065 _last_pan_width_position_written = -1.0;
1066 _last_gain_position_written = -1.0;