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 ();
188 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
193 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
194 _surface->number(), _index, _route->name()));
196 _solo->set_control (_route->solo_control());
197 _mute->set_control (_route->mute_control());
199 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
200 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
202 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
204 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control();
206 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
209 pan_control = _route->pan_width_control();
211 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
214 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
215 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
217 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
220 _recenable->set_control (trk->rec_enable_control());
221 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
224 // TODO this works when a currently-banked route is made inactive, but not
225 // when a route is activated which should be currently banked.
227 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
228 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
230 /* setup legal VPot modes for this route */
232 possible_pot_parameters.clear();
234 if (_route->pan_azimuth_control()) {
235 possible_pot_parameters.push_back (PanAzimuthAutomation);
237 if (_route->pan_width_control()) {
238 possible_pot_parameters.push_back (PanWidthAutomation);
240 if (_route->pan_elevation_control()) {
241 possible_pot_parameters.push_back (PanElevationAutomation);
243 if (_route->pan_frontback_control()) {
244 possible_pot_parameters.push_back (PanFrontBackAutomation);
246 if (_route->pan_lfe_control()) {
247 possible_pot_parameters.push_back (PanLFEAutomation);
250 _pan_mode = PanAzimuthAutomation;
252 if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
253 set_vpot_parameter (_pan_mode);
256 _fader->set_control (_route->gain_control());
268 // The active V-pot control may not be active for this strip
269 // But if we zero it in the controls function it may erase
270 // the one we do want
271 _surface->write (_vpot->zero());
273 notify_solo_changed ();
274 notify_mute_changed ();
275 notify_gain_changed ();
276 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
277 notify_panner_azi_changed ();
278 notify_panner_width_changed ();
279 notify_record_enable_changed ();
280 notify_processor_changed ();
284 Strip::notify_solo_changed ()
286 if (_route && _solo) {
287 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
292 Strip::notify_mute_changed ()
294 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
295 if (_route && _mute) {
296 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
297 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
299 _surface->write (_mute->set_state (_route->muted() ? on : off));
304 Strip::notify_record_enable_changed ()
306 if (_route && _recenable) {
307 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
312 Strip::notify_active_changed ()
314 _surface->mcp().refresh_current_bank();
318 Strip::notify_route_deleted ()
320 _surface->mcp().refresh_current_bank();
324 Strip::notify_gain_changed (bool force_update)
330 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
334 /* doesn't seem possible but lets be safe */
338 /* track gain control could be on vpot or fader, depending in
342 if (_vpot->control() == ac) {
344 } else if (_fader->control() == ac) {
350 float gain_coefficient = ac->get_value();
351 float normalized_position = ac->internal_to_interface (gain_coefficient);
353 if (force_update || normalized_position != _last_gain_position_written) {
355 if (!control->in_use()) {
356 if (control == _vpot) {
357 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
359 _surface->write (_fader->set_position (normalized_position));
363 do_parameter_display (GainAutomation, gain_coefficient);
364 _last_gain_position_written = normalized_position;
369 Strip::notify_processor_changed (bool force_update)
374 Strip::notify_property_changed (const PropertyChange& what_changed)
376 if (!what_changed.contains (ARDOUR::Properties::name)) {
384 Strip::show_route_name ()
386 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
388 if (svm != MackieControlProtocol::None) {
389 /* subview mode is responsible for upper line */
393 string fullname = string();
397 fullname = _route->name();
400 if (fullname.length() <= 6) {
401 pending_display[0] = fullname;
403 pending_display[0] = PBD::short_version (fullname, 6);
408 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
410 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
413 /* not in subview mode */
417 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
418 /* no longer in Sends subview mode */
422 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
428 float val = control->get_value();
429 do_parameter_display (type, val);
431 if (_vpot->control() == control) {
432 /* update pot/encoder */
433 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
439 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
441 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
444 /* not in subview mode */
448 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
449 /* no longer in TrackViewsubview mode */
453 boost::shared_ptr<AutomationControl> control;
454 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
458 control = r->trim_control();
460 case SoloIsolateAutomation:
461 control = r->solo_isolate_control ();
463 case SoloSafeAutomation:
464 control = r->solo_safe_control ();
466 case MonitoringAutomation:
468 control = track->monitoring_control();
471 case PhaseAutomation:
472 control = r->phase_control ();
479 float val = control->get_value();
481 /* Note: all of the displayed controllables require the display
482 * of their *actual* ("internal") value, not the version mapped
483 * into the normalized 0..1.0 ("interface") range.
486 do_parameter_display (type, val);
487 /* update pot/encoder */
488 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
493 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
495 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
498 /* not in subview mode */
502 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
503 /* no longer in EQ subview mode */
507 boost::shared_ptr<AutomationControl> control;
511 control = r->eq_gain_controllable (band);
514 control = r->eq_freq_controllable (band);
517 control = r->eq_q_controllable (band);
520 control = r->eq_shape_controllable (band);
523 control = r->eq_hpf_controllable ();
526 control = r->eq_enable_controllable ();
533 float val = control->get_value();
534 do_parameter_display (type, val);
535 /* update pot/encoder */
536 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
541 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
543 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
546 /* not in subview mode */
550 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
551 /* no longer in EQ subview mode */
555 boost::shared_ptr<AutomationControl> control;
556 bool reset_all = false;
560 control = r->comp_threshold_controllable ();
563 control = r->comp_speed_controllable ();
566 control = r->comp_mode_controllable ();
570 control = r->comp_makeup_controllable ();
573 control = r->comp_redux_controllable ();
576 control = r->comp_enable_controllable ();
582 if (propagate_mode && reset_all) {
583 _surface->subview_mode_changed ();
587 float val = control->get_value();
588 do_parameter_display (type, val);
589 /* update pot/encoder */
590 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
595 Strip::notify_panner_azi_changed (bool force_update)
601 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
603 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
606 /* basically impossible, since we're here because that control
607 * changed, but sure, whatever.
612 if (_vpot->control() != pan_control) {
616 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
617 double internal_pos = pan_control->get_value();
619 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
621 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
622 /* show actual internal value to user */
623 do_parameter_display (PanAzimuthAutomation, internal_pos);
625 _last_pan_azi_position_written = normalized_pos;
630 Strip::notify_panner_width_changed (bool force_update)
636 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
638 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
641 /* basically impossible, since we're here because that control
642 * changed, but sure, whatever.
647 if (_vpot->control() != pan_control) {
651 double pos = pan_control->internal_to_interface (pan_control->get_value());
653 if (force_update || pos != _last_pan_width_position_written) {
655 _surface->write (_vpot->set (pos, true, Pot::spread));
656 do_parameter_display (PanWidthAutomation, pos);
658 _last_pan_width_position_written = pos;
663 Strip::select_event (Button&, ButtonState bs)
665 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
669 int ms = _surface->mcp().main_modifier_state();
671 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
672 _controls_locked = !_controls_locked;
673 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
674 block_vpot_mode_display_for (1000);
678 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
679 _surface->mcp().add_down_select_button (_surface->number(), _index);
680 _surface->mcp().select_range ();
683 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
684 _surface->mcp().remove_down_select_button (_surface->number(), _index);
689 Strip::vselect_event (Button&, ButtonState bs)
691 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
693 /* most subview modes: vpot press acts like a button for toggle parameters */
699 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
701 boost::shared_ptr<AutomationControl> control = _vpot->control ();
706 Controllable::GroupControlDisposition gcd;
707 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
708 gcd = Controllable::InverseGroup;
710 gcd = Controllable::UseGroup;
713 if (control->toggled()) {
714 if (control->toggled()) {
715 control->set_value (!control->get_value(), gcd);
718 } else if (control->desc().enumeration || control->desc().integer_step) {
720 double val = control->get_value ();
721 if (val <= control->upper() - 1.0) {
722 control->set_value (val + 1.0, gcd);
724 control->set_value (control->lower(), gcd);
730 /* Send mode: press enables/disables the relevant
731 * send, but the vpot is bound to the send-level so we
732 * need to lookup the enable/disable control
736 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
740 const uint32_t global_pos = _surface->mcp().global_index (*this);
741 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
744 bool currently_enabled = (bool) control->get_value();
745 Controllable::GroupControlDisposition gcd;
747 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
748 gcd = Controllable::InverseGroup;
750 gcd = Controllable::UseGroup;
753 control->set_value (!currently_enabled, gcd);
755 if (currently_enabled) {
756 /* we just turned it off */
757 pending_display[1] = "off";
759 /* we just turned it on, show the level
761 control = _route->send_level_controllable (global_pos);
762 do_parameter_display (BusSendLevel, control->get_value());
768 /* done with this event in subview mode */
775 int ms = _surface->mcp().main_modifier_state();
777 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
779 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
783 /* reset to default/normal value */
784 ac->set_value (ac->normal(), Controllable::NoGroup);
791 boost::shared_ptr<AutomationControl> ac = _route->master_send_enable_controllable ();
793 Controllable::GroupControlDisposition gcd;
795 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
796 gcd = Controllable::InverseGroup;
798 gcd = Controllable::UseGroup;
801 bool enabled = ac->get_value();
802 ac->set_value (!enabled, gcd);
806 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
807 /* switch vpot to control next available parameter */
816 Strip::fader_touch_event (Button&, ButtonState bs)
818 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
822 boost::shared_ptr<AutomationControl> ac = _fader->control ();
824 _fader->set_in_use (true);
825 _fader->start_touch (_surface->mcp().transport_frame());
828 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
833 _fader->set_in_use (false);
834 _fader->stop_touch (_surface->mcp().transport_frame(), true);
841 Strip::handle_button (Button& button, ButtonState bs)
843 boost::shared_ptr<AutomationControl> control;
846 button.set_in_use (true);
848 button.set_in_use (false);
851 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
853 switch (button.bid()) {
855 select_event (button, bs);
858 case Button::VSelect:
859 vselect_event (button, bs);
862 case Button::FaderTouch:
863 fader_touch_event (button, bs);
867 if ((control = button.control ())) {
869 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
870 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
872 float new_value = control->get_value() ? 0.0 : 1.0;
874 /* get all controls that either have their
875 * button down or are within a range of
876 * several down buttons
879 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
882 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
883 controls.size(), control->parameter().type(), new_value));
885 /* apply change, with potential modifier semantics */
887 Controllable::GroupControlDisposition gcd;
889 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
890 gcd = Controllable::InverseGroup;
892 gcd = Controllable::UseGroup;
895 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
896 (*c)->set_value (new_value, gcd);
900 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
901 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
909 Strip::do_parameter_display (AutomationType type, float val)
911 bool screen_hold = false;
917 pending_display[1] = " -inf ";
919 float dB = accurate_coefficient_to_dB (val);
920 snprintf (buf, sizeof (buf), "%6.1f", dB);
921 pending_display[1] = buf;
927 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
928 snprintf (buf, sizeof (buf), "%2.1f", val);
929 pending_display[1] = buf;
933 pending_display[1] = " -inf ";
935 float dB = accurate_coefficient_to_dB (val);
936 snprintf (buf, sizeof (buf), "%6.1f", dB);
937 pending_display[1] = buf;
943 case PanAzimuthAutomation:
944 if (Profile->get_mixbus()) {
945 snprintf (buf, sizeof (buf), "%2.1f", val);
946 pending_display[1] = buf;
950 boost::shared_ptr<Pannable> p = _route->pannable();
951 if (p && _route->panner()) {
952 pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
959 case PanWidthAutomation:
961 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
962 pending_display[1] = buf;
969 float dB = accurate_coefficient_to_dB (val);
970 snprintf (buf, sizeof (buf), "%6.1f", dB);
971 pending_display[1] = buf;
976 case PhaseAutomation:
979 pending_display[1] = "Normal";
981 pending_display[1] = "Invert";
996 snprintf (buf, sizeof (buf), "%6.1f", val);
997 pending_display[1] = buf;
1003 pending_display[1] = "on";
1005 pending_display[1] = "off";
1009 if (_surface->mcp().subview_route()) {
1010 pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1013 case SoloSafeAutomation:
1014 case SoloIsolateAutomation:
1016 pending_display[1] = "on";
1018 pending_display[1] = "off";
1021 case MonitoringAutomation:
1022 switch (MonitorChoice ((int) val)) {
1024 pending_display[1] = "auto";
1027 pending_display[1] = "input";
1030 pending_display[1] = "disk";
1032 case MonitorCue: /* XXX not implemented as of jan 2016 */
1033 pending_display[1] = "cue";
1042 /* we just queued up a parameter to be displayed.
1043 1 second from now, switch back to vpot mode display.
1045 block_vpot_mode_display_for (1000);
1050 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1053 fader.start_touch (_surface->mcp().transport_frame());
1055 fader.stop_touch (_surface->mcp().transport_frame(), false);
1060 Strip::handle_fader (Fader& fader, float position)
1062 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1063 boost::shared_ptr<AutomationControl> ac = fader.control();
1068 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1070 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1071 gcd = Controllable::InverseGroup;
1074 fader.set_value (position, gcd);
1076 /* From the Mackie Control MIDI implementation docs:
1078 In order to ensure absolute synchronization with the host software,
1079 Mackie Control uses a closed-loop servo system for the faders,
1080 meaning the faders will always move to their last received position.
1081 When a host receives a Fader Position Message, it must then
1082 re-transmit that message to the Mackie Control or else the faders
1083 will return to their last position.
1086 _surface->write (fader.set_position (position));
1090 Strip::handle_pot (Pot& pot, float delta)
1092 /* Pots only emit events when they move, not when they
1093 stop moving. So to get a stop event, we need to use a timeout.
1096 boost::shared_ptr<AutomationControl> ac = pot.control();
1101 Controllable::GroupControlDisposition gcd;
1103 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1104 gcd = Controllable::InverseGroup;
1106 gcd = Controllable::UseGroup;
1109 if (ac->toggled()) {
1111 /* make it like a single-step, directional switch */
1114 ac->set_value (1.0, gcd);
1116 ac->set_value (0.0, gcd);
1119 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1121 /* use Controllable::get_value() to avoid the
1122 * "scaling-to-interface" that takes place in
1123 * Control::get_value() via the pot member.
1125 * an enumeration with 4 values will have interface values of
1126 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1131 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1133 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1138 double p = ac->get_interface();
1145 ac->set_value ( ac->interface_to_internal(p), gcd);
1150 Strip::periodic (ARDOUR::microseconds_t now)
1153 update_automation ();
1157 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1159 if (_block_screen_redisplay_until >= now) {
1160 /* no drawing allowed */
1164 if (_block_screen_redisplay_until) {
1165 /* we were blocked, but the time period has elapsed, so we must
1169 _block_screen_redisplay_until = 0;
1172 if (force || (current_display[0] != pending_display[0])) {
1173 _surface->write (display (0, pending_display[0]));
1174 current_display[0] = pending_display[0];
1177 if (return_to_vpot_mode_display_at <= now) {
1178 return_to_vpot_mode_display_at = UINT64_MAX;
1179 return_to_vpot_mode_display ();
1182 if (force || (current_display[1] != pending_display[1])) {
1183 _surface->write (display (1, pending_display[1]));
1184 current_display[1] = pending_display[1];
1189 Strip::update_automation ()
1195 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1197 if (state == Touch || state == Play) {
1198 notify_gain_changed (false);
1201 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1203 state = pan_control->automation_state ();
1204 if (state == Touch || state == Play) {
1205 notify_panner_azi_changed (false);
1209 pan_control = _route->pan_width_control ();
1211 state = pan_control->automation_state ();
1212 if (state == Touch || state == Play) {
1213 notify_panner_width_changed (false);
1219 Strip::update_meter ()
1225 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1229 if (_meter && _transport_is_rolling && _metering_active) {
1230 float dB = _route->peak_meter()->meter_level (0, MeterMCP);
1231 _meter->send_update (*_surface, dB);
1239 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1240 _surface->write ((*it)->zero ());
1243 _surface->write (blank_display (0));
1244 _surface->write (blank_display (1));
1245 pending_display[0] = string();
1246 pending_display[1] = string();
1247 current_display[0] = string();
1248 current_display[1] = string();
1252 Strip::blank_display (uint32_t line_number)
1254 return display (line_number, string());
1258 Strip::display (uint32_t line_number, const std::string& line)
1260 assert (line_number <= 1);
1262 MidiByteArray retval;
1264 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1267 retval << _surface->sysex_hdr();
1271 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1272 retval << (_index * 7 + (line_number * 0x38));
1274 // ascii data to display. @param line is UTF-8
1275 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1276 string::size_type len = ascii.length();
1278 ascii = ascii.substr (0, 6);
1282 // pad with " " out to 6 chars
1283 for (int i = len; i < 6; ++i) {
1287 // column spacer, unless it's the right-hand column
1293 retval << MIDI::eox;
1299 Strip::lock_controls ()
1301 _controls_locked = true;
1305 Strip::unlock_controls ()
1307 _controls_locked = false;
1311 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1313 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1314 if ((*i) == _route) {
1315 _surface->write (_select->set_state (on));
1320 _surface->write (_select->set_state (off));
1324 Strip::vpot_mode_string ()
1326 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1330 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1336 switch (ac->desc().type) {
1337 case PanAzimuthAutomation:
1339 case PanWidthAutomation:
1341 case PanElevationAutomation:
1343 case PanFrontBackAutomation:
1345 case PanLFEAutomation:
1355 Strip::flip_mode_changed ()
1357 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1359 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1360 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1362 if (pot_control && fader_control) {
1363 _vpot->set_control (fader_control);
1364 _fader->set_control (pot_control);
1367 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1368 do_parameter_display (GainAutomation, fader_control->get_value());
1370 do_parameter_display (BusSendLevel, fader_control->get_value());
1375 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1379 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1388 Strip::block_screen_display_for (uint32_t msecs)
1390 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1394 Strip::block_vpot_mode_display_for (uint32_t msecs)
1396 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1400 Strip::return_to_vpot_mode_display ()
1402 /* returns the second line of the two-line per-strip display
1403 back the mode where it shows what the VPot controls.
1406 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1407 /* do nothing - second line shows value of current subview parameter */
1409 } else if (_route) {
1410 pending_display[1] = vpot_mode_string();
1412 pending_display[1] = string();
1417 Strip::next_pot_mode ()
1419 vector<AutomationType>::iterator i;
1421 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1422 /* do not change vpot mode while in flipped mode */
1423 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1424 pending_display[1] = "Flip";
1425 block_vpot_mode_display_for (1000);
1430 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1437 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1441 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1445 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1446 if ((*i) == ac->parameter().type()) {
1451 /* move to the next mode in the list, or back to the start (which will
1452 also happen if the current mode is not in the current pot mode list)
1455 if (i != possible_pot_parameters.end()) {
1459 if (i == possible_pot_parameters.end()) {
1460 i = possible_pot_parameters.begin();
1463 set_vpot_parameter (*i);
1467 Strip::subview_mode_changed ()
1469 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1471 subview_connections.drop_connections ();
1473 switch (_surface->mcp().subview_mode()) {
1474 case MackieControlProtocol::None:
1475 set_vpot_parameter (_pan_mode);
1476 /* need to show strip name again */
1479 _surface->write (_vpot->set (0, true, Pot::wrap));
1480 _surface->write (_fader->set_position (0.0));
1482 notify_metering_state_changed ();
1486 case MackieControlProtocol::EQ:
1490 /* leave it as it was */
1494 case MackieControlProtocol::Dynamics:
1498 /* leave it as it was */
1503 case MackieControlProtocol::Sends:
1505 setup_sends_vpot (r);
1507 /* leave it as it was */
1511 case MackieControlProtocol::TrackView:
1513 setup_trackview_vpot (r);
1515 /* leave it as it was */
1523 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1529 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1530 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1531 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1532 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1533 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1534 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1536 uint32_t pos = _surface->mcp().global_index (*this);
1538 /* we will control the pos-th available parameter, from the list in the
1539 * order shown above.
1542 vector<boost::shared_ptr<AutomationControl> > available;
1543 vector<AutomationType> params;
1545 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1546 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1547 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1548 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1549 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1550 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1552 if (pos >= available.size()) {
1553 /* this knob is not needed to control the available parameters */
1554 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1555 pending_display[0] = string();
1556 pending_display[1] = string();
1560 boost::shared_ptr<AutomationControl> pc;
1561 AutomationType param;
1563 pc = available[pos];
1564 param = params[pos];
1566 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1567 _vpot->set_control (pc);
1577 pot_id = r->comp_speed_name (mc->get_value());
1598 if (!pot_id.empty()) {
1599 pending_display[0] = pot_id;
1601 pending_display[0] = string();
1604 notify_dyn_change (param, true, false);
1608 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1610 uint32_t bands = r->eq_band_cnt ();
1613 /* should never get here */
1617 /* figure out how many params per band are available */
1619 boost::shared_ptr<AutomationControl> pc;
1620 uint32_t params_per_band = 0;
1622 if ((pc = r->eq_gain_controllable (0))) {
1623 params_per_band += 1;
1625 if ((pc = r->eq_freq_controllable (0))) {
1626 params_per_band += 1;
1628 if ((pc = r->eq_q_controllable (0))) {
1629 params_per_band += 1;
1631 if ((pc = r->eq_shape_controllable (0))) {
1632 params_per_band += 1;
1635 /* pick the one for this strip, based on its global position across
1641 const uint32_t total_band_parameters = bands * params_per_band;
1642 const uint32_t global_pos = _surface->mcp().global_index (*this);
1643 AutomationType param = NullAutomation;
1648 if (global_pos < total_band_parameters) {
1650 /* show a parameter for an EQ band */
1652 const uint32_t parameter = global_pos % params_per_band;
1653 eq_band = global_pos / params_per_band;
1654 band_name = r->eq_band_name (eq_band);
1656 switch (parameter) {
1658 pc = r->eq_gain_controllable (eq_band);
1662 pc = r->eq_freq_controllable (eq_band);
1663 param = EQFrequency;
1666 pc = r->eq_q_controllable (eq_band);
1670 pc = r->eq_shape_controllable (eq_band);
1677 /* show a non-band parameter (HPF or enable)
1680 uint32_t parameter = global_pos - total_band_parameters;
1682 switch (parameter) {
1683 case 0: /* first control after band parameters */
1684 pc = r->eq_hpf_controllable();
1687 case 1: /* second control after band parameters */
1688 pc = r->eq_enable_controllable();
1692 /* nothing to control */
1693 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1694 pending_display[0] = string();
1695 pending_display[1] = string();
1704 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1705 _vpot->set_control (pc);
1711 pot_id = band_name + "Gain";
1714 pot_id = band_name + "Freq";
1717 pot_id = band_name + " Q";
1720 pot_id = band_name + " Shp";
1732 if (!pot_id.empty()) {
1733 pending_display[0] = pot_id;
1735 pending_display[0] = string();
1738 notify_eq_change (param, eq_band, true);
1743 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1749 const uint32_t global_pos = _surface->mcp().global_index (*this);
1751 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1754 pending_display[0] = string();
1755 pending_display[1] = string();
1759 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1760 _vpot->set_control (pc);
1762 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1764 notify_send_level_change (BusSendLevel, global_pos, true);
1768 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1774 const uint32_t global_pos = _surface->mcp().global_index (*this);
1776 if (global_pos >= 8) {
1777 pending_display[0] = string();
1778 pending_display[1] = string();
1782 boost::shared_ptr<AutomationControl> pc;
1783 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1786 switch (global_pos) {
1788 pc = r->trim_control ();
1790 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1791 pending_display[0] = "Trim";
1792 notify_trackview_change (TrimAutomation, global_pos, true);
1797 pc = track->monitoring_control();
1799 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1800 pending_display[0] = "Mon";
1801 notify_trackview_change (MonitoringAutomation, global_pos, true);
1806 pc = r->solo_isolate_control ();
1808 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1809 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1810 pending_display[0] = "S-Iso";
1814 pc = r->solo_safe_control ();
1816 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1817 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1818 pending_display[0] = "S-Safe";
1822 pc = r->phase_control();
1824 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1825 notify_trackview_change (PhaseAutomation, global_pos, true);
1826 pending_display[0] = "Phase";
1830 // pc = r->trim_control ();
1833 // pc = r->trim_control ();
1836 // pc = r->trim_control ();
1841 pending_display[0] = string();
1842 pending_display[1] = string();
1846 _vpot->set_control (pc);
1850 Strip::set_vpot_parameter (AutomationType p)
1852 if (!_route || (p == NullAutomation)) {
1853 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1854 pending_display[1] = string();
1858 boost::shared_ptr<AutomationControl> pan_control;
1860 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1862 reset_saved_values ();
1865 case PanAzimuthAutomation:
1866 pan_control = _route->pan_azimuth_control ();
1868 case PanWidthAutomation:
1869 pan_control = _route->pan_width_control ();
1871 case PanElevationAutomation:
1873 case PanFrontBackAutomation:
1875 case PanLFEAutomation:
1883 _vpot->set_control (pan_control);
1886 pending_display[1] = vpot_mode_string ();
1890 Strip::is_midi_track () const
1892 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1896 Strip::reset_saved_values ()
1898 _last_pan_azi_position_written = -1.0;
1899 _last_pan_width_position_written = -1.0;
1900 _last_gain_position_written = -1.0;
1901 _last_trim_position_written = -1.0;
1906 Strip::notify_metering_state_changed()
1908 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1912 if (!_route || !_meter) {
1916 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1917 bool metering_active = _surface->mcp().metering_active ();
1919 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1923 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1925 if (!transport_is_rolling || !metering_active) {
1926 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1927 notify_panner_azi_changed (true);
1930 _transport_is_rolling = transport_is_rolling;
1931 _metering_active = metering_active;