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)
76 , _vpot_mode (PanAzimuth)
77 , _preflip_vpot_mode (PanAzimuth)
81 , _controls_locked (false)
82 , _reset_display_at (0)
83 , _last_gain_position_written (-1.0)
84 , _last_pan_position_written (-1.0)
86 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
87 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
88 _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));
100 /* surface is responsible for deleting all controls */
104 Strip::add (Control & control)
108 Group::add (control);
110 /* fader, vpot, meter were all set explicitly */
112 if ((button = dynamic_cast<Button*>(&control)) != 0) {
113 switch (button->bid()) {
114 case Button::RecEnable:
126 case Button::VSelect:
129 case Button::FaderTouch:
130 _fader_touch = button;
138 Strip::set_route (boost::shared_ptr<Route> r)
140 if (_controls_locked) {
144 route_connections.drop_connections ();
146 _solo->set_control (boost::shared_ptr<AutomationControl>());
147 _mute->set_control (boost::shared_ptr<AutomationControl>());
148 _select->set_control (boost::shared_ptr<AutomationControl>());
149 _recenable->set_control (boost::shared_ptr<AutomationControl>());
150 _fader->set_control (boost::shared_ptr<AutomationControl>());
151 _vpot->set_control (boost::shared_ptr<AutomationControl>());
159 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
160 _surface->number(), _index, _route->name()));
162 _solo->set_control (_route->solo_control());
163 _mute->set_control (_route->mute_control());
164 set_vpot_mode (PanAzimuth);
166 _route->solo_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_solo_changed, this), ui_context());
167 _route->mute_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_mute_changed, this), ui_context());
169 boost::shared_ptr<Pannable> pannable = _route->pannable();
172 pannable->pan_azimuth_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
173 pannable->pan_width_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_width_changed, this, false), ui_context());
175 _route->gain_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
176 _route->PropertyChanged.connect (route_connections, invalidator(), ui_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, invalidator(), ui_bind (&Strip::notify_record_enable_changed, this), ui_context());
185 // TODO this works when a currently-banked route is made inactive, but not
186 // when a route is activated which should be currently banked.
188 _route->active_changed.connect (route_connections, invalidator(), ui_bind (&Strip::notify_active_changed, this), ui_context());
189 _route->DropReferences.connect (route_connections, invalidator(), ui_bind (&Strip::notify_route_deleted, this), ui_context());
195 /* setup legal VPot modes for this route */
197 build_input_list (_route->input()->n_ports());
198 build_output_list (_route->output()->n_ports());
200 current_pot_modes.clear();
203 boost::shared_ptr<Panner> panner = pannable->panner();
205 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
206 set<Evoral::Parameter>::iterator a;
208 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
209 current_pot_modes.push_back (PanAzimuth);
212 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
213 current_pot_modes.push_back (PanWidth);
218 current_pot_modes.push_back (Input);
219 current_pot_modes.push_back (Output);
221 if (_route->nth_send (0) != 0) {
222 current_pot_modes.push_back (Send1);
224 if (_route->nth_send (1) != 0) {
225 current_pot_modes.push_back (Send2);
227 if (_route->nth_send (2) != 0) {
228 current_pot_modes.push_back (Send3);
230 if (_route->nth_send (3) != 0) {
231 current_pot_modes.push_back (Send4);
233 if (_route->nth_send (4) != 0) {
234 current_pot_modes.push_back (Send5);
236 if (_route->nth_send (5) != 0) {
237 current_pot_modes.push_back (Send6);
239 if (_route->nth_send (6) != 0) {
240 current_pot_modes.push_back (Send7);
242 if (_route->nth_send (7) != 0) {
243 current_pot_modes.push_back (Send8);
250 notify_solo_changed ();
251 notify_mute_changed ();
252 notify_gain_changed ();
253 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
254 notify_panner_azi_changed ();
255 notify_panner_width_changed ();
256 notify_record_enable_changed ();
260 Strip::notify_solo_changed ()
262 if (_route && _solo) {
263 _surface->write (_solo->set_state (_route->soloed() ? on : off));
268 Strip::notify_mute_changed ()
270 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
271 if (_route && _mute) {
272 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
273 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
275 _surface->write (_mute->set_state (_route->muted() ? on : off));
280 Strip::notify_record_enable_changed ()
282 if (_route && _recenable) {
283 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
288 Strip::notify_active_changed ()
290 _surface->mcp().refresh_current_bank();
294 Strip::notify_route_deleted ()
296 _surface->mcp().refresh_current_bank();
300 Strip::notify_gain_changed (bool force_update)
302 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("gain changed for strip %1, flip mode %2\n", _index, _surface->mcp().flip_mode()));
308 if (_surface->mcp().flip_mode()) {
314 if (!control->in_use()) {
316 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
318 float gain_coefficient = ac->get_value();
319 float normalized_position = ac->internal_to_interface (gain_coefficient);
321 if (force_update || normalized_position != _last_gain_position_written) {
324 if (_surface->mcp().flip_mode()) {
325 _surface->write (_vpot->set_all (normalized_position, true, Pot::wrap));
326 do_parameter_display (GainAutomation, gain_coefficient);
328 _surface->write (_fader->set_position (normalized_position));
329 do_parameter_display (GainAutomation, gain_coefficient);
332 queue_display_reset (2000);
333 _last_gain_position_written = normalized_position;
336 DEBUG_TRACE (DEBUG::MackieControl, "value is stale, no message sent\n");
339 DEBUG_TRACE (DEBUG::MackieControl, "fader in use, no message sent\n");
342 DEBUG_TRACE (DEBUG::MackieControl, "no route or no fader\n");
347 Strip::notify_property_changed (const PropertyChange& what_changed)
349 if (!what_changed.contains (ARDOUR::Properties::name)) {
355 string fullname = _route->name();
357 if (fullname.length() <= 6) {
360 line1 = PBD::short_version (fullname, 6);
363 _surface->write (display (0, line1));
368 Strip::notify_panner_azi_changed (bool force_update)
372 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
374 boost::shared_ptr<Pannable> pannable = _route->pannable();
377 _surface->write (_vpot->zero());
383 if (_surface->mcp().flip_mode()) {
386 if (_vpot_mode != PanAzimuth) {
392 if (!control->in_use()) {
394 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
396 if (force_update || pos != _last_pan_position_written) {
398 if (_surface->mcp().flip_mode()) {
400 _surface->write (_fader->set_position (pos));
401 do_parameter_display (PanAzimuthAutomation, pos);
403 _surface->write (_vpot->set_all (pos, true, Pot::dot));
404 do_parameter_display (PanAzimuthAutomation, pos);
407 queue_display_reset (2000);
408 _last_pan_position_written = pos;
415 Strip::notify_panner_width_changed (bool force_update)
419 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
421 boost::shared_ptr<Pannable> pannable = _route->pannable();
424 _surface->write (_vpot->zero());
430 if (_surface->mcp().flip_mode()) {
433 if (_vpot_mode != PanWidth) {
439 if (!control->in_use()) {
441 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
443 if (force_update || pos != _last_pan_position_written) {
445 if (_surface->mcp().flip_mode()) {
447 _surface->write (_fader->set_position (pos));
448 do_parameter_display (PanWidthAutomation, pos);
450 _surface->write (_vpot->set_all (pos, true, Pot::dot));
451 do_parameter_display (PanWidthAutomation, pos);
454 queue_display_reset (2000);
455 _last_pan_position_written = pos;
462 Strip::select_event (Button& button, ButtonState bs)
464 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
468 int ms = _surface->mcp().modifier_state();
470 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
471 _controls_locked = !_controls_locked;
472 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
473 queue_display_reset (1000);
477 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
478 /* reset to default */
479 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
481 ac->set_value (ac->normal());
486 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
487 _surface->mcp().add_down_select_button (_surface->number(), _index);
488 _surface->mcp().select_range ();
491 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
492 _surface->mcp().remove_down_select_button (_surface->number(), _index);
497 Strip::vselect_event (Button& button, ButtonState bs)
502 int ms = _surface->mcp().modifier_state();
504 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
505 boost::shared_ptr<AutomationControl> ac = button.control ();
509 /* reset to default/normal value */
510 ac->set_value (ac->normal());
514 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
522 Strip::fader_touch_event (Button& button, ButtonState bs)
524 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
526 /* never use the modified control for fader stuff */
530 _fader->set_in_use (true);
531 _fader->start_touch (_surface->mcp().transport_frame());
532 boost::shared_ptr<AutomationControl> ac = _fader->control ();
534 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
535 queue_display_reset (2000);
540 _fader->set_in_use (false);
541 _fader->stop_touch (_surface->mcp().transport_frame(), true);
548 Strip::handle_button (Button& button, ButtonState bs)
550 boost::shared_ptr<AutomationControl> control;
553 button.set_in_use (true);
555 button.set_in_use (false);
558 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
560 switch (button.bid()) {
562 select_event (button, bs);
565 case Button::VSelect:
566 vselect_event (button, bs);
569 case Button::FaderTouch:
570 fader_touch_event (button, bs);
574 if ((control = button.control ())) {
576 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
577 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
580 int ms = _surface->mcp().modifier_state();
582 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
583 /* reset to default/normal value */
584 new_value = control->normal();
586 new_value = control->get_value() ? 0.0 : 1.0;
589 /* get all controls that either have their
590 * button down or are within a range of
591 * several down buttons
594 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
597 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
598 controls.size(), control->parameter().type(), new_value));
602 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
603 (*c)->set_value (new_value);
607 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
608 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
616 Strip::do_parameter_display (AutomationType type, float val)
621 _surface->write (display (1, " -inf "));
624 float dB = accurate_coefficient_to_dB (val);
625 snprintf (buf, sizeof (buf), "%6.1f", dB);
626 _surface->write (display (1, buf));
630 case PanAzimuthAutomation:
632 boost::shared_ptr<Pannable> p = _route->pannable();
633 if (p && p->panner()) {
634 string str = p->panner()->value_as_string (p->pan_azimuth_control);
635 _surface->write (display (1, str));
640 case PanWidthAutomation:
643 snprintf (buf, sizeof (buf), "%5ld%%", lrintf (val * 100.0));
644 _surface->write (display (1, buf));
654 Strip::handle_fader (Fader& fader, float position)
656 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
658 fader.set_value (position);
659 fader.start_touch (_surface->mcp().transport_frame());
660 queue_display_reset (2000);
662 // must echo bytes back to slider now, because
663 // the notifier only works if the fader is not being
664 // touched. Which it is if we're getting input.
666 _surface->write (fader.set_position (position));
670 Strip::handle_pot (Pot& pot, float delta)
672 /* Pots only emit events when they move, not when they
673 stop moving. So to get a stop event, we need to use a timeout.
676 boost::shared_ptr<AutomationControl> ac = pot.control();
677 double p = pot.get_value ();
679 p = max (ac->lower(), p);
680 p = min (ac->upper(), p);
685 Strip::periodic (uint64_t usecs)
691 update_automation ();
694 if (_reset_display_at && _reset_display_at < usecs) {
700 Strip::update_automation ()
702 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
704 if (gain_state == Touch || gain_state == Play) {
705 notify_gain_changed (false);
708 if (_route->panner()) {
709 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
710 if (panner_state == Touch || panner_state == Play) {
711 notify_panner_azi_changed (false);
712 notify_panner_width_changed (false);
718 Strip::update_meter ()
721 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
722 _surface->write (_meter->update_message (dB));
729 MidiByteArray retval;
731 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
732 retval << (*it)->zero ();
735 retval << blank_display (0);
736 retval << blank_display (1);
742 Strip::blank_display (uint32_t line_number)
744 return display (line_number, string());
748 Strip::display (uint32_t line_number, const std::string& line)
750 assert (line_number <= 1);
752 MidiByteArray retval;
754 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
757 retval << _surface->sysex_hdr();
761 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
762 retval << (_index * 7 + (line_number * 0x38));
764 // ascii data to display
766 // pad with " " out to 6 chars
767 for (int i = line.length(); i < 6; ++i) {
771 // column spacer, unless it's the right-hand column
779 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieMidiBuilder::strip_display midi: %1\n", retval));
785 Strip::lock_controls ()
787 _controls_locked = true;
791 Strip::unlock_controls ()
793 _controls_locked = false;
797 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
799 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
800 if ((*i) == _route) {
801 return _select->set_state (on);
805 return _select->set_state (off);
809 Strip::vpot_mode_string () const
811 switch (_vpot_mode) {
850 Strip::flip_mode_changed (bool notify)
856 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
857 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
859 _fader->set_control (vpot_controllable);
860 _vpot->set_control (fader_controllable);
862 _surface->write (display (1, vpot_mode_string ()));
870 Strip::queue_display_reset (uint32_t msecs)
873 struct timeval delta;
875 gettimeofday (&now, 0);
877 delta.tv_sec = msecs/1000;
878 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
880 timeradd (&now, &delta, &when);
882 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
886 Strip::clear_display_reset ()
888 _reset_display_at = 0;
892 Strip::reset_display ()
894 _surface->write (display (1, vpot_mode_string()));
895 clear_display_reset ();
898 struct RouteCompareByName {
899 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
900 return a->name().compare (b->name()) < 0;
905 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
907 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
915 Strip::build_input_list (const ChanCount& channels)
917 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
919 input_bundles.clear ();
921 /* give user bundles first chance at being in the menu */
923 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
924 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
925 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
929 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
930 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
931 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
935 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
936 RouteList copy = *routes;
937 copy.sort (RouteCompareByName ());
939 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
940 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
946 Strip::build_output_list (const ChanCount& channels)
948 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
950 output_bundles.clear ();
952 /* give user bundles first chance at being in the menu */
954 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
955 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
956 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
960 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
961 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
962 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
966 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
967 RouteList copy = *routes;
968 copy.sort (RouteCompareByName ());
970 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
971 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
976 Strip::next_pot_mode ()
978 vector<PotMode>::iterator i;
980 if (_surface->mcp().flip_mode()) {
981 /* do not change vpot mode while in flipped mode */
982 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
983 _surface->write (display (1, "Flip"));
984 queue_display_reset (2000);
988 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
989 if ((*i) == _vpot_mode) {
994 /* move to the next mode in the list, or back to the start (which will
995 also happen if the current mode is not in the current pot mode list)
998 if (i != current_pot_modes.end()) {
1002 if (i == current_pot_modes.end()) {
1003 i = current_pot_modes.begin();
1010 Strip::set_vpot_mode (PotMode m)
1012 boost::shared_ptr<Send> send;
1013 boost::shared_ptr<Pannable> pannable;
1015 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", m));
1023 /* one of these is unnecessary, but its not worth trying to find
1024 out which - it will just cause one additional message to be
1025 sent to the surface.
1028 _last_pan_position_written = -1;
1029 _last_gain_position_written = -1;
1031 switch (_vpot_mode) {
1035 pannable = _route->pannable ();
1037 if (_surface->mcp().flip_mode()) {
1038 /* gain to vpot, pan azi to fader */
1039 _vpot->set_control (_route->gain_control());
1041 _fader->set_control (pannable->pan_azimuth_control);
1043 _vpot->set_mode (Pot::boost_cut);
1046 /* gain to fader, pan azi to vpot */
1047 _fader->set_control (_route->gain_control());
1049 _vpot->set_mode (Pot::spread);
1050 _vpot->set_control (pannable->pan_azimuth_control);
1056 pannable = _route->pannable ();
1058 if (_surface->mcp().flip_mode()) {
1059 /* gain to vpot, pan width to fader */
1060 _vpot->set_control (_route->gain_control());
1062 _fader->set_control (pannable->pan_width_control);
1064 _vpot->set_mode (Pot::boost_cut);
1067 /* gain to fader, pan width to vpot */
1068 _fader->set_control (_route->gain_control());
1070 _vpot->set_mode (Pot::spread);
1071 _vpot->set_control (pannable->pan_width_control);
1087 send = boost::dynamic_pointer_cast<Send> (_route->nth_send (0));
1089 if (_surface->mcp().flip_mode()) {
1090 /* route gain to vpot, send gain to fader */
1091 _fader->set_control (send->amp()->gain_control());
1092 _vpot->set_control (_route->gain_control());
1095 /* route gain to fader, send gain to vpot */
1096 _vpot->set_control (send->amp()->gain_control());
1097 _fader->set_control (_route->gain_control());
1117 _surface->write (display (1, vpot_mode_string()));