2 Copyright (C) 2006,2007 John Anderson
3 Copyright (C) 2012 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "midi++/port.h"
28 #include "pbd/compose.h"
29 #include "pbd/convert.h"
31 #include "ardour/amp.h"
32 #include "ardour/bundle.h"
33 #include "ardour/debug.h"
34 #include "ardour/midi_ui.h"
35 #include "ardour/meter.h"
36 #include "ardour/pannable.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/route.h"
41 #include "ardour/session.h"
42 #include "ardour/send.h"
43 #include "ardour/track.h"
44 #include "ardour/user_bundle.h"
46 #include "mackie_control_protocol.h"
47 #include "surface_port.h"
56 using namespace Mackie;
58 using namespace ARDOUR;
61 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
63 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
75 , _controls_locked (false)
76 , _reset_display_at (0)
77 , _last_gain_position_written (-1.0)
78 , _last_pan_azi_position_written (-1.0)
79 , _last_pan_width_position_written (-1.0)
81 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
82 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
83 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
85 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
86 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
87 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
88 _surface->number(), index, Button::id_to_name (bb->bid()),
89 bb->id(), b->second.base_id));
95 /* surface is responsible for deleting all controls */
99 Strip::add (Control & control)
103 Group::add (control);
105 /* fader, vpot, meter were all set explicitly */
107 if ((button = dynamic_cast<Button*>(&control)) != 0) {
108 switch (button->bid()) {
109 case Button::RecEnable:
121 case Button::VSelect:
124 case Button::FaderTouch:
125 _fader_touch = button;
133 Strip::set_route (boost::shared_ptr<Route> r, bool with_messages)
135 if (_controls_locked) {
139 route_connections.drop_connections ();
141 _solo->set_control (boost::shared_ptr<AutomationControl>());
142 _mute->set_control (boost::shared_ptr<AutomationControl>());
143 _select->set_control (boost::shared_ptr<AutomationControl>());
144 _recenable->set_control (boost::shared_ptr<AutomationControl>());
145 _fader->set_control (boost::shared_ptr<AutomationControl>());
146 _vpot->set_control (boost::shared_ptr<AutomationControl>());
150 control_by_parameter.clear ();
151 reset_saved_values ();
157 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
158 _surface->number(), _index, _route->name()));
160 _solo->set_control (_route->solo_control());
161 _mute->set_control (_route->mute_control());
163 set_vpot_parameter (PanAzimuthAutomation);
165 _route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
166 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
168 boost::shared_ptr<Pannable> pannable = _route->pannable();
170 if (pannable && pannable->panner()) {
171 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
172 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
174 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
175 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
177 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
180 _recenable->set_control (trk->rec_enable_control());
181 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
186 // TODO this works when a currently-banked route is made inactive, but not
187 // when a route is activated which should be currently banked.
189 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
190 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
196 /* setup legal VPot modes for this route */
198 build_input_list (_route->input()->n_ports());
199 build_output_list (_route->output()->n_ports());
201 possible_pot_parameters.clear();
204 boost::shared_ptr<Panner> panner = pannable->panner();
206 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
207 set<Evoral::Parameter>::iterator a;
209 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
210 possible_pot_parameters.push_back (PanAzimuthAutomation);
213 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
214 possible_pot_parameters.push_back (PanWidthAutomation);
217 std::cerr << "connected to route without a panner\n";
230 notify_solo_changed ();
231 notify_mute_changed ();
232 notify_gain_changed ();
233 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
234 notify_panner_azi_changed ();
235 notify_panner_width_changed ();
236 notify_record_enable_changed ();
240 Strip::notify_solo_changed ()
242 if (_route && _solo) {
243 _surface->write (_solo->set_state (_route->soloed() ? on : off));
248 Strip::notify_mute_changed ()
250 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
251 if (_route && _mute) {
252 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
253 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
255 _surface->write (_mute->set_state (_route->muted() ? on : off));
260 Strip::notify_record_enable_changed ()
262 if (_route && _recenable) {
263 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
268 Strip::notify_active_changed ()
270 _surface->mcp().refresh_current_bank();
274 Strip::notify_route_deleted ()
276 _surface->mcp().refresh_current_bank();
280 Strip::notify_gain_changed (bool force_update)
286 if (_surface->mcp().flip_mode()) {
293 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
295 float gain_coefficient = ac->get_value();
296 float normalized_position = ac->internal_to_interface (gain_coefficient);
298 if (force_update || normalized_position != _last_gain_position_written) {
300 if (_surface->mcp().flip_mode()) {
301 if (!control->in_use()) {
302 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
304 do_parameter_display (GainAutomation, gain_coefficient);
306 if (!control->in_use()) {
307 _surface->write (_fader->set_position (normalized_position));
309 do_parameter_display (GainAutomation, gain_coefficient);
312 queue_display_reset (2000);
313 _last_gain_position_written = normalized_position;
319 Strip::notify_property_changed (const PropertyChange& what_changed)
321 if (!what_changed.contains (ARDOUR::Properties::name)) {
327 string fullname = _route->name();
329 if (fullname.length() <= 6) {
332 line1 = PBD::short_version (fullname, 6);
335 _surface->write (display (0, line1));
340 Strip::notify_panner_azi_changed (bool force_update)
344 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
346 boost::shared_ptr<Pannable> pannable = _route->pannable();
348 if (!pannable || !pannable->panner()) {
349 _surface->write (_vpot->zero());
353 Control* control = control_by_parameter[PanAzimuthAutomation];
359 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
361 if (force_update || pos != _last_pan_azi_position_written) {
363 if (control == _fader) {
364 if (!_fader->in_use()) {
365 _surface->write (_fader->set_position (pos));
367 } else if (control == _vpot) {
368 _surface->write (_vpot->set (pos, true, Pot::dot));
371 do_parameter_display (PanAzimuthAutomation, pos);
372 queue_display_reset (2000);
373 _last_pan_azi_position_written = pos;
379 Strip::notify_panner_width_changed (bool force_update)
383 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
385 boost::shared_ptr<Pannable> pannable = _route->pannable();
387 if (!pannable || !pannable->panner()) {
388 _surface->write (_vpot->zero());
393 Control* control = control_by_parameter[PanWidthAutomation];
399 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
401 if (force_update || pos != _last_pan_azi_position_written) {
403 if (_surface->mcp().flip_mode()) {
405 if (control == _fader) {
406 if (!control->in_use()) {
407 _surface->write (_fader->set_position (pos));
411 } else if (control == _vpot) {
412 _surface->write (_vpot->set (pos, true, Pot::spread));
415 do_parameter_display (PanWidthAutomation, pos);
416 queue_display_reset (2000);
417 _last_pan_azi_position_written = pos;
423 Strip::select_event (Button& button, ButtonState bs)
425 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
429 int ms = _surface->mcp().modifier_state();
431 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
432 _controls_locked = !_controls_locked;
433 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
434 queue_display_reset (1000);
438 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
439 /* reset to default */
440 boost::shared_ptr<AutomationControl> ac = _fader->control ();
442 ac->set_value (ac->normal());
447 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
448 _surface->mcp().add_down_select_button (_surface->number(), _index);
449 _surface->mcp().select_range ();
452 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
453 _surface->mcp().remove_down_select_button (_surface->number(), _index);
458 Strip::vselect_event (Button& button, ButtonState bs)
462 int ms = _surface->mcp().modifier_state();
464 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
465 boost::shared_ptr<AutomationControl> ac = button.control ();
469 /* reset to default/normal value */
470 ac->set_value (ac->normal());
474 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
482 Strip::fader_touch_event (Button& button, ButtonState bs)
484 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
488 boost::shared_ptr<AutomationControl> ac = _fader->control ();
490 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
492 ac->set_value (ac->normal());
496 _fader->set_in_use (true);
497 _fader->start_touch (_surface->mcp().transport_frame());
500 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
501 queue_display_reset (2000);
507 _fader->set_in_use (false);
508 _fader->stop_touch (_surface->mcp().transport_frame(), true);
515 Strip::handle_button (Button& button, ButtonState bs)
517 boost::shared_ptr<AutomationControl> control;
520 button.set_in_use (true);
522 button.set_in_use (false);
525 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
527 switch (button.bid()) {
529 select_event (button, bs);
532 case Button::VSelect:
533 vselect_event (button, bs);
536 case Button::FaderTouch:
537 fader_touch_event (button, bs);
541 if ((control = button.control ())) {
543 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
544 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
547 int ms = _surface->mcp().modifier_state();
549 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
550 /* reset to default/normal value */
551 new_value = control->normal();
553 new_value = control->get_value() ? 0.0 : 1.0;
556 /* get all controls that either have their
557 * button down or are within a range of
558 * several down buttons
561 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
564 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
565 controls.size(), control->parameter().type(), new_value));
569 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
570 (*c)->set_value (new_value);
574 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
575 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
583 Strip::do_parameter_display (AutomationType type, float val)
588 _surface->write (display (1, " -inf "));
591 float dB = accurate_coefficient_to_dB (val);
592 snprintf (buf, sizeof (buf), "%6.1f", dB);
593 _surface->write (display (1, buf));
597 case PanAzimuthAutomation:
599 boost::shared_ptr<Pannable> p = _route->pannable();
600 if (p && p->panner()) {
601 string str = p->panner()->value_as_string (p->pan_azimuth_control);
602 _surface->write (display (1, str));
607 case PanWidthAutomation:
610 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
611 _surface->write (display (1, buf));
621 Strip::handle_fader (Fader& fader, float position)
623 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
625 fader.set_value (position);
626 fader.start_touch (_surface->mcp().transport_frame());
627 queue_display_reset (2000);
629 // must echo bytes back to slider now, because
630 // the notifier only works if the fader is not being
631 // touched. Which it is if we're getting input.
633 _surface->write (fader.set_position (position));
637 Strip::handle_pot (Pot& pot, float delta)
639 /* Pots only emit events when they move, not when they
640 stop moving. So to get a stop event, we need to use a timeout.
643 boost::shared_ptr<AutomationControl> ac = pot.control();
644 double p = pot.get_value ();
646 p = max (ac->lower(), p);
647 p = min (ac->upper(), p);
652 Strip::periodic (uint64_t usecs)
658 update_automation ();
661 if (_reset_display_at && _reset_display_at < usecs) {
667 Strip::update_automation ()
669 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
671 if (gain_state == Touch || gain_state == Play) {
672 notify_gain_changed (false);
675 if (_route->panner()) {
676 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
677 if (panner_state == Touch || panner_state == Play) {
678 notify_panner_azi_changed (false);
679 notify_panner_width_changed (false);
685 Strip::update_meter ()
688 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
689 _surface->write (_meter->update_message (dB));
696 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
697 _surface->write ((*it)->zero ());
700 _surface->write (blank_display (0));
701 _surface->write (blank_display (1));
705 Strip::blank_display (uint32_t line_number)
707 return display (line_number, string());
711 Strip::display (uint32_t line_number, const std::string& line)
713 assert (line_number <= 1);
715 MidiByteArray retval;
717 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
720 retval << _surface->sysex_hdr();
724 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
725 retval << (_index * 7 + (line_number * 0x38));
727 // ascii data to display
729 // pad with " " out to 6 chars
730 for (int i = line.length(); i < 6; ++i) {
734 // column spacer, unless it's the right-hand column
746 Strip::lock_controls ()
748 _controls_locked = true;
752 Strip::unlock_controls ()
754 _controls_locked = false;
758 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
760 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
761 if ((*i) == _route) {
762 _surface->write (_select->set_state (on));
767 _surface->write (_select->set_state (off));
771 Strip::vpot_mode_string () const
773 boost::shared_ptr<AutomationControl> ac = _vpot->control();
779 switch (ac->parameter().type()) {
782 case PanAzimuthAutomation:
784 case PanWidthAutomation:
786 case PanElevationAutomation:
788 case PanFrontBackAutomation:
790 case PanLFEAutomation:
798 Strip::flip_mode_changed (bool notify)
804 reset_saved_values ();
806 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
807 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
809 _fader->set_control (vpot_controllable);
810 _vpot->set_control (fader_controllable);
812 control_by_parameter[fader_controllable->parameter()] = _vpot;
813 control_by_parameter[vpot_controllable->parameter()] = _fader;
815 _surface->write (display (1, vpot_mode_string ()));
823 Strip::queue_display_reset (uint32_t msecs)
826 struct timeval delta;
828 gettimeofday (&now, 0);
830 delta.tv_sec = msecs/1000;
831 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
833 timeradd (&now, &delta, &when);
835 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
839 Strip::clear_display_reset ()
841 _reset_display_at = 0;
845 Strip::reset_display ()
848 _surface->write (display (1, vpot_mode_string()));
850 _surface->write (blank_display (1));
853 clear_display_reset ();
856 struct RouteCompareByName {
857 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
858 return a->name().compare (b->name()) < 0;
863 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
865 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
873 Strip::build_input_list (const ChanCount& channels)
875 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
877 input_bundles.clear ();
879 /* give user bundles first chance at being in the menu */
881 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
882 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
883 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
887 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
888 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
889 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
893 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
894 RouteList copy = *routes;
895 copy.sort (RouteCompareByName ());
897 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
898 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
904 Strip::build_output_list (const ChanCount& channels)
906 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
908 output_bundles.clear ();
910 /* give user bundles first chance at being in the menu */
912 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
913 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
914 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
918 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
919 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
920 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
924 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
925 RouteList copy = *routes;
926 copy.sort (RouteCompareByName ());
928 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
929 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
934 Strip::next_pot_mode ()
936 vector<Evoral::Parameter>::iterator i;
938 if (_surface->mcp().flip_mode()) {
939 /* do not change vpot mode while in flipped mode */
940 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
941 _surface->write (display (1, "Flip"));
942 queue_display_reset (1000);
947 boost::shared_ptr<AutomationControl> ac = _vpot->control();
953 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
957 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
958 if ((*i) == ac->parameter()) {
963 /* move to the next mode in the list, or back to the start (which will
964 also happen if the current mode is not in the current pot mode list)
967 if (i != possible_pot_parameters.end()) {
971 if (i == possible_pot_parameters.end()) {
972 i = possible_pot_parameters.begin();
975 set_vpot_parameter (*i);
979 Strip::set_vpot_parameter (Evoral::Parameter p)
981 boost::shared_ptr<Pannable> pannable;
983 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
985 reset_saved_values ();
988 case PanAzimuthAutomation:
989 pannable = _route->pannable ();
991 if (_surface->mcp().flip_mode()) {
992 /* gain to vpot, pan azi to fader */
993 _vpot->set_control (_route->gain_control());
994 control_by_parameter[GainAutomation] = _vpot;
996 _fader->set_control (pannable->pan_azimuth_control);
997 control_by_parameter[PanAzimuthAutomation] = _fader;
999 _fader->set_control (boost::shared_ptr<AutomationControl>());
1000 control_by_parameter[PanAzimuthAutomation] = 0;
1003 /* gain to fader, pan azi to vpot */
1004 _fader->set_control (_route->gain_control());
1005 control_by_parameter[GainAutomation] = _fader;
1007 _vpot->set_control (pannable->pan_azimuth_control);
1008 control_by_parameter[PanAzimuthAutomation] = _vpot;
1010 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1011 control_by_parameter[PanAzimuthAutomation] = 0;
1016 case PanWidthAutomation:
1017 pannable = _route->pannable ();
1019 if (_surface->mcp().flip_mode()) {
1020 /* gain to vpot, pan width to fader */
1021 _vpot->set_control (_route->gain_control());
1022 control_by_parameter[GainAutomation] = _vpot;
1024 _fader->set_control (pannable->pan_width_control);
1025 control_by_parameter[PanWidthAutomation] = _fader;
1027 _fader->set_control (boost::shared_ptr<AutomationControl>());
1028 control_by_parameter[PanWidthAutomation] = 0;
1031 /* gain to fader, pan width to vpot */
1032 _fader->set_control (_route->gain_control());
1033 control_by_parameter[GainAutomation] = _fader;
1035 _vpot->set_control (pannable->pan_width_control);
1036 control_by_parameter[PanWidthAutomation] = _vpot;
1038 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1039 control_by_parameter[PanWidthAutomation] = 0;
1044 case PanElevationAutomation:
1046 case PanFrontBackAutomation:
1048 case PanLFEAutomation:
1052 _surface->write (display (1, vpot_mode_string()));
1056 Strip::reset_saved_values ()
1058 _last_pan_azi_position_written = -1.0;
1059 _last_pan_width_position_written = -1.0;
1060 _last_gain_position_written = -1.0;