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 <glibmm/convert.h>
28 #include "midi++/port.h"
30 #include "pbd/compose.h"
31 #include "pbd/convert.h"
33 #include "ardour/amp.h"
34 #include "ardour/bundle.h"
35 #include "ardour/debug.h"
36 #include "ardour/midi_ui.h"
37 #include "ardour/meter.h"
38 #include "ardour/pannable.h"
39 #include "ardour/panner.h"
40 #include "ardour/panner_shell.h"
41 #include "ardour/rc_configuration.h"
42 #include "ardour/route.h"
43 #include "ardour/session.h"
44 #include "ardour/send.h"
45 #include "ardour/track.h"
46 #include "ardour/user_bundle.h"
48 #include "mackie_control_protocol.h"
49 #include "surface_port.h"
59 using namespace ARDOUR;
61 using namespace ArdourSurface;
62 using namespace Mackie;
64 #ifndef timeradd /// only avail with __USE_BSD
65 #define timeradd(a,b,result) \
67 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
68 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
69 if ((result)->tv_usec >= 1000000) \
72 (result)->tv_usec -= 1000000; \
77 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
79 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
92 , _controls_locked (false)
93 , _transport_is_rolling (false)
94 , _metering_active (true)
95 , _reset_display_at (0)
96 , _last_gain_position_written (-1.0)
97 , _last_pan_azi_position_written (-1.0)
98 , _last_pan_width_position_written (-1.0)
99 , redisplay_requests (256)
101 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
102 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
104 if (s.mcp().device_info().has_meters()) {
105 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
108 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
109 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
110 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
111 _surface->number(), index, Button::id_to_name (bb->bid()),
112 bb->id(), b->second.base_id));
118 /* surface is responsible for deleting all controls */
122 Strip::add (Control & control)
126 Group::add (control);
128 /* fader, vpot, meter were all set explicitly */
130 if ((button = dynamic_cast<Button*>(&control)) != 0) {
131 switch (button->bid()) {
132 case Button::RecEnable:
144 case Button::VSelect:
147 case Button::FaderTouch:
148 _fader_touch = button;
157 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
159 if (_controls_locked) {
163 route_connections.drop_connections ();
165 _solo->set_control (boost::shared_ptr<AutomationControl>());
166 _mute->set_control (boost::shared_ptr<AutomationControl>());
167 _select->set_control (boost::shared_ptr<AutomationControl>());
168 _recenable->set_control (boost::shared_ptr<AutomationControl>());
169 _fader->set_control (boost::shared_ptr<AutomationControl>());
170 _vpot->set_control (boost::shared_ptr<AutomationControl>());
174 control_by_parameter.clear ();
175 reset_saved_values ();
182 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
183 _surface->number(), _index, _route->name()));
185 _solo->set_control (_route->solo_control());
186 _mute->set_control (_route->mute_control());
188 set_vpot_parameter (PanAzimuthAutomation);
190 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
191 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
193 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
195 boost::shared_ptr<Pannable> pannable = _route->pannable();
197 if (pannable && _route->panner()) {
198 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
199 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
201 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
202 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
204 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
207 _recenable->set_control (trk->rec_enable_control());
208 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
213 // TODO this works when a currently-banked route is made inactive, but not
214 // when a route is activated which should be currently banked.
216 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
217 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
223 /* setup legal VPot modes for this route */
225 build_input_list (_route->input()->n_ports());
226 build_output_list (_route->output()->n_ports());
228 possible_pot_parameters.clear();
231 boost::shared_ptr<Panner> panner = _route->panner();
233 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
234 set<Evoral::Parameter>::iterator a;
236 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
237 possible_pot_parameters.push_back (PanAzimuthAutomation);
240 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
241 possible_pot_parameters.push_back (PanWidthAutomation);
255 notify_solo_changed ();
256 notify_mute_changed ();
257 notify_gain_changed ();
258 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
259 notify_panner_azi_changed ();
260 notify_panner_width_changed ();
261 notify_record_enable_changed ();
265 Strip::notify_solo_changed ()
267 if (_route && _solo) {
268 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
273 Strip::notify_mute_changed ()
275 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
276 if (_route && _mute) {
277 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
278 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
280 _surface->write (_mute->set_state (_route->muted() ? on : off));
285 Strip::notify_record_enable_changed ()
287 if (_route && _recenable) {
288 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
293 Strip::notify_active_changed ()
295 _surface->mcp().refresh_current_bank();
299 Strip::notify_route_deleted ()
301 _surface->mcp().refresh_current_bank();
305 Strip::notify_gain_changed (bool force_update)
311 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
317 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
319 float gain_coefficient = ac->get_value();
320 float normalized_position = ac->internal_to_interface (gain_coefficient);
323 if (force_update || normalized_position != _last_gain_position_written) {
325 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
326 if (!control->in_use()) {
327 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
329 queue_parameter_display (GainAutomation, gain_coefficient);
331 if (!control->in_use()) {
332 _surface->write (_fader->set_position (normalized_position));
334 queue_parameter_display (GainAutomation, gain_coefficient);
337 queue_display_reset (2000);
338 _last_gain_position_written = normalized_position;
344 Strip::notify_property_changed (const PropertyChange& what_changed)
346 if (!what_changed.contains (ARDOUR::Properties::name)) {
352 string fullname = _route->name();
354 if (fullname.length() <= 6) {
357 line1 = PBD::short_version (fullname, 6);
360 _surface->write (display (0, line1));
365 Strip::notify_panner_azi_changed (bool force_update)
369 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
371 boost::shared_ptr<Pannable> pannable = _route->pannable();
373 if (!pannable || !_route->panner()) {
374 _surface->write (_vpot->zero());
378 Control* control = control_by_parameter[PanAzimuthAutomation];
384 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
386 if (force_update || pos != _last_pan_azi_position_written) {
388 if (control == _fader) {
389 if (!_fader->in_use()) {
390 _surface->write (_fader->set_position (pos));
392 } else if (control == _vpot) {
393 _surface->write (_vpot->set (pos, true, Pot::dot));
396 queue_parameter_display (PanAzimuthAutomation, pos);
397 queue_display_reset (2000);
398 _last_pan_azi_position_written = pos;
404 Strip::notify_panner_width_changed (bool force_update)
408 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
410 boost::shared_ptr<Pannable> pannable = _route->pannable();
412 if (!pannable || !_route->panner()) {
413 _surface->write (_vpot->zero());
418 Control* control = control_by_parameter[PanWidthAutomation];
424 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
426 if (force_update || pos != _last_pan_azi_position_written) {
428 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
430 if (control == _fader) {
431 if (!control->in_use()) {
432 _surface->write (_fader->set_position (pos));
436 } else if (control == _vpot) {
437 _surface->write (_vpot->set (pos, true, Pot::spread));
440 queue_parameter_display (PanWidthAutomation, pos);
441 queue_display_reset (2000);
442 _last_pan_azi_position_written = pos;
448 Strip::select_event (Button&, ButtonState bs)
450 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
454 int ms = _surface->mcp().main_modifier_state();
456 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
457 _controls_locked = !_controls_locked;
458 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
459 queue_display_reset (1000);
463 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
464 /* reset to default */
465 boost::shared_ptr<AutomationControl> ac = _fader->control ();
467 ac->set_value (ac->normal());
472 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
473 _surface->mcp().add_down_select_button (_surface->number(), _index);
474 _surface->mcp().select_range ();
477 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
478 _surface->mcp().remove_down_select_button (_surface->number(), _index);
483 Strip::vselect_event (Button&, ButtonState bs)
487 int ms = _surface->mcp().main_modifier_state();
489 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
491 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
495 /* reset to default/normal value */
496 ac->set_value (ac->normal());
501 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
509 Strip::fader_touch_event (Button&, ButtonState bs)
511 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
515 boost::shared_ptr<AutomationControl> ac = _fader->control ();
517 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
519 ac->set_value (ac->normal());
523 _fader->set_in_use (true);
524 _fader->start_touch (_surface->mcp().transport_frame());
527 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
528 queue_display_reset (2000);
534 _fader->set_in_use (false);
535 _fader->stop_touch (_surface->mcp().transport_frame(), true);
542 Strip::handle_button (Button& button, ButtonState bs)
544 boost::shared_ptr<AutomationControl> control;
547 button.set_in_use (true);
549 button.set_in_use (false);
552 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
554 switch (button.bid()) {
556 select_event (button, bs);
559 case Button::VSelect:
560 vselect_event (button, bs);
563 case Button::FaderTouch:
564 fader_touch_event (button, bs);
568 if ((control = button.control ())) {
570 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
571 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
574 int ms = _surface->mcp().main_modifier_state();
576 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
577 /* reset to default/normal value */
578 new_value = control->normal();
580 new_value = control->get_value() ? 0.0 : 1.0;
583 /* get all controls that either have their
584 * button down or are within a range of
585 * several down buttons
588 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
591 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
592 controls.size(), control->parameter().type(), new_value));
596 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
597 (*c)->set_value (new_value);
601 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
602 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
610 Strip::queue_parameter_display (AutomationType type, float val)
612 RedisplayRequest req;
617 redisplay_requests.write (&req, 1);
621 Strip::do_parameter_display (AutomationType type, float val)
626 _surface->write (display (1, " -inf "));
629 float dB = accurate_coefficient_to_dB (val);
630 snprintf (buf, sizeof (buf), "%6.1f", dB);
631 _surface->write (display (1, buf));
635 case PanAzimuthAutomation:
637 boost::shared_ptr<Pannable> p = _route->pannable();
638 if (p && _route->panner()) {
639 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
640 _surface->write (display (1, str));
645 case PanWidthAutomation:
648 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
649 _surface->write (display (1, buf));
659 Strip::handle_fader_touch (Fader& fader, bool touch_on)
662 fader.start_touch (_surface->mcp().transport_frame());
664 fader.stop_touch (_surface->mcp().transport_frame(), false);
669 Strip::handle_fader (Fader& fader, float position)
671 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
673 fader.set_value (position);
675 /* From the Mackie Control MIDI implementation docs:
677 In order to ensure absolute synchronization with the host software,
678 Mackie Control uses a closed-loop servo system for the faders,
679 meaning the faders will always move to their last received position.
680 When a host receives a Fader Position Message, it must then
681 re-transmit that message to the Mackie Control or else the faders
682 will return to their last position.
685 _surface->write (fader.set_position (position));
689 Strip::handle_pot (Pot& pot, float delta)
691 /* Pots only emit events when they move, not when they
692 stop moving. So to get a stop event, we need to use a timeout.
695 boost::shared_ptr<AutomationControl> ac = pot.control();
696 double p = pot.get_value ();
698 p = max (ac->lower(), p);
699 p = min (ac->upper(), p);
704 Strip::periodic (uint64_t usecs)
710 update_automation ();
713 if (_reset_display_at && _reset_display_at < usecs) {
721 RedisplayRequest req;
722 bool have_request = false;
724 while (redisplay_requests.read (&req, 1) == 1) {
730 do_parameter_display (req.type, req.val);
735 Strip::update_automation ()
737 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
739 if (gain_state == Touch || gain_state == Play) {
740 notify_gain_changed (false);
743 if (_route->panner()) {
744 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
745 if (panner_state == Touch || panner_state == Play) {
746 notify_panner_azi_changed (false);
747 notify_panner_width_changed (false);
753 Strip::update_meter ()
755 if (_meter && _transport_is_rolling && _metering_active) {
756 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
757 _meter->send_update (*_surface, dB);
764 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
765 _surface->write ((*it)->zero ());
768 _surface->write (blank_display (0));
769 _surface->write (blank_display (1));
773 Strip::blank_display (uint32_t line_number)
775 return display (line_number, string());
779 Strip::display (uint32_t line_number, const std::string& line)
781 assert (line_number <= 1);
783 MidiByteArray retval;
785 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
788 retval << _surface->sysex_hdr();
792 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
793 retval << (_index * 7 + (line_number * 0x38));
795 // ascii data to display. @param line is UTF-8
796 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
797 string::size_type len = ascii.length();
799 ascii = ascii.substr (0, 6);
803 // pad with " " out to 6 chars
804 for (int i = len; i < 6; ++i) {
808 // column spacer, unless it's the right-hand column
820 Strip::lock_controls ()
822 _controls_locked = true;
826 Strip::unlock_controls ()
828 _controls_locked = false;
832 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
834 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
835 if ((*i) == _route) {
836 _surface->write (_select->set_state (on));
841 _surface->write (_select->set_state (off));
845 Strip::vpot_mode_string () const
847 boost::shared_ptr<AutomationControl> ac = _vpot->control();
853 switch (ac->parameter().type()) {
856 case PanAzimuthAutomation:
858 case PanWidthAutomation:
860 case PanElevationAutomation:
862 case PanFrontBackAutomation:
864 case PanLFEAutomation:
872 Strip::flip_mode_changed (bool notify)
878 reset_saved_values ();
880 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
881 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
883 _fader->set_control (vpot_controllable);
884 _vpot->set_control (fader_controllable);
886 control_by_parameter[fader_controllable->parameter()] = _vpot;
887 control_by_parameter[vpot_controllable->parameter()] = _fader;
889 _surface->write (display (1, vpot_mode_string ()));
897 Strip::queue_display_reset (uint32_t msecs)
900 struct timeval delta;
902 gettimeofday (&now, 0);
904 delta.tv_sec = msecs/1000;
905 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
907 timeradd (&now, &delta, &when);
909 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
913 Strip::clear_display_reset ()
915 _reset_display_at = 0;
919 Strip::reset_display ()
922 _surface->write (display (1, vpot_mode_string()));
924 _surface->write (blank_display (1));
927 clear_display_reset ();
930 struct RouteCompareByName {
931 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
932 return a->name().compare (b->name()) < 0;
937 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
939 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
947 Strip::build_input_list (const ChanCount& channels)
949 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
951 input_bundles.clear ();
953 /* give user bundles first chance at being in the menu */
955 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
956 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
957 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
961 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
962 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
963 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
967 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
968 RouteList copy = *routes;
969 copy.sort (RouteCompareByName ());
971 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
972 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
978 Strip::build_output_list (const ChanCount& channels)
980 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
982 output_bundles.clear ();
984 /* give user bundles first chance at being in the menu */
986 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
987 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
988 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
992 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
993 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
994 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
998 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
999 RouteList copy = *routes;
1000 copy.sort (RouteCompareByName ());
1002 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1003 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
1008 Strip::next_pot_mode ()
1010 vector<Evoral::Parameter>::iterator i;
1012 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1013 /* do not change vpot mode while in flipped mode */
1014 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1015 _surface->write (display (1, "Flip"));
1016 queue_display_reset (1000);
1021 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1027 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1031 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1032 if ((*i) == ac->parameter()) {
1037 /* move to the next mode in the list, or back to the start (which will
1038 also happen if the current mode is not in the current pot mode list)
1041 if (i != possible_pot_parameters.end()) {
1045 if (i == possible_pot_parameters.end()) {
1046 i = possible_pot_parameters.begin();
1049 set_vpot_parameter (*i);
1053 Strip::set_vpot_parameter (Evoral::Parameter p)
1055 boost::shared_ptr<Pannable> pannable;
1057 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1059 reset_saved_values ();
1062 case PanAzimuthAutomation:
1063 pannable = _route->pannable ();
1065 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1066 /* gain to vpot, pan azi to fader */
1067 _vpot->set_control (_route->gain_control());
1068 control_by_parameter[GainAutomation] = _vpot;
1070 _fader->set_control (pannable->pan_azimuth_control);
1071 control_by_parameter[PanAzimuthAutomation] = _fader;
1073 _fader->set_control (boost::shared_ptr<AutomationControl>());
1074 control_by_parameter[PanAzimuthAutomation] = 0;
1077 /* gain to fader, pan azi to vpot */
1078 _fader->set_control (_route->gain_control());
1079 control_by_parameter[GainAutomation] = _fader;
1081 _vpot->set_control (pannable->pan_azimuth_control);
1082 control_by_parameter[PanAzimuthAutomation] = _vpot;
1084 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1085 control_by_parameter[PanAzimuthAutomation] = 0;
1090 case PanWidthAutomation:
1091 pannable = _route->pannable ();
1093 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1094 /* gain to vpot, pan width to fader */
1095 _vpot->set_control (_route->gain_control());
1096 control_by_parameter[GainAutomation] = _vpot;
1098 _fader->set_control (pannable->pan_width_control);
1099 control_by_parameter[PanWidthAutomation] = _fader;
1101 _fader->set_control (boost::shared_ptr<AutomationControl>());
1102 control_by_parameter[PanWidthAutomation] = 0;
1105 /* gain to fader, pan width to vpot */
1106 _fader->set_control (_route->gain_control());
1107 control_by_parameter[GainAutomation] = _fader;
1109 _vpot->set_control (pannable->pan_width_control);
1110 control_by_parameter[PanWidthAutomation] = _vpot;
1112 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1113 control_by_parameter[PanWidthAutomation] = 0;
1118 case PanElevationAutomation:
1120 case PanFrontBackAutomation:
1122 case PanLFEAutomation:
1126 _surface->write (display (1, vpot_mode_string()));
1130 Strip::reset_saved_values ()
1132 _last_pan_azi_position_written = -1.0;
1133 _last_pan_width_position_written = -1.0;
1134 _last_gain_position_written = -1.0;
1139 Strip::notify_metering_state_changed()
1141 if (!_route || !_meter) {
1145 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1146 bool metering_active = _surface->mcp().metering_active ();
1148 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1152 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1154 if (!transport_is_rolling || !metering_active) {
1155 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1156 notify_panner_azi_changed (true);
1159 _transport_is_rolling = transport_is_rolling;
1160 _metering_active = metering_active;