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 extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
65 #define invalidator() __invalidator (*(MackieControlProtocol::instance()), __FILE__, __LINE__)
67 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
79 , _controls_locked (false)
80 , _reset_display_at (0)
81 , _last_gain_position_written (-1.0)
82 , _last_pan_azi_position_written (-1.0)
83 , _last_pan_width_position_written (-1.0)
85 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
86 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
87 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
90 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
91 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
92 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
93 _surface->number(), index, Button::id_to_name (bb->bid()),
94 bb->id(), b->second.base_id));
101 /* surface is responsible for deleting all controls */
105 Strip::add (Control & control)
109 Group::add (control);
111 /* fader, vpot, meter were all set explicitly */
113 if ((button = dynamic_cast<Button*>(&control)) != 0) {
114 switch (button->bid()) {
115 case Button::RecEnable:
127 case Button::VSelect:
130 case Button::FaderTouch:
131 _fader_touch = button;
139 Strip::set_route (boost::shared_ptr<Route> r, bool with_messages)
141 if (_controls_locked) {
145 route_connections.drop_connections ();
147 _solo->set_control (boost::shared_ptr<AutomationControl>());
148 _mute->set_control (boost::shared_ptr<AutomationControl>());
149 _select->set_control (boost::shared_ptr<AutomationControl>());
150 _recenable->set_control (boost::shared_ptr<AutomationControl>());
151 _fader->set_control (boost::shared_ptr<AutomationControl>());
152 _vpot->set_control (boost::shared_ptr<AutomationControl>());
156 control_by_parameter.clear ();
157 reset_saved_values ();
163 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
164 _surface->number(), _index, _route->name()));
166 _solo->set_control (_route->solo_control());
167 _mute->set_control (_route->mute_control());
169 set_vpot_parameter (PanAzimuthAutomation);
171 _route->solo_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_solo_changed, this), ui_context());
172 _route->mute_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_mute_changed, this), ui_context());
174 boost::shared_ptr<Pannable> pannable = _route->pannable();
177 pannable->pan_azimuth_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
178 pannable->pan_width_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_width_changed, this, false), ui_context());
180 _route->gain_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
181 _route->PropertyChanged.connect (route_connections, invalidator(), ui_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, invalidator(), ui_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, invalidator(), ui_bind (&Strip::notify_active_changed, this), ui_context());
196 _route->DropReferences.connect (route_connections, invalidator(), ui_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 current_pot_modes.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 current_pot_modes.push_back (PanAzimuthAutomation);
219 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
220 current_pot_modes.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() ? 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();
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();
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& 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& button, ButtonState bs)
467 int ms = _surface->mcp().modifier_state();
469 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
470 boost::shared_ptr<AutomationControl> ac = button.control ();
474 /* reset to default/normal value */
475 ac->set_value (ac->normal());
479 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
487 Strip::fader_touch_event (Button& button, ButtonState bs)
489 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
493 boost::shared_ptr<AutomationControl> ac = _fader->control ();
495 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
497 ac->set_value (ac->normal());
501 _fader->set_in_use (true);
502 _fader->start_touch (_surface->mcp().transport_frame());
505 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
506 queue_display_reset (2000);
512 _fader->set_in_use (false);
513 _fader->stop_touch (_surface->mcp().transport_frame(), true);
520 Strip::handle_button (Button& button, ButtonState bs)
522 boost::shared_ptr<AutomationControl> control;
525 button.set_in_use (true);
527 button.set_in_use (false);
530 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
532 switch (button.bid()) {
534 select_event (button, bs);
537 case Button::VSelect:
538 vselect_event (button, bs);
541 case Button::FaderTouch:
542 fader_touch_event (button, bs);
546 if ((control = button.control ())) {
548 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
549 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
552 int ms = _surface->mcp().modifier_state();
554 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
555 /* reset to default/normal value */
556 new_value = control->normal();
558 new_value = control->get_value() ? 0.0 : 1.0;
561 /* get all controls that either have their
562 * button down or are within a range of
563 * several down buttons
566 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
569 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
570 controls.size(), control->parameter().type(), new_value));
574 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
575 (*c)->set_value (new_value);
579 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
580 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
588 Strip::do_parameter_display (AutomationType type, float val)
593 _surface->write (display (1, " -inf "));
596 float dB = accurate_coefficient_to_dB (val);
597 snprintf (buf, sizeof (buf), "%6.1f", dB);
598 _surface->write (display (1, buf));
602 case PanAzimuthAutomation:
604 boost::shared_ptr<Pannable> p = _route->pannable();
605 if (p && p->panner()) {
606 string str = p->panner()->value_as_string (p->pan_azimuth_control);
607 _surface->write (display (1, str));
612 case PanWidthAutomation:
615 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
616 _surface->write (display (1, buf));
626 Strip::handle_fader (Fader& fader, float position)
628 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
630 fader.set_value (position);
631 fader.start_touch (_surface->mcp().transport_frame());
632 queue_display_reset (2000);
634 // must echo bytes back to slider now, because
635 // the notifier only works if the fader is not being
636 // touched. Which it is if we're getting input.
638 _surface->write (fader.set_position (position));
642 Strip::handle_pot (Pot& pot, float delta)
644 /* Pots only emit events when they move, not when they
645 stop moving. So to get a stop event, we need to use a timeout.
648 boost::shared_ptr<AutomationControl> ac = pot.control();
649 double p = pot.get_value ();
651 p = max (ac->lower(), p);
652 p = min (ac->upper(), p);
657 Strip::periodic (uint64_t usecs)
663 update_automation ();
666 if (_reset_display_at && _reset_display_at < usecs) {
672 Strip::update_automation ()
674 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
676 if (gain_state == Touch || gain_state == Play) {
677 notify_gain_changed (false);
680 if (_route->panner()) {
681 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
682 if (panner_state == Touch || panner_state == Play) {
683 notify_panner_azi_changed (false);
684 notify_panner_width_changed (false);
690 Strip::update_meter ()
693 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
694 _surface->write (_meter->update_message (dB));
701 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
702 _surface->write ((*it)->zero ());
705 _surface->write (blank_display (0));
706 _surface->write (blank_display (1));
710 Strip::blank_display (uint32_t line_number)
712 return display (line_number, string());
716 Strip::display (uint32_t line_number, const std::string& line)
718 assert (line_number <= 1);
720 MidiByteArray retval;
722 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
725 retval << _surface->sysex_hdr();
729 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
730 retval << (_index * 7 + (line_number * 0x38));
732 // ascii data to display
734 // pad with " " out to 6 chars
735 for (int i = line.length(); i < 6; ++i) {
739 // column spacer, unless it's the right-hand column
751 Strip::lock_controls ()
753 _controls_locked = true;
757 Strip::unlock_controls ()
759 _controls_locked = false;
763 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
765 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
766 if ((*i) == _route) {
767 cerr << "Surface " << _surface->number() << "Strip " << _index << " found its route in the selection, turn button on\n";
768 _surface->write (_select->set_state (on));
773 cerr << "Surface " << _surface->number() << "Strip " << _index << " did NOT find its route in the selection, turn button OFF\n";
774 _surface->write (_select->set_state (off));
778 Strip::vpot_mode_string () const
780 boost::shared_ptr<AutomationControl> ac = _vpot->control();
786 switch (ac->parameter().type()) {
789 case PanAzimuthAutomation:
791 case PanWidthAutomation:
793 case PanElevationAutomation:
795 case PanFrontBackAutomation:
797 case PanLFEAutomation:
805 Strip::flip_mode_changed (bool notify)
811 reset_saved_values ();
813 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
814 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
816 _fader->set_control (vpot_controllable);
817 _vpot->set_control (fader_controllable);
819 control_by_parameter[fader_controllable->parameter()] = _vpot;
820 control_by_parameter[vpot_controllable->parameter()] = _fader;
822 _surface->write (display (1, vpot_mode_string ()));
830 Strip::queue_display_reset (uint32_t msecs)
833 struct timeval delta;
835 gettimeofday (&now, 0);
837 delta.tv_sec = msecs/1000;
838 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
840 timeradd (&now, &delta, &when);
842 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
846 Strip::clear_display_reset ()
848 _reset_display_at = 0;
852 Strip::reset_display ()
855 _surface->write (display (1, vpot_mode_string()));
857 _surface->write (blank_display (1));
860 clear_display_reset ();
863 struct RouteCompareByName {
864 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
865 return a->name().compare (b->name()) < 0;
870 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
872 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
880 Strip::build_input_list (const ChanCount& channels)
882 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
884 input_bundles.clear ();
886 /* give user bundles first chance at being in the menu */
888 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
889 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
890 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
894 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
895 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
896 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
900 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
901 RouteList copy = *routes;
902 copy.sort (RouteCompareByName ());
904 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
905 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
911 Strip::build_output_list (const ChanCount& channels)
913 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
915 output_bundles.clear ();
917 /* give user bundles first chance at being in the menu */
919 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
920 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
921 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
925 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
926 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
927 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
931 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
932 RouteList copy = *routes;
933 copy.sort (RouteCompareByName ());
935 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
936 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
941 Strip::next_pot_mode ()
943 vector<Evoral::Parameter>::iterator i;
945 if (_surface->mcp().flip_mode()) {
946 /* do not change vpot mode while in flipped mode */
947 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
948 _surface->write (display (1, "Flip"));
949 queue_display_reset (1000);
953 boost::shared_ptr<AutomationControl> ac = _vpot->control();
959 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
960 if ((*i) == ac->parameter()) {
965 /* move to the next mode in the list, or back to the start (which will
966 also happen if the current mode is not in the current pot mode list)
969 if (i != current_pot_modes.end()) {
973 if (i == current_pot_modes.end()) {
974 i = current_pot_modes.begin();
977 set_vpot_parameter (*i);
981 Strip::set_vpot_parameter (Evoral::Parameter p)
983 boost::shared_ptr<Pannable> pannable;
985 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
987 reset_saved_values ();
990 case PanAzimuthAutomation:
991 pannable = _route->pannable ();
993 if (_surface->mcp().flip_mode()) {
994 /* gain to vpot, pan azi to fader */
995 _vpot->set_control (_route->gain_control());
996 control_by_parameter[GainAutomation] = _vpot;
998 _fader->set_control (pannable->pan_azimuth_control);
999 control_by_parameter[PanAzimuthAutomation] = _fader;
1001 _fader->set_control (boost::shared_ptr<AutomationControl>());
1002 control_by_parameter[PanAzimuthAutomation] = 0;
1005 /* gain to fader, pan azi to vpot */
1006 _fader->set_control (_route->gain_control());
1007 control_by_parameter[GainAutomation] = _fader;
1009 _vpot->set_control (pannable->pan_azimuth_control);
1010 control_by_parameter[PanAzimuthAutomation] = _vpot;
1012 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1013 control_by_parameter[PanAzimuthAutomation] = 0;
1018 case PanWidthAutomation:
1019 pannable = _route->pannable ();
1021 if (_surface->mcp().flip_mode()) {
1022 /* gain to vpot, pan width to fader */
1023 _vpot->set_control (_route->gain_control());
1024 control_by_parameter[GainAutomation] = _vpot;
1026 _fader->set_control (pannable->pan_width_control);
1027 control_by_parameter[PanWidthAutomation] = _fader;
1029 _fader->set_control (boost::shared_ptr<AutomationControl>());
1030 control_by_parameter[PanWidthAutomation] = 0;
1033 /* gain to fader, pan width to vpot */
1034 _fader->set_control (_route->gain_control());
1035 control_by_parameter[GainAutomation] = _fader;
1037 _vpot->set_control (pannable->pan_width_control);
1038 control_by_parameter[PanWidthAutomation] = _vpot;
1040 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1041 control_by_parameter[PanWidthAutomation] = 0;
1046 case PanElevationAutomation:
1048 case PanFrontBackAutomation:
1050 case PanLFEAutomation:
1054 _surface->write (display (1, vpot_mode_string()));
1058 Strip::reset_saved_values ()
1060 _last_pan_azi_position_written = -1.0;
1061 _last_pan_width_position_written = -1.0;
1062 _last_gain_position_written = -1.0;