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.
28 #include <glibmm/convert.h>
30 #include "midi++/port.h"
32 #include "pbd/compose.h"
33 #include "pbd/convert.h"
35 #include "ardour/amp.h"
36 #include "ardour/bundle.h"
37 #include "ardour/debug.h"
38 #include "ardour/midi_ui.h"
39 #include "ardour/meter.h"
40 #include "ardour/plugin_insert.h"
41 #include "ardour/pannable.h"
42 #include "ardour/panner.h"
43 #include "ardour/panner_shell.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/route.h"
46 #include "ardour/session.h"
47 #include "ardour/send.h"
48 #include "ardour/track.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/profile.h"
53 #include "mackie_control_protocol.h"
54 #include "surface_port.h"
65 using namespace ARDOUR;
67 using namespace ArdourSurface;
68 using namespace Mackie;
70 #ifndef timeradd /// only avail with __USE_BSD
71 #define timeradd(a,b,result) \
73 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
74 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
75 if ((result)->tv_usec >= 1000000) \
78 (result)->tv_usec -= 1000000; \
83 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
85 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
98 , _controls_locked (false)
99 , _transport_is_rolling (false)
100 , _metering_active (true)
101 , _block_screen_redisplay_until (0)
102 , return_to_vpot_mode_display_at (UINT64_MAX)
104 , _pan_mode (PanAzimuthAutomation)
105 , _last_gain_position_written (-1.0)
106 , _last_pan_azi_position_written (-1.0)
107 , _last_pan_width_position_written (-1.0)
108 , _last_trim_position_written (-1.0)
110 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
111 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
113 if (s.mcp().device_info().has_meters()) {
114 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
117 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
118 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
119 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
120 _surface->number(), index, Button::id_to_name (bb->bid()),
121 bb->id(), b->second.base_id));
127 /* surface is responsible for deleting all controls */
131 Strip::add (Control & control)
135 Group::add (control);
137 /* fader, vpot, meter were all set explicitly */
139 if ((button = dynamic_cast<Button*>(&control)) != 0) {
140 switch (button->bid()) {
141 case Button::RecEnable:
153 case Button::VSelect:
156 case Button::FaderTouch:
157 _fader_touch = button;
166 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
168 if (_controls_locked) {
172 mb_pan_controllable.reset();
174 route_connections.drop_connections ();
176 _solo->set_control (boost::shared_ptr<AutomationControl>());
177 _mute->set_control (boost::shared_ptr<AutomationControl>());
178 _select->set_control (boost::shared_ptr<AutomationControl>());
179 _recenable->set_control (boost::shared_ptr<AutomationControl>());
180 _fader->set_control (boost::shared_ptr<AutomationControl>());
181 _vpot->set_control (boost::shared_ptr<AutomationControl>());
185 reset_saved_values ();
192 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
193 _surface->number(), _index, _route->name()));
195 _solo->set_control (_route->solo_control());
196 _mute->set_control (_route->mute_control());
198 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
199 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
201 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
203 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control();
205 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
208 pan_control = _route->pan_width_control();
210 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
213 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
214 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
216 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
219 _recenable->set_control (trk->rec_enable_control());
220 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
223 // TODO this works when a currently-banked route is made inactive, but not
224 // when a route is activated which should be currently banked.
226 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
227 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
229 /* setup legal VPot modes for this route */
231 possible_pot_parameters.clear();
233 if (_route->pan_azimuth_control()) {
234 possible_pot_parameters.push_back (PanAzimuthAutomation);
236 if (_route->pan_width_control()) {
237 possible_pot_parameters.push_back (PanWidthAutomation);
239 if (_route->pan_elevation_control()) {
240 possible_pot_parameters.push_back (PanElevationAutomation);
242 if (_route->pan_frontback_control()) {
243 possible_pot_parameters.push_back (PanFrontBackAutomation);
245 if (_route->pan_lfe_control()) {
246 possible_pot_parameters.push_back (PanLFEAutomation);
249 _pan_mode = PanAzimuthAutomation;
251 if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
252 set_vpot_parameter (_pan_mode);
255 _fader->set_control (_route->gain_control());
267 // The active V-pot control may not be active for this strip
268 // But if we zero it in the controls function it may erase
269 // the one we do want
270 _surface->write (_vpot->zero());
272 notify_solo_changed ();
273 notify_mute_changed ();
274 notify_gain_changed ();
275 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
276 notify_panner_azi_changed ();
277 notify_panner_width_changed ();
278 notify_record_enable_changed ();
279 notify_processor_changed ();
283 Strip::notify_solo_changed ()
285 if (_route && _solo) {
286 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
291 Strip::notify_mute_changed ()
293 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
294 if (_route && _mute) {
295 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
296 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
298 _surface->write (_mute->set_state (_route->muted() ? on : off));
303 Strip::notify_record_enable_changed ()
305 if (_route && _recenable) {
306 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
311 Strip::notify_active_changed ()
313 _surface->mcp().refresh_current_bank();
317 Strip::notify_route_deleted ()
319 _surface->mcp().refresh_current_bank();
323 Strip::notify_gain_changed (bool force_update)
329 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
333 /* doesn't seem possible but lets be safe */
337 /* track gain control could be on vpot or fader, depending in
341 if (_vpot->control() == ac) {
343 } else if (_fader->control() == ac) {
349 float gain_coefficient = ac->get_value();
350 float normalized_position = ac->internal_to_interface (gain_coefficient);
352 if (force_update || normalized_position != _last_gain_position_written) {
354 if (!control->in_use()) {
355 if (control == _vpot) {
356 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
358 _surface->write (_fader->set_position (normalized_position));
362 do_parameter_display (GainAutomation, gain_coefficient);
363 _last_gain_position_written = normalized_position;
368 Strip::notify_processor_changed (bool force_update)
373 Strip::notify_property_changed (const PropertyChange& what_changed)
375 if (!what_changed.contains (ARDOUR::Properties::name)) {
383 Strip::show_route_name ()
385 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
387 if (svm != MackieControlProtocol::None) {
388 /* subview mode is responsible for upper line */
392 string fullname = string();
394 // make sure first three strips get cleared of view mode
399 fullname = _route->name();
403 if (fullname.length() <= 6) {
406 line1 = PBD::short_version (fullname, 6);
409 pending_display[0] = line1;
413 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
415 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
418 /* not in subview mode */
422 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
423 /* no longer in Sends subview mode */
427 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
433 float val = control->get_value();
434 do_parameter_display (type, val);
436 if (_vpot->control() == control) {
437 /* update pot/encoder */
438 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
444 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
446 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
449 /* not in subview mode */
453 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
454 /* no longer in TrackViewsubview mode */
458 boost::shared_ptr<AutomationControl> control;
459 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
463 control = r->trim_control();
465 case SoloIsolateAutomation:
466 control = r->solo_isolate_control ();
468 case SoloSafeAutomation:
469 control = r->solo_safe_control ();
471 case MonitoringAutomation:
473 control = track->monitoring_control();
476 case PhaseAutomation:
477 control = r->phase_control ();
484 float val = control->get_value();
486 /* Note: all of the displayed controllables require the display
487 * of their *actual* ("internal") value, not the version mapped
488 * into the normalized 0..1.0 ("interface") range.
491 do_parameter_display (type, val);
492 /* update pot/encoder */
493 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
498 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
500 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
503 /* not in subview mode */
507 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
508 /* no longer in EQ subview mode */
512 boost::shared_ptr<AutomationControl> control;
516 control = r->eq_gain_controllable (band);
519 control = r->eq_freq_controllable (band);
522 control = r->eq_q_controllable (band);
525 control = r->eq_shape_controllable (band);
528 control = r->eq_hpf_controllable ();
531 control = r->eq_enable_controllable ();
538 float val = control->get_value();
539 do_parameter_display (type, val);
540 /* update pot/encoder */
541 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
546 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
548 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
551 /* not in subview mode */
555 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
556 /* no longer in EQ subview mode */
560 boost::shared_ptr<AutomationControl> control;
561 bool reset_all = false;
565 control = r->comp_threshold_controllable ();
568 control = r->comp_speed_controllable ();
571 control = r->comp_mode_controllable ();
575 control = r->comp_makeup_controllable ();
578 control = r->comp_redux_controllable ();
581 control = r->comp_enable_controllable ();
587 if (propagate_mode && reset_all) {
588 _surface->subview_mode_changed ();
592 float val = control->get_value();
593 do_parameter_display (type, val);
594 /* update pot/encoder */
595 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
600 Strip::notify_panner_azi_changed (bool force_update)
606 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
608 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
611 /* basically impossible, since we're here because that control
612 * changed, but sure, whatever.
617 if (_vpot->control() != pan_control) {
621 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
622 double internal_pos = pan_control->get_value();
624 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
626 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
627 /* show actual internal value to user */
628 do_parameter_display (PanAzimuthAutomation, internal_pos);
630 _last_pan_azi_position_written = normalized_pos;
635 Strip::notify_panner_width_changed (bool force_update)
641 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
643 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
646 /* basically impossible, since we're here because that control
647 * changed, but sure, whatever.
652 if (_vpot->control() != pan_control) {
656 double pos = pan_control->internal_to_interface (pan_control->get_value());
658 if (force_update || pos != _last_pan_width_position_written) {
660 _surface->write (_vpot->set (pos, true, Pot::spread));
661 do_parameter_display (PanWidthAutomation, pos);
663 _last_pan_width_position_written = pos;
668 Strip::select_event (Button&, ButtonState bs)
670 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
674 int ms = _surface->mcp().main_modifier_state();
676 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
677 _controls_locked = !_controls_locked;
678 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
679 block_vpot_mode_display_for (1000);
683 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
684 /* reset to default */
685 boost::shared_ptr<AutomationControl> ac = _fader->control ();
687 ac->set_value (ac->normal(), Controllable::NoGroup);
692 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
693 _surface->mcp().add_down_select_button (_surface->number(), _index);
694 _surface->mcp().select_range ();
697 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
698 _surface->mcp().remove_down_select_button (_surface->number(), _index);
703 Strip::vselect_event (Button&, ButtonState bs)
705 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
707 /* most subview modes: vpot press acts like a button for toggle parameters */
713 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
715 boost::shared_ptr<AutomationControl> control = _vpot->control ();
720 Controllable::GroupControlDisposition gcd;
721 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
722 gcd = Controllable::InverseGroup;
724 gcd = Controllable::UseGroup;
727 if (control->toggled()) {
728 if (control->toggled()) {
729 control->set_value (!control->get_value(), gcd);
732 } else if (control->desc().enumeration || control->desc().integer_step) {
734 double val = control->get_value ();
735 if (val <= control->upper() - 1.0) {
736 control->set_value (val + 1.0, gcd);
738 control->set_value (control->lower(), gcd);
744 /* Send mode: press enables/disables the relevant
745 * send, but the vpot is bound to the send-level so we
746 * need to lookup the enable/disable control
750 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
754 const uint32_t global_pos = _surface->mcp().global_index (*this);
755 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
758 bool currently_enabled = (bool) control->get_value();
759 Controllable::GroupControlDisposition gcd;
761 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
762 gcd = Controllable::InverseGroup;
764 gcd = Controllable::UseGroup;
767 control->set_value (!currently_enabled, gcd);
769 if (currently_enabled) {
770 /* we just turned it off */
771 pending_display[1] = "off";
773 /* we just turned it on, show the level
775 control = _route->send_level_controllable (global_pos);
776 do_parameter_display (BusSendLevel, control->get_value());
782 /* done with this event in subview mode */
789 int ms = _surface->mcp().main_modifier_state();
791 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
793 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
797 /* reset to default/normal value */
798 ac->set_value (ac->normal(), Controllable::NoGroup);
805 boost::shared_ptr<AutomationControl> ac = _route->master_send_enable_controllable ();
807 Controllable::GroupControlDisposition gcd;
809 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
810 gcd = Controllable::InverseGroup;
812 gcd = Controllable::UseGroup;
815 bool enabled = ac->get_value();
816 ac->set_value (!enabled, gcd);
820 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
821 /* switch vpot to control next available parameter */
830 Strip::fader_touch_event (Button&, ButtonState bs)
832 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
836 boost::shared_ptr<AutomationControl> ac = _fader->control ();
838 _fader->set_in_use (true);
839 _fader->start_touch (_surface->mcp().transport_frame());
842 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
847 _fader->set_in_use (false);
848 _fader->stop_touch (_surface->mcp().transport_frame(), true);
855 Strip::handle_button (Button& button, ButtonState bs)
857 boost::shared_ptr<AutomationControl> control;
860 button.set_in_use (true);
862 button.set_in_use (false);
865 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
867 switch (button.bid()) {
869 select_event (button, bs);
872 case Button::VSelect:
873 vselect_event (button, bs);
876 case Button::FaderTouch:
877 fader_touch_event (button, bs);
881 if ((control = button.control ())) {
883 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
884 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
886 float new_value = control->get_value() ? 0.0 : 1.0;
888 /* get all controls that either have their
889 * button down or are within a range of
890 * several down buttons
893 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
896 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
897 controls.size(), control->parameter().type(), new_value));
899 /* apply change, with potential modifier semantics */
901 Controllable::GroupControlDisposition gcd;
903 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
904 gcd = Controllable::InverseGroup;
906 gcd = Controllable::UseGroup;
909 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
910 (*c)->set_value (new_value, gcd);
914 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
915 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
923 Strip::do_parameter_display (AutomationType type, float val)
925 bool screen_hold = false;
932 pending_display[1] = " -inf ";
934 float dB = accurate_coefficient_to_dB (val);
935 snprintf (buf, sizeof (buf), "%6.1f", dB);
936 pending_display[1] = buf;
941 case PanAzimuthAutomation:
942 if (Profile->get_mixbus()) {
943 snprintf (buf, sizeof (buf), "%2.1f", val);
944 pending_display[1] = buf;
948 boost::shared_ptr<Pannable> p = _route->pannable();
949 if (p && _route->panner()) {
950 pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
957 case PanWidthAutomation:
959 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
960 pending_display[1] = buf;
967 float dB = accurate_coefficient_to_dB (val);
968 snprintf (buf, sizeof (buf), "%6.1f", dB);
969 pending_display[1] = buf;
974 case PhaseAutomation:
977 pending_display[1] = "Normal";
979 pending_display[1] = "Invert";
994 snprintf (buf, sizeof (buf), "%6.1f", val);
995 pending_display[1] = buf;
1001 pending_display[1] = "on";
1003 pending_display[1] = "off";
1007 if (_surface->mcp().subview_route()) {
1008 pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1011 case SoloSafeAutomation:
1012 case SoloIsolateAutomation:
1014 pending_display[1] = "on";
1016 pending_display[1] = "off";
1019 case MonitoringAutomation:
1020 switch (MonitorChoice ((int) val)) {
1022 pending_display[1] = "auto";
1025 pending_display[1] = "input";
1028 pending_display[1] = "disk";
1030 case MonitorCue: /* XXX not implemented as of jan 2016 */
1031 pending_display[1] = "cue";
1040 /* we just queued up a parameter to be displayed.
1041 1 second from now, switch back to vpot mode display.
1043 block_vpot_mode_display_for (1000);
1048 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1051 fader.start_touch (_surface->mcp().transport_frame());
1053 fader.stop_touch (_surface->mcp().transport_frame(), false);
1058 Strip::handle_fader (Fader& fader, float position)
1060 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1061 boost::shared_ptr<AutomationControl> ac = fader.control();
1066 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1068 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1069 gcd = Controllable::InverseGroup;
1072 fader.set_value (position, gcd);
1074 /* From the Mackie Control MIDI implementation docs:
1076 In order to ensure absolute synchronization with the host software,
1077 Mackie Control uses a closed-loop servo system for the faders,
1078 meaning the faders will always move to their last received position.
1079 When a host receives a Fader Position Message, it must then
1080 re-transmit that message to the Mackie Control or else the faders
1081 will return to their last position.
1084 _surface->write (fader.set_position (position));
1088 Strip::handle_pot (Pot& pot, float delta)
1090 /* Pots only emit events when they move, not when they
1091 stop moving. So to get a stop event, we need to use a timeout.
1094 boost::shared_ptr<AutomationControl> ac = pot.control();
1099 Controllable::GroupControlDisposition gcd;
1101 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1102 gcd = Controllable::InverseGroup;
1104 gcd = Controllable::UseGroup;
1107 if (ac->toggled()) {
1109 /* make it like a single-step, directional switch */
1112 ac->set_value (1.0, gcd);
1114 ac->set_value (0.0, gcd);
1117 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1119 /* use Controllable::get_value() to avoid the
1120 * "scaling-to-interface" that takes place in
1121 * Control::get_value() via the pot member.
1123 * an enumeration with 4 values will have interface values of
1124 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1129 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1131 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1136 double p = ac->get_value();
1140 p = max (ac->lower(), p);
1141 p = min (ac->upper(), p);
1143 ac->set_value (p, gcd);
1148 Strip::periodic (ARDOUR::microseconds_t now)
1151 update_automation ();
1155 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1157 if (_block_screen_redisplay_until >= now) {
1158 /* no drawing allowed */
1162 if (_block_screen_redisplay_until) {
1163 /* we were blocked, but the time period has elapsed, so we must
1167 _block_screen_redisplay_until = 0;
1170 if (force || (current_display[0] != pending_display[0])) {
1171 _surface->write (display (0, pending_display[0]));
1172 current_display[0] = pending_display[0];
1175 if (return_to_vpot_mode_display_at <= now) {
1176 return_to_vpot_mode_display_at = UINT64_MAX;
1177 return_to_vpot_mode_display ();
1180 if (force || (current_display[1] != pending_display[1])) {
1181 _surface->write (display (1, pending_display[1]));
1182 current_display[1] = pending_display[1];
1187 Strip::update_automation ()
1193 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1195 if (state == Touch || state == Play) {
1196 notify_gain_changed (false);
1199 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1201 state = pan_control->automation_state ();
1202 if (state == Touch || state == Play) {
1203 notify_panner_azi_changed (false);
1207 pan_control = _route->pan_width_control ();
1209 state = pan_control->automation_state ();
1210 if (state == Touch || state == Play) {
1211 notify_panner_width_changed (false);
1217 Strip::update_meter ()
1223 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1227 if (_meter && _transport_is_rolling && _metering_active) {
1228 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1229 _meter->send_update (*_surface, dB);
1237 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1238 _surface->write ((*it)->zero ());
1241 _surface->write (blank_display (0));
1242 _surface->write (blank_display (1));
1243 pending_display[0] = string();
1244 pending_display[1] = string();
1245 current_display[0] = string();
1246 current_display[1] = string();
1250 Strip::blank_display (uint32_t line_number)
1252 return display (line_number, string());
1256 Strip::display (uint32_t line_number, const std::string& line)
1258 assert (line_number <= 1);
1260 MidiByteArray retval;
1262 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1265 retval << _surface->sysex_hdr();
1269 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1270 retval << (_index * 7 + (line_number * 0x38));
1272 // ascii data to display. @param line is UTF-8
1273 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1274 string::size_type len = ascii.length();
1276 ascii = ascii.substr (0, 6);
1280 // pad with " " out to 6 chars
1281 for (int i = len; i < 6; ++i) {
1285 // column spacer, unless it's the right-hand column
1291 retval << MIDI::eox;
1297 Strip::lock_controls ()
1299 _controls_locked = true;
1303 Strip::unlock_controls ()
1305 _controls_locked = false;
1309 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1311 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1312 if ((*i) == _route) {
1313 _surface->write (_select->set_state (on));
1318 _surface->write (_select->set_state (off));
1322 Strip::vpot_mode_string ()
1324 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1328 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1334 switch (ac->desc().type) {
1335 case PanAzimuthAutomation:
1337 case PanWidthAutomation:
1339 case PanElevationAutomation:
1341 case PanFrontBackAutomation:
1343 case PanLFEAutomation:
1353 Strip::flip_mode_changed ()
1355 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1357 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1358 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1360 if (pot_control && fader_control) {
1361 _vpot->set_control (fader_control);
1362 _fader->set_control (pot_control);
1365 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1366 do_parameter_display (GainAutomation, fader_control->get_value());
1368 do_parameter_display (BusSendLevel, fader_control->get_value());
1373 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1377 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1386 Strip::block_screen_display_for (uint32_t msecs)
1388 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1392 Strip::block_vpot_mode_display_for (uint32_t msecs)
1394 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1398 Strip::return_to_vpot_mode_display ()
1400 /* returns the second line of the two-line per-strip display
1401 back the mode where it shows what the VPot controls.
1404 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1405 /* do nothing - second line shows value of current subview parameter */
1407 } else if (_route) {
1408 pending_display[1] = vpot_mode_string();
1410 pending_display[1] = string();
1415 Strip::next_pot_mode ()
1417 vector<AutomationType>::iterator i;
1419 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1420 /* do not change vpot mode while in flipped mode */
1421 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1422 pending_display[1] = "Flip";
1423 block_vpot_mode_display_for (1000);
1428 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1435 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1439 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1443 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1444 if ((*i) == ac->parameter().type()) {
1449 /* move to the next mode in the list, or back to the start (which will
1450 also happen if the current mode is not in the current pot mode list)
1453 if (i != possible_pot_parameters.end()) {
1457 if (i == possible_pot_parameters.end()) {
1458 i = possible_pot_parameters.begin();
1461 set_vpot_parameter (*i);
1465 Strip::subview_mode_changed ()
1467 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1469 subview_connections.drop_connections ();
1471 switch (_surface->mcp().subview_mode()) {
1472 case MackieControlProtocol::None:
1473 set_vpot_parameter (_pan_mode);
1474 /* need to show strip name again */
1476 notify_metering_state_changed ();
1480 case MackieControlProtocol::EQ:
1484 /* leave it as it was */
1488 case MackieControlProtocol::Dynamics:
1492 /* leave it as it was */
1497 case MackieControlProtocol::Sends:
1499 setup_sends_vpot (r);
1501 /* leave it as it was */
1505 case MackieControlProtocol::TrackView:
1507 setup_trackview_vpot (r);
1509 /* leave it as it was */
1517 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1523 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1524 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1525 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1526 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1527 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1528 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1530 uint32_t pos = _surface->mcp().global_index (*this);
1532 /* we will control the pos-th available parameter, from the list in the
1533 * order shown above.
1536 vector<boost::shared_ptr<AutomationControl> > available;
1537 vector<AutomationType> params;
1539 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1540 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1541 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1542 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1543 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1544 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1546 if (pos >= available.size()) {
1547 /* this knob is not needed to control the available parameters */
1548 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1549 pending_display[0] = string();
1550 pending_display[1] = string();
1554 boost::shared_ptr<AutomationControl> pc;
1555 AutomationType param;
1557 pc = available[pos];
1558 param = params[pos];
1560 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1561 _vpot->set_control (pc);
1571 pot_id = r->comp_speed_name (mc->get_value());
1592 if (!pot_id.empty()) {
1593 pending_display[0] = pot_id;
1595 pending_display[0] = string();
1598 notify_dyn_change (param, true, false);
1602 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1604 uint32_t bands = r->eq_band_cnt ();
1607 /* should never get here */
1611 /* figure out how many params per band are available */
1613 boost::shared_ptr<AutomationControl> pc;
1614 uint32_t params_per_band = 0;
1616 if ((pc = r->eq_gain_controllable (0))) {
1617 params_per_band += 1;
1619 if ((pc = r->eq_freq_controllable (0))) {
1620 params_per_band += 1;
1622 if ((pc = r->eq_q_controllable (0))) {
1623 params_per_band += 1;
1625 if ((pc = r->eq_shape_controllable (0))) {
1626 params_per_band += 1;
1629 /* pick the one for this strip, based on its global position across
1635 const uint32_t total_band_parameters = bands * params_per_band;
1636 const uint32_t global_pos = _surface->mcp().global_index (*this);
1637 AutomationType param = NullAutomation;
1642 if (global_pos < total_band_parameters) {
1644 /* show a parameter for an EQ band */
1646 const uint32_t parameter = global_pos % params_per_band;
1647 eq_band = global_pos / params_per_band;
1648 band_name = r->eq_band_name (eq_band);
1650 switch (parameter) {
1652 pc = r->eq_gain_controllable (eq_band);
1656 pc = r->eq_freq_controllable (eq_band);
1657 param = EQFrequency;
1660 pc = r->eq_q_controllable (eq_band);
1664 pc = r->eq_shape_controllable (eq_band);
1671 /* show a non-band parameter (HPF or enable)
1674 uint32_t parameter = global_pos - total_band_parameters;
1676 switch (parameter) {
1677 case 0: /* first control after band parameters */
1678 pc = r->eq_hpf_controllable();
1681 case 1: /* second control after band parameters */
1682 pc = r->eq_enable_controllable();
1686 /* nothing to control */
1687 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1688 pending_display[0] = string();
1689 pending_display[1] = string();
1698 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1699 _vpot->set_control (pc);
1705 pot_id = band_name + "Gain";
1708 pot_id = band_name + "Freq";
1711 pot_id = band_name + " Q";
1714 pot_id = band_name + " Shp";
1726 if (!pot_id.empty()) {
1727 pending_display[0] = pot_id;
1729 pending_display[0] = string();
1732 notify_eq_change (param, eq_band, true);
1737 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1743 const uint32_t global_pos = _surface->mcp().global_index (*this);
1745 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1748 pending_display[0] = string();
1749 pending_display[1] = string();
1753 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1754 _vpot->set_control (pc);
1756 pending_display[0] = r->send_name (global_pos);
1758 notify_send_level_change (BusSendLevel, global_pos, true);
1762 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1768 const uint32_t global_pos = _surface->mcp().global_index (*this);
1770 if (global_pos >= 8) {
1771 pending_display[0] = string();
1772 pending_display[1] = string();
1776 boost::shared_ptr<AutomationControl> pc;
1777 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1780 switch (global_pos) {
1782 pc = r->trim_control ();
1784 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1785 pending_display[0] = "Trim";
1786 notify_trackview_change (TrimAutomation, global_pos, true);
1791 pc = track->monitoring_control();
1793 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1794 pending_display[0] = "Mon";
1795 notify_trackview_change (MonitoringAutomation, global_pos, true);
1800 pc = r->solo_isolate_control ();
1802 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1803 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1804 pending_display[0] = "S-Iso";
1808 pc = r->solo_safe_control ();
1810 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1811 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1812 pending_display[0] = "S-Safe";
1816 pc = r->phase_control();
1818 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1819 notify_trackview_change (PhaseAutomation, global_pos, true);
1820 pending_display[0] = "Phase";
1824 // pc = r->trim_control ();
1827 // pc = r->trim_control ();
1830 // pc = r->trim_control ();
1835 pending_display[0] = string();
1836 pending_display[1] = string();
1840 _vpot->set_control (pc);
1844 Strip::set_vpot_parameter (AutomationType p)
1846 if (!_route || (p == NullAutomation)) {
1847 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1848 pending_display[1] = string();
1852 boost::shared_ptr<AutomationControl> pan_control;
1854 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1856 reset_saved_values ();
1859 case PanAzimuthAutomation:
1860 pan_control = _route->pan_azimuth_control ();
1862 case PanWidthAutomation:
1863 pan_control = _route->pan_width_control ();
1865 case PanElevationAutomation:
1867 case PanFrontBackAutomation:
1869 case PanLFEAutomation:
1877 _vpot->set_control (pan_control);
1880 pending_display[1] = vpot_mode_string ();
1884 Strip::is_midi_track () const
1886 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1890 Strip::reset_saved_values ()
1892 _last_pan_azi_position_written = -1.0;
1893 _last_pan_width_position_written = -1.0;
1894 _last_gain_position_written = -1.0;
1895 _last_trim_position_written = -1.0;
1900 Strip::notify_metering_state_changed()
1902 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1906 if (!_route || !_meter) {
1910 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1911 bool metering_active = _surface->mcp().metering_active ();
1913 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1917 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1919 if (!transport_is_rolling || !metering_active) {
1920 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1921 notify_panner_azi_changed (true);
1924 _transport_is_rolling = transport_is_rolling;
1925 _metering_active = metering_active;