2 Copyright (C) 2006,2007 John Anderson
3 Copyright (C) 2012 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "midi++/port.h"
28 #include "pbd/compose.h"
29 #include "pbd/convert.h"
31 #include "ardour/amp.h"
32 #include "ardour/bundle.h"
33 #include "ardour/debug.h"
34 #include "ardour/midi_ui.h"
35 #include "ardour/meter.h"
36 #include "ardour/pannable.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/route.h"
41 #include "ardour/session.h"
42 #include "ardour/send.h"
43 #include "ardour/track.h"
44 #include "ardour/user_bundle.h"
46 #include "mackie_control_protocol.h"
47 #include "surface_port.h"
56 using namespace Mackie;
58 using namespace ARDOUR;
61 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
63 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
75 , _controls_locked (false)
76 , _reset_display_at (0)
77 , _last_gain_position_written (-1.0)
78 , _last_pan_azi_position_written (-1.0)
79 , _last_pan_width_position_written (-1.0)
81 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
82 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
83 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
85 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
86 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
87 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
88 _surface->number(), index, Button::id_to_name (bb->bid()),
89 bb->id(), b->second.base_id));
95 /* surface is responsible for deleting all controls */
99 Strip::add (Control & control)
103 Group::add (control);
105 /* fader, vpot, meter were all set explicitly */
107 if ((button = dynamic_cast<Button*>(&control)) != 0) {
108 switch (button->bid()) {
109 case Button::RecEnable:
121 case Button::VSelect:
124 case Button::FaderTouch:
125 _fader_touch = button;
133 Strip::set_route (boost::shared_ptr<Route> r, bool with_messages)
135 if (_controls_locked) {
139 route_connections.drop_connections ();
141 _solo->set_control (boost::shared_ptr<AutomationControl>());
142 _mute->set_control (boost::shared_ptr<AutomationControl>());
143 _select->set_control (boost::shared_ptr<AutomationControl>());
144 _recenable->set_control (boost::shared_ptr<AutomationControl>());
145 _fader->set_control (boost::shared_ptr<AutomationControl>());
146 _vpot->set_control (boost::shared_ptr<AutomationControl>());
150 control_by_parameter.clear ();
151 reset_saved_values ();
158 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
159 _surface->number(), _index, _route->name()));
161 _solo->set_control (_route->solo_control());
162 _mute->set_control (_route->mute_control());
164 set_vpot_parameter (PanAzimuthAutomation);
166 _route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
167 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
169 boost::shared_ptr<Pannable> pannable = _route->pannable();
171 if (pannable && pannable->panner()) {
172 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
173 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
175 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
176 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
178 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
181 _recenable->set_control (trk->rec_enable_control());
182 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
187 // TODO this works when a currently-banked route is made inactive, but not
188 // when a route is activated which should be currently banked.
190 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
191 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
197 /* setup legal VPot modes for this route */
199 build_input_list (_route->input()->n_ports());
200 build_output_list (_route->output()->n_ports());
202 possible_pot_parameters.clear();
205 boost::shared_ptr<Panner> panner = pannable->panner();
207 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
208 set<Evoral::Parameter>::iterator a;
210 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
211 possible_pot_parameters.push_back (PanAzimuthAutomation);
214 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
215 possible_pot_parameters.push_back (PanWidthAutomation);
229 notify_solo_changed ();
230 notify_mute_changed ();
231 notify_gain_changed ();
232 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
233 notify_panner_azi_changed ();
234 notify_panner_width_changed ();
235 notify_record_enable_changed ();
239 Strip::notify_solo_changed ()
241 if (_route && _solo) {
242 _surface->write (_solo->set_state (_route->soloed() ? on : off));
247 Strip::notify_mute_changed ()
249 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
250 if (_route && _mute) {
251 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
252 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
254 _surface->write (_mute->set_state (_route->muted() ? on : off));
259 Strip::notify_record_enable_changed ()
261 if (_route && _recenable) {
262 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
267 Strip::notify_active_changed ()
269 _surface->mcp().refresh_current_bank();
273 Strip::notify_route_deleted ()
275 _surface->mcp().refresh_current_bank();
279 Strip::notify_gain_changed (bool force_update)
285 if (_surface->mcp().flip_mode()) {
292 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
294 float gain_coefficient = ac->get_value();
295 float normalized_position = ac->internal_to_interface (gain_coefficient);
297 if (force_update || normalized_position != _last_gain_position_written) {
299 if (_surface->mcp().flip_mode()) {
300 if (!control->in_use()) {
301 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
303 do_parameter_display (GainAutomation, gain_coefficient);
305 if (!control->in_use()) {
306 _surface->write (_fader->set_position (normalized_position));
308 do_parameter_display (GainAutomation, gain_coefficient);
311 queue_display_reset (2000);
312 _last_gain_position_written = normalized_position;
318 Strip::notify_property_changed (const PropertyChange& what_changed)
320 if (!what_changed.contains (ARDOUR::Properties::name)) {
326 string fullname = _route->name();
328 if (fullname.length() <= 6) {
331 line1 = PBD::short_version (fullname, 6);
334 _surface->write (display (0, line1));
339 Strip::notify_panner_azi_changed (bool force_update)
343 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
345 boost::shared_ptr<Pannable> pannable = _route->pannable();
347 if (!pannable || !pannable->panner()) {
348 _surface->write (_vpot->zero());
352 Control* control = control_by_parameter[PanAzimuthAutomation];
358 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
360 if (force_update || pos != _last_pan_azi_position_written) {
362 if (control == _fader) {
363 if (!_fader->in_use()) {
364 _surface->write (_fader->set_position (pos));
366 } else if (control == _vpot) {
367 _surface->write (_vpot->set (pos, true, Pot::dot));
370 do_parameter_display (PanAzimuthAutomation, pos);
371 queue_display_reset (2000);
372 _last_pan_azi_position_written = pos;
378 Strip::notify_panner_width_changed (bool force_update)
382 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
384 boost::shared_ptr<Pannable> pannable = _route->pannable();
386 if (!pannable || !pannable->panner()) {
387 _surface->write (_vpot->zero());
392 Control* control = control_by_parameter[PanWidthAutomation];
398 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
400 if (force_update || pos != _last_pan_azi_position_written) {
402 if (_surface->mcp().flip_mode()) {
404 if (control == _fader) {
405 if (!control->in_use()) {
406 _surface->write (_fader->set_position (pos));
410 } else if (control == _vpot) {
411 _surface->write (_vpot->set (pos, true, Pot::spread));
414 do_parameter_display (PanWidthAutomation, pos);
415 queue_display_reset (2000);
416 _last_pan_azi_position_written = pos;
422 Strip::select_event (Button& button, ButtonState bs)
424 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
428 int ms = _surface->mcp().modifier_state();
430 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
431 _controls_locked = !_controls_locked;
432 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
433 queue_display_reset (1000);
437 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
438 /* reset to default */
439 boost::shared_ptr<AutomationControl> ac = _fader->control ();
441 ac->set_value (ac->normal());
446 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
447 _surface->mcp().add_down_select_button (_surface->number(), _index);
448 _surface->mcp().select_range ();
451 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
452 _surface->mcp().remove_down_select_button (_surface->number(), _index);
457 Strip::vselect_event (Button& button, ButtonState bs)
461 int ms = _surface->mcp().modifier_state();
463 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
465 /* get the corresponding vpot and whatever its
469 Pot* pot = _surface->pots[Pot::ID + _index];
472 boost::shared_ptr<AutomationControl> ac = pot->control ();
476 /* reset to default/normal value */
477 ac->set_value (ac->normal());
483 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
491 Strip::fader_touch_event (Button& button, ButtonState bs)
493 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
497 boost::shared_ptr<AutomationControl> ac = _fader->control ();
499 if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) {
501 ac->set_value (ac->normal());
505 _fader->set_in_use (true);
506 _fader->start_touch (_surface->mcp().transport_frame());
509 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
510 queue_display_reset (2000);
516 _fader->set_in_use (false);
517 _fader->stop_touch (_surface->mcp().transport_frame(), true);
524 Strip::handle_button (Button& button, ButtonState bs)
526 boost::shared_ptr<AutomationControl> control;
529 button.set_in_use (true);
531 button.set_in_use (false);
534 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
536 switch (button.bid()) {
538 select_event (button, bs);
541 case Button::VSelect:
542 vselect_event (button, bs);
545 case Button::FaderTouch:
546 fader_touch_event (button, bs);
550 if ((control = button.control ())) {
552 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
553 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
556 int ms = _surface->mcp().modifier_state();
558 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
559 /* reset to default/normal value */
560 new_value = control->normal();
562 new_value = control->get_value() ? 0.0 : 1.0;
565 /* get all controls that either have their
566 * button down or are within a range of
567 * several down buttons
570 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
573 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
574 controls.size(), control->parameter().type(), new_value));
578 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
579 (*c)->set_value (new_value);
583 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
584 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
592 Strip::do_parameter_display (AutomationType type, float val)
597 _surface->write (display (1, " -inf "));
600 float dB = accurate_coefficient_to_dB (val);
601 snprintf (buf, sizeof (buf), "%6.1f", dB);
602 _surface->write (display (1, buf));
606 case PanAzimuthAutomation:
608 boost::shared_ptr<Pannable> p = _route->pannable();
609 if (p && p->panner()) {
610 string str = p->panner()->value_as_string (p->pan_azimuth_control);
611 _surface->write (display (1, str));
616 case PanWidthAutomation:
619 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
620 _surface->write (display (1, buf));
630 Strip::handle_fader (Fader& fader, float position)
632 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
634 fader.set_value (position);
635 fader.start_touch (_surface->mcp().transport_frame());
636 queue_display_reset (2000);
638 // must echo bytes back to slider now, because
639 // the notifier only works if the fader is not being
640 // touched. Which it is if we're getting input.
642 _surface->write (fader.set_position (position));
646 Strip::handle_pot (Pot& pot, float delta)
648 /* Pots only emit events when they move, not when they
649 stop moving. So to get a stop event, we need to use a timeout.
652 boost::shared_ptr<AutomationControl> ac = pot.control();
653 double p = pot.get_value ();
655 p = max (ac->lower(), p);
656 p = min (ac->upper(), p);
661 Strip::periodic (uint64_t usecs)
667 update_automation ();
670 if (_reset_display_at && _reset_display_at < usecs) {
676 Strip::update_automation ()
678 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
680 if (gain_state == Touch || gain_state == Play) {
681 notify_gain_changed (false);
684 if (_route->panner()) {
685 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
686 if (panner_state == Touch || panner_state == Play) {
687 notify_panner_azi_changed (false);
688 notify_panner_width_changed (false);
694 Strip::update_meter ()
697 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
698 _surface->write (_meter->update_message (dB));
705 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
706 _surface->write ((*it)->zero ());
709 _surface->write (blank_display (0));
710 _surface->write (blank_display (1));
714 Strip::blank_display (uint32_t line_number)
716 return display (line_number, string());
720 Strip::display (uint32_t line_number, const std::string& line)
722 assert (line_number <= 1);
724 MidiByteArray retval;
726 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
729 retval << _surface->sysex_hdr();
733 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
734 retval << (_index * 7 + (line_number * 0x38));
736 // ascii data to display
738 // pad with " " out to 6 chars
739 for (int i = line.length(); i < 6; ++i) {
743 // column spacer, unless it's the right-hand column
755 Strip::lock_controls ()
757 _controls_locked = true;
761 Strip::unlock_controls ()
763 _controls_locked = false;
767 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
769 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
770 if ((*i) == _route) {
771 _surface->write (_select->set_state (on));
776 _surface->write (_select->set_state (off));
780 Strip::vpot_mode_string () const
782 boost::shared_ptr<AutomationControl> ac = _vpot->control();
788 switch (ac->parameter().type()) {
791 case PanAzimuthAutomation:
793 case PanWidthAutomation:
795 case PanElevationAutomation:
797 case PanFrontBackAutomation:
799 case PanLFEAutomation:
807 Strip::flip_mode_changed (bool notify)
813 reset_saved_values ();
815 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
816 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
818 _fader->set_control (vpot_controllable);
819 _vpot->set_control (fader_controllable);
821 control_by_parameter[fader_controllable->parameter()] = _vpot;
822 control_by_parameter[vpot_controllable->parameter()] = _fader;
824 _surface->write (display (1, vpot_mode_string ()));
832 Strip::queue_display_reset (uint32_t msecs)
835 struct timeval delta;
837 gettimeofday (&now, 0);
839 delta.tv_sec = msecs/1000;
840 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
842 timeradd (&now, &delta, &when);
844 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
848 Strip::clear_display_reset ()
850 _reset_display_at = 0;
854 Strip::reset_display ()
857 _surface->write (display (1, vpot_mode_string()));
859 _surface->write (blank_display (1));
862 clear_display_reset ();
865 struct RouteCompareByName {
866 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
867 return a->name().compare (b->name()) < 0;
872 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
874 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
882 Strip::build_input_list (const ChanCount& channels)
884 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
886 input_bundles.clear ();
888 /* give user bundles first chance at being in the menu */
890 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
891 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
892 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
896 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
897 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
898 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
902 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
903 RouteList copy = *routes;
904 copy.sort (RouteCompareByName ());
906 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
907 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
913 Strip::build_output_list (const ChanCount& channels)
915 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
917 output_bundles.clear ();
919 /* give user bundles first chance at being in the menu */
921 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
923 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
927 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
928 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
929 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
933 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
934 RouteList copy = *routes;
935 copy.sort (RouteCompareByName ());
937 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
938 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
943 Strip::next_pot_mode ()
945 vector<Evoral::Parameter>::iterator i;
947 if (_surface->mcp().flip_mode()) {
948 /* do not change vpot mode while in flipped mode */
949 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
950 _surface->write (display (1, "Flip"));
951 queue_display_reset (1000);
956 boost::shared_ptr<AutomationControl> ac = _vpot->control();
962 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
966 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
967 if ((*i) == ac->parameter()) {
972 /* move to the next mode in the list, or back to the start (which will
973 also happen if the current mode is not in the current pot mode list)
976 if (i != possible_pot_parameters.end()) {
980 if (i == possible_pot_parameters.end()) {
981 i = possible_pot_parameters.begin();
984 set_vpot_parameter (*i);
988 Strip::set_vpot_parameter (Evoral::Parameter p)
990 boost::shared_ptr<Pannable> pannable;
992 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
994 reset_saved_values ();
997 case PanAzimuthAutomation:
998 pannable = _route->pannable ();
1000 if (_surface->mcp().flip_mode()) {
1001 /* gain to vpot, pan azi to fader */
1002 _vpot->set_control (_route->gain_control());
1003 control_by_parameter[GainAutomation] = _vpot;
1005 _fader->set_control (pannable->pan_azimuth_control);
1006 control_by_parameter[PanAzimuthAutomation] = _fader;
1008 _fader->set_control (boost::shared_ptr<AutomationControl>());
1009 control_by_parameter[PanAzimuthAutomation] = 0;
1012 /* gain to fader, pan azi to vpot */
1013 _fader->set_control (_route->gain_control());
1014 control_by_parameter[GainAutomation] = _fader;
1016 _vpot->set_control (pannable->pan_azimuth_control);
1017 control_by_parameter[PanAzimuthAutomation] = _vpot;
1019 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1020 control_by_parameter[PanAzimuthAutomation] = 0;
1025 case PanWidthAutomation:
1026 pannable = _route->pannable ();
1028 if (_surface->mcp().flip_mode()) {
1029 /* gain to vpot, pan width to fader */
1030 _vpot->set_control (_route->gain_control());
1031 control_by_parameter[GainAutomation] = _vpot;
1033 _fader->set_control (pannable->pan_width_control);
1034 control_by_parameter[PanWidthAutomation] = _fader;
1036 _fader->set_control (boost::shared_ptr<AutomationControl>());
1037 control_by_parameter[PanWidthAutomation] = 0;
1040 /* gain to fader, pan width to vpot */
1041 _fader->set_control (_route->gain_control());
1042 control_by_parameter[GainAutomation] = _fader;
1044 _vpot->set_control (pannable->pan_width_control);
1045 control_by_parameter[PanWidthAutomation] = _vpot;
1047 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1048 control_by_parameter[PanWidthAutomation] = 0;
1053 case PanElevationAutomation:
1055 case PanFrontBackAutomation:
1057 case PanLFEAutomation:
1061 _surface->write (display (1, vpot_mode_string()));
1065 Strip::reset_saved_values ()
1067 _last_pan_azi_position_written = -1.0;
1068 _last_pan_width_position_written = -1.0;
1069 _last_gain_position_written = -1.0;