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;
460 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
464 control = r->trim_control();
466 case SoloIsolateAutomation:
467 control = r->solo_isolate_control ();
469 case SoloSafeAutomation:
470 control = r->solo_safe_control ();
472 case MonitoringAutomation:
474 control = track->monitoring_control();
477 case PhaseAutomation:
478 control = r->phase_control ();
485 float val = control->get_value();
486 if (control->desc().enumeration || control->desc().integer_step) {
487 do_parameter_display (type, val);
489 do_parameter_display (type, control->internal_to_interface (val));
491 /* update pot/encoder */
492 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
497 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
499 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
502 /* not in subview mode */
506 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
507 /* no longer in EQ subview mode */
511 boost::shared_ptr<AutomationControl> control;
515 control = r->eq_gain_controllable (band);
518 control = r->eq_freq_controllable (band);
521 control = r->eq_q_controllable (band);
524 control = r->eq_shape_controllable (band);
527 control = r->eq_hpf_controllable ();
530 control = r->eq_enable_controllable ();
537 float val = control->get_value();
538 do_parameter_display (type, val);
539 /* update pot/encoder */
540 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
545 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
547 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
550 /* not in subview mode */
554 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
555 /* no longer in EQ subview mode */
559 boost::shared_ptr<AutomationControl> control;
560 bool reset_all = false;
564 control = r->comp_threshold_controllable ();
567 control = r->comp_speed_controllable ();
570 control = r->comp_mode_controllable ();
574 control = r->comp_makeup_controllable ();
577 control = r->comp_redux_controllable ();
580 control = r->comp_enable_controllable ();
586 if (propagate_mode && reset_all) {
587 _surface->subview_mode_changed ();
591 float val = control->get_value();
592 do_parameter_display (type, val);
593 /* update pot/encoder */
594 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
599 Strip::notify_panner_azi_changed (bool force_update)
605 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
607 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
610 /* basically impossible, since we're here because that control
611 * changed, but sure, whatever.
616 if (_vpot->control() != pan_control) {
620 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
621 double internal_pos = pan_control->get_value();
623 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
625 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
626 /* show actual internal value to user */
627 do_parameter_display (PanAzimuthAutomation, internal_pos);
629 _last_pan_azi_position_written = normalized_pos;
634 Strip::notify_panner_width_changed (bool force_update)
640 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
642 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
645 /* basically impossible, since we're here because that control
646 * changed, but sure, whatever.
651 if (_vpot->control() != pan_control) {
655 double pos = pan_control->internal_to_interface (pan_control->get_value());
657 if (force_update || pos != _last_pan_width_position_written) {
659 _surface->write (_vpot->set (pos, true, Pot::spread));
660 do_parameter_display (PanWidthAutomation, pos);
662 _last_pan_width_position_written = pos;
667 Strip::select_event (Button&, ButtonState bs)
669 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
673 int ms = _surface->mcp().main_modifier_state();
675 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
676 _controls_locked = !_controls_locked;
677 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
678 block_vpot_mode_display_for (1000);
682 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
683 /* reset to default */
684 boost::shared_ptr<AutomationControl> ac = _fader->control ();
686 ac->set_value (ac->normal(), Controllable::NoGroup);
691 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
692 _surface->mcp().add_down_select_button (_surface->number(), _index);
693 _surface->mcp().select_range ();
696 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
697 _surface->mcp().remove_down_select_button (_surface->number(), _index);
702 Strip::vselect_event (Button&, ButtonState bs)
704 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
706 /* most subview modes: vpot press acts like a button for toggle parameters */
712 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
714 boost::shared_ptr<AutomationControl> control = _vpot->control ();
719 Controllable::GroupControlDisposition gcd;
720 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
721 gcd = Controllable::InverseGroup;
723 gcd = Controllable::UseGroup;
726 if (control->toggled()) {
727 if (control->toggled()) {
728 control->set_value (!control->get_value(), gcd);
731 } else if (control->desc().enumeration || control->desc().integer_step) {
733 double val = control->get_value ();
734 if (val <= control->upper() - 1.0) {
735 control->set_value (val + 1.0, gcd);
737 control->set_value (control->lower(), gcd);
743 /* Send mode: press enables/disables the relevant
744 * send, but the vpot is bound to the send-level so we
745 * need to lookup the enable/disable control
749 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
753 const uint32_t global_pos = _surface->mcp().global_index (*this);
754 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
757 bool currently_enabled = (bool) control->get_value();
758 Controllable::GroupControlDisposition gcd;
760 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
761 gcd = Controllable::InverseGroup;
763 gcd = Controllable::UseGroup;
766 control->set_value (!currently_enabled, gcd);
768 if (currently_enabled) {
769 /* we just turned it off */
770 pending_display[1] = "off";
772 /* we just turned it on, show the level
774 control = _route->send_level_controllable (global_pos);
775 do_parameter_display (BusSendLevel, control->get_value());
781 /* done with this event in subview mode */
788 int ms = _surface->mcp().main_modifier_state();
790 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
792 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
796 /* reset to default/normal value */
797 ac->set_value (ac->normal(), Controllable::NoGroup);
804 boost::shared_ptr<AutomationControl> ac = _route->master_send_enable_controllable ();
806 Controllable::GroupControlDisposition gcd;
808 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
809 gcd = Controllable::InverseGroup;
811 gcd = Controllable::UseGroup;
814 bool enabled = ac->get_value();
815 ac->set_value (!enabled, gcd);
819 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
820 /* switch vpot to control next available parameter */
829 Strip::fader_touch_event (Button&, ButtonState bs)
831 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
835 boost::shared_ptr<AutomationControl> ac = _fader->control ();
837 _fader->set_in_use (true);
838 _fader->start_touch (_surface->mcp().transport_frame());
841 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
846 _fader->set_in_use (false);
847 _fader->stop_touch (_surface->mcp().transport_frame(), true);
854 Strip::handle_button (Button& button, ButtonState bs)
856 boost::shared_ptr<AutomationControl> control;
859 button.set_in_use (true);
861 button.set_in_use (false);
864 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
866 switch (button.bid()) {
868 select_event (button, bs);
871 case Button::VSelect:
872 vselect_event (button, bs);
875 case Button::FaderTouch:
876 fader_touch_event (button, bs);
880 if ((control = button.control ())) {
882 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
883 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
885 float new_value = control->get_value() ? 0.0 : 1.0;
887 /* get all controls that either have their
888 * button down or are within a range of
889 * several down buttons
892 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
895 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
896 controls.size(), control->parameter().type(), new_value));
898 /* apply change, with potential modifier semantics */
900 Controllable::GroupControlDisposition gcd;
902 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
903 gcd = Controllable::InverseGroup;
905 gcd = Controllable::UseGroup;
908 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
909 (*c)->set_value (new_value, gcd);
913 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
914 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
922 Strip::do_parameter_display (AutomationType type, float val)
924 bool screen_hold = false;
931 pending_display[1] = " -inf ";
933 float dB = accurate_coefficient_to_dB (val);
934 snprintf (buf, sizeof (buf), "%6.1f", dB);
935 pending_display[1] = buf;
940 case PanAzimuthAutomation:
941 if (Profile->get_mixbus()) {
942 snprintf (buf, sizeof (buf), "%2.1f", val);
943 pending_display[1] = buf;
947 boost::shared_ptr<Pannable> p = _route->pannable();
948 if (p && _route->panner()) {
949 pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
956 case PanWidthAutomation:
958 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
959 pending_display[1] = buf;
966 float dB = accurate_coefficient_to_dB (val);
967 snprintf (buf, sizeof (buf), "%6.1f", dB);
968 pending_display[1] = buf;
973 case PhaseAutomation:
976 pending_display[1] = "Normal";
978 pending_display[1] = "Invert";
993 snprintf (buf, sizeof (buf), "%6.1f", val);
994 pending_display[1] = buf;
1000 pending_display[1] = "on";
1002 pending_display[1] = "off";
1006 if (_surface->mcp().subview_route()) {
1007 pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1010 case SoloSafeAutomation:
1011 case SoloIsolateAutomation:
1013 pending_display[1] = "on";
1015 pending_display[1] = "off";
1018 case MonitoringAutomation:
1019 switch (MonitorChoice ((int) val)) {
1021 pending_display[1] = "auto";
1024 pending_display[1] = "input";
1027 pending_display[1] = "disk";
1029 case MonitorCue: /* XXX not implemented as of jan 2016 */
1030 pending_display[1] = "cue";
1039 /* we just queued up a parameter to be displayed.
1040 1 second from now, switch back to vpot mode display.
1042 block_vpot_mode_display_for (1000);
1047 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1050 fader.start_touch (_surface->mcp().transport_frame());
1052 fader.stop_touch (_surface->mcp().transport_frame(), false);
1057 Strip::handle_fader (Fader& fader, float position)
1059 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1060 boost::shared_ptr<AutomationControl> ac = fader.control();
1065 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1067 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1068 gcd = Controllable::InverseGroup;
1071 fader.set_value (position, gcd);
1073 /* From the Mackie Control MIDI implementation docs:
1075 In order to ensure absolute synchronization with the host software,
1076 Mackie Control uses a closed-loop servo system for the faders,
1077 meaning the faders will always move to their last received position.
1078 When a host receives a Fader Position Message, it must then
1079 re-transmit that message to the Mackie Control or else the faders
1080 will return to their last position.
1083 _surface->write (fader.set_position (position));
1087 Strip::handle_pot (Pot& pot, float delta)
1089 /* Pots only emit events when they move, not when they
1090 stop moving. So to get a stop event, we need to use a timeout.
1093 boost::shared_ptr<AutomationControl> ac = pot.control();
1098 Controllable::GroupControlDisposition gcd;
1100 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1101 gcd = Controllable::InverseGroup;
1103 gcd = Controllable::UseGroup;
1106 if (ac->toggled()) {
1108 /* make it like a single-step, directional switch */
1111 ac->set_value (1.0, gcd);
1113 ac->set_value (0.0, gcd);
1116 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1118 /* use Controllable::get_value() to avoid the
1119 * "scaling-to-interface" that takes place in
1120 * Control::get_value() via the pot member.
1122 * an enumeration with 4 values will have interface values of
1123 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1128 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1130 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1135 double p = ac->get_value();
1139 p = max (ac->lower(), p);
1140 p = min (ac->upper(), p);
1142 ac->set_value (p, gcd);
1147 Strip::periodic (ARDOUR::microseconds_t now)
1150 update_automation ();
1154 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1156 if (_block_screen_redisplay_until >= now) {
1157 /* no drawing allowed */
1161 if (_block_screen_redisplay_until) {
1162 /* we were blocked, but the time period has elapsed, so we must
1166 _block_screen_redisplay_until = 0;
1169 if (force || (current_display[0] != pending_display[0])) {
1170 _surface->write (display (0, pending_display[0]));
1171 current_display[0] = pending_display[0];
1174 if (return_to_vpot_mode_display_at <= now) {
1175 return_to_vpot_mode_display_at = UINT64_MAX;
1176 return_to_vpot_mode_display ();
1179 if (force || (current_display[1] != pending_display[1])) {
1180 _surface->write (display (1, pending_display[1]));
1181 current_display[1] = pending_display[1];
1186 Strip::update_automation ()
1192 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1194 if (state == Touch || state == Play) {
1195 notify_gain_changed (false);
1198 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1200 state = pan_control->automation_state ();
1201 if (state == Touch || state == Play) {
1202 notify_panner_azi_changed (false);
1206 pan_control = _route->pan_width_control ();
1208 state = pan_control->automation_state ();
1209 if (state == Touch || state == Play) {
1210 notify_panner_width_changed (false);
1216 Strip::update_meter ()
1222 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1226 if (_meter && _transport_is_rolling && _metering_active) {
1227 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1228 _meter->send_update (*_surface, dB);
1236 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1237 _surface->write ((*it)->zero ());
1240 _surface->write (blank_display (0));
1241 _surface->write (blank_display (1));
1242 pending_display[0] = string();
1243 pending_display[1] = string();
1244 current_display[0] = string();
1245 current_display[1] = string();
1249 Strip::blank_display (uint32_t line_number)
1251 return display (line_number, string());
1255 Strip::display (uint32_t line_number, const std::string& line)
1257 assert (line_number <= 1);
1259 MidiByteArray retval;
1261 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1264 retval << _surface->sysex_hdr();
1268 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1269 retval << (_index * 7 + (line_number * 0x38));
1271 // ascii data to display. @param line is UTF-8
1272 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1273 string::size_type len = ascii.length();
1275 ascii = ascii.substr (0, 6);
1279 // pad with " " out to 6 chars
1280 for (int i = len; i < 6; ++i) {
1284 // column spacer, unless it's the right-hand column
1290 retval << MIDI::eox;
1296 Strip::lock_controls ()
1298 _controls_locked = true;
1302 Strip::unlock_controls ()
1304 _controls_locked = false;
1308 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1310 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1311 if ((*i) == _route) {
1312 _surface->write (_select->set_state (on));
1317 _surface->write (_select->set_state (off));
1321 Strip::vpot_mode_string ()
1323 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1327 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1333 switch (ac->desc().type) {
1334 case PanAzimuthAutomation:
1336 case PanWidthAutomation:
1338 case PanElevationAutomation:
1340 case PanFrontBackAutomation:
1342 case PanLFEAutomation:
1352 Strip::flip_mode_changed ()
1354 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1356 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1357 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1359 if (pot_control && fader_control) {
1360 _vpot->set_control (fader_control);
1361 _fader->set_control (pot_control);
1364 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1365 do_parameter_display (GainAutomation, fader_control->get_value());
1367 do_parameter_display (BusSendLevel, fader_control->get_value());
1376 Strip::block_screen_display_for (uint32_t msecs)
1378 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1382 Strip::block_vpot_mode_display_for (uint32_t msecs)
1384 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1388 Strip::return_to_vpot_mode_display ()
1390 /* returns the second line of the two-line per-strip display
1391 back the mode where it shows what the VPot controls.
1394 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1395 /* do nothing - second line shows value of current subview parameter */
1397 } else if (_route) {
1398 pending_display[1] = vpot_mode_string();
1400 pending_display[1] = string();
1405 Strip::next_pot_mode ()
1407 vector<AutomationType>::iterator i;
1409 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1410 /* do not change vpot mode while in flipped mode */
1411 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1412 pending_display[1] = "Flip";
1413 block_vpot_mode_display_for (1000);
1418 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1425 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1429 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1433 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1434 if ((*i) == ac->parameter().type()) {
1439 /* move to the next mode in the list, or back to the start (which will
1440 also happen if the current mode is not in the current pot mode list)
1443 if (i != possible_pot_parameters.end()) {
1447 if (i == possible_pot_parameters.end()) {
1448 i = possible_pot_parameters.begin();
1451 set_vpot_parameter (*i);
1455 Strip::subview_mode_changed ()
1457 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1459 subview_connections.drop_connections ();
1461 switch (_surface->mcp().subview_mode()) {
1462 case MackieControlProtocol::None:
1463 set_vpot_parameter (_pan_mode);
1464 /* need to show strip name again */
1466 notify_metering_state_changed ();
1470 case MackieControlProtocol::EQ:
1474 /* leave it as it was */
1478 case MackieControlProtocol::Dynamics:
1482 /* leave it as it was */
1487 case MackieControlProtocol::Sends:
1489 setup_sends_vpot (r);
1491 /* leave it as it was */
1495 case MackieControlProtocol::TrackView:
1497 setup_trackview_vpot (r);
1499 /* leave it as it was */
1507 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1513 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1514 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1515 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1516 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1517 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1518 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1520 uint32_t pos = _surface->mcp().global_index (*this);
1522 /* we will control the pos-th available parameter, from the list in the
1523 * order shown above.
1526 vector<boost::shared_ptr<AutomationControl> > available;
1527 vector<AutomationType> params;
1529 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1530 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1531 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1532 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1533 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1534 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1536 if (pos >= available.size()) {
1537 /* this knob is not needed to control the available parameters */
1538 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1539 pending_display[0] = string();
1540 pending_display[1] = string();
1544 boost::shared_ptr<AutomationControl> pc;
1545 AutomationType param;
1547 pc = available[pos];
1548 param = params[pos];
1550 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1551 _vpot->set_control (pc);
1561 pot_id = r->comp_speed_name (mc->get_value());
1582 if (!pot_id.empty()) {
1583 pending_display[0] = pot_id;
1585 pending_display[0] = string();
1588 notify_dyn_change (param, true, false);
1592 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1594 uint32_t bands = r->eq_band_cnt ();
1597 /* should never get here */
1601 /* figure out how many params per band are available */
1603 boost::shared_ptr<AutomationControl> pc;
1604 uint32_t params_per_band = 0;
1606 if ((pc = r->eq_gain_controllable (0))) {
1607 params_per_band += 1;
1609 if ((pc = r->eq_freq_controllable (0))) {
1610 params_per_band += 1;
1612 if ((pc = r->eq_q_controllable (0))) {
1613 params_per_band += 1;
1615 if ((pc = r->eq_shape_controllable (0))) {
1616 params_per_band += 1;
1619 /* pick the one for this strip, based on its global position across
1625 const uint32_t total_band_parameters = bands * params_per_band;
1626 const uint32_t global_pos = _surface->mcp().global_index (*this);
1627 AutomationType param = NullAutomation;
1632 if (global_pos < total_band_parameters) {
1634 /* show a parameter for an EQ band */
1636 const uint32_t parameter = global_pos % params_per_band;
1637 eq_band = global_pos / params_per_band;
1638 band_name = r->eq_band_name (eq_band);
1640 switch (parameter) {
1642 pc = r->eq_gain_controllable (eq_band);
1646 pc = r->eq_freq_controllable (eq_band);
1647 param = EQFrequency;
1650 pc = r->eq_q_controllable (eq_band);
1654 pc = r->eq_shape_controllable (eq_band);
1661 /* show a non-band parameter (HPF or enable)
1664 uint32_t parameter = global_pos - total_band_parameters;
1666 switch (parameter) {
1667 case 0: /* first control after band parameters */
1668 pc = r->eq_hpf_controllable();
1671 case 1: /* second control after band parameters */
1672 pc = r->eq_enable_controllable();
1676 /* nothing to control */
1677 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1678 pending_display[0] = string();
1679 pending_display[1] = string();
1688 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1689 _vpot->set_control (pc);
1695 pot_id = band_name + "Gain";
1698 pot_id = band_name + "Freq";
1701 pot_id = band_name + " Q";
1704 pot_id = band_name + " Shp";
1716 if (!pot_id.empty()) {
1717 pending_display[0] = pot_id;
1719 pending_display[0] = string();
1722 notify_eq_change (param, eq_band, true);
1727 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1733 const uint32_t global_pos = _surface->mcp().global_index (*this);
1735 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1738 pending_display[0] = string();
1739 pending_display[1] = string();
1743 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1744 _vpot->set_control (pc);
1746 pending_display[0] = r->send_name (global_pos);
1748 notify_send_level_change (BusSendLevel, global_pos, true);
1752 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1758 const uint32_t global_pos = _surface->mcp().global_index (*this);
1760 if (global_pos >= 8) {
1761 pending_display[0] = string();
1762 pending_display[1] = string();
1766 boost::shared_ptr<AutomationControl> pc;
1767 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1770 switch (global_pos) {
1772 pc = r->trim_control ();
1774 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1775 pending_display[0] = "Trim";
1776 notify_trackview_change (TrimAutomation, global_pos, true);
1781 pc = track->monitoring_control();
1783 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1784 pending_display[0] = "Mon";
1785 notify_trackview_change (MonitoringAutomation, global_pos, true);
1790 pc = r->solo_isolate_control ();
1792 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1793 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1794 pending_display[0] = "S-Iso";
1798 pc = r->solo_safe_control ();
1800 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1801 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1802 pending_display[0] = "S-Safe";
1806 pc = r->phase_control();
1808 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1809 notify_trackview_change (PhaseAutomation, global_pos, true);
1810 pending_display[0] = "Phase";
1814 // pc = r->trim_control ();
1817 // pc = r->trim_control ();
1820 // pc = r->trim_control ();
1825 pending_display[0] = string();
1826 pending_display[1] = string();
1830 _vpot->set_control (pc);
1834 Strip::set_vpot_parameter (AutomationType p)
1836 if (!_route || (p == NullAutomation)) {
1837 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1838 pending_display[1] = string();
1842 boost::shared_ptr<AutomationControl> pan_control;
1844 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1846 reset_saved_values ();
1849 case PanAzimuthAutomation:
1850 pan_control = _route->pan_azimuth_control ();
1852 case PanWidthAutomation:
1853 pan_control = _route->pan_width_control ();
1855 case PanElevationAutomation:
1857 case PanFrontBackAutomation:
1859 case PanLFEAutomation:
1867 _vpot->set_control (pan_control);
1870 pending_display[1] = vpot_mode_string ();
1874 Strip::is_midi_track () const
1876 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1880 Strip::reset_saved_values ()
1882 _last_pan_azi_position_written = -1.0;
1883 _last_pan_width_position_written = -1.0;
1884 _last_gain_position_written = -1.0;
1885 _last_trim_position_written = -1.0;
1890 Strip::notify_metering_state_changed()
1892 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1896 if (!_route || !_meter) {
1900 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1901 bool metering_active = _surface->mcp().metering_active ();
1903 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1907 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1909 if (!transport_is_rolling || !metering_active) {
1910 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1911 notify_panner_azi_changed (true);
1914 _transport_is_rolling = transport_is_rolling;
1915 _metering_active = metering_active;