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/monitor_control.h"
41 #include "ardour/plugin_insert.h"
42 #include "ardour/pannable.h"
43 #include "ardour/panner.h"
44 #include "ardour/panner_shell.h"
45 #include "ardour/phase_control.h"
46 #include "ardour/rc_configuration.h"
47 #include "ardour/record_enable_control.h"
48 #include "ardour/route.h"
49 #include "ardour/session.h"
50 #include "ardour/send.h"
51 #include "ardour/solo_isolate_control.h"
52 #include "ardour/track.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/user_bundle.h"
55 #include "ardour/profile.h"
57 #include "mackie_control_protocol.h"
58 #include "surface_port.h"
69 using namespace ARDOUR;
71 using namespace ArdourSurface;
72 using namespace Mackie;
74 #ifndef timeradd /// only avail with __USE_BSD
75 #define timeradd(a,b,result) \
77 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
78 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
79 if ((result)->tv_usec >= 1000000) \
82 (result)->tv_usec -= 1000000; \
87 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
89 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
102 , _controls_locked (false)
103 , _transport_is_rolling (false)
104 , _metering_active (true)
105 , _block_screen_redisplay_until (0)
106 , return_to_vpot_mode_display_at (UINT64_MAX)
108 , _pan_mode (PanAzimuthAutomation)
109 , _last_gain_position_written (-1.0)
110 , _last_pan_azi_position_written (-1.0)
111 , _last_pan_width_position_written (-1.0)
112 , _last_trim_position_written (-1.0)
114 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
115 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
117 if (s.mcp().device_info().has_meters()) {
118 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
121 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
122 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
123 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
124 _surface->number(), index, Button::id_to_name (bb->bid()),
125 bb->id(), b->second.base_id));
131 /* surface is responsible for deleting all controls */
135 Strip::add (Control & control)
139 Group::add (control);
141 /* fader, vpot, meter were all set explicitly */
143 if ((button = dynamic_cast<Button*>(&control)) != 0) {
144 switch (button->bid()) {
145 case Button::RecEnable:
157 case Button::VSelect:
160 case Button::FaderTouch:
161 _fader_touch = button;
170 Strip::set_stripable (boost::shared_ptr<Stripable> r, bool /*with_messages*/)
172 if (_controls_locked) {
176 mb_pan_controllable.reset();
178 stripable_connections.drop_connections ();
180 _solo->set_control (boost::shared_ptr<AutomationControl>());
181 _mute->set_control (boost::shared_ptr<AutomationControl>());
182 _select->set_control (boost::shared_ptr<AutomationControl>());
183 _recenable->set_control (boost::shared_ptr<AutomationControl>());
184 _fader->set_control (boost::shared_ptr<AutomationControl>());
185 _vpot->set_control (boost::shared_ptr<AutomationControl>());
189 reset_saved_values ();
192 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
197 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping stripable %3\n",
198 _surface->number(), _index, _stripable->name()));
200 _solo->set_control (_stripable->solo_control());
201 _mute->set_control (_stripable->mute_control());
203 _stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
204 _stripable->mute_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
206 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control();
208 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
211 pan_control = _stripable->pan_width_control();
213 pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
216 _stripable->gain_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
217 _stripable->PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
218 _stripable->presentation_info().PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
220 boost::shared_ptr<AutomationControl> rec_enable_control = _stripable->rec_enable_control ();
222 if (rec_enable_control) {
223 _recenable->set_control (rec_enable_control);
224 rec_enable_control->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
227 // TODO this works when a currently-banked stripable is made inactive, but not
228 // when a stripable is activated which should be currently banked.
230 _stripable->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_stripable_deleted, this), ui_context());
232 /* setup legal VPot modes for this stripable */
234 possible_pot_parameters.clear();
236 if (_stripable->pan_azimuth_control()) {
237 possible_pot_parameters.push_back (PanAzimuthAutomation);
239 if (_stripable->pan_width_control()) {
240 possible_pot_parameters.push_back (PanWidthAutomation);
242 if (_stripable->pan_elevation_control()) {
243 possible_pot_parameters.push_back (PanElevationAutomation);
245 if (_stripable->pan_frontback_control()) {
246 possible_pot_parameters.push_back (PanFrontBackAutomation);
248 if (_stripable->pan_lfe_control()) {
249 possible_pot_parameters.push_back (PanLFEAutomation);
252 _pan_mode = PanAzimuthAutomation;
254 if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
255 set_vpot_parameter (_pan_mode);
258 _fader->set_control (_stripable->gain_control());
270 // The active V-pot control may not be active for this strip
271 // But if we zero it in the controls function it may erase
272 // the one we do want
273 _surface->write (_vpot->zero());
275 notify_solo_changed ();
276 notify_mute_changed ();
277 notify_gain_changed ();
278 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
279 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::selected));
280 notify_panner_azi_changed ();
281 notify_panner_width_changed ();
282 notify_record_enable_changed ();
283 notify_processor_changed ();
287 Strip::notify_solo_changed ()
289 if (_stripable && _solo) {
290 _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
295 Strip::notify_mute_changed ()
297 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
298 if (_stripable && _mute) {
299 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\tstripable muted ? %1\n", _stripable->mute_control()->muted()));
300 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_stripable->mute_control()->muted() ? on : off)));
302 _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
307 Strip::notify_record_enable_changed ()
309 if (_stripable && _recenable) {
310 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (_stripable);
312 _surface->write (_recenable->set_state (trk->rec_enable_control()->get_value() ? on : off));
318 Strip::notify_stripable_deleted ()
320 _surface->mcp().notify_stripable_removed ();
321 _surface->mcp().refresh_current_bank();
325 Strip::notify_gain_changed (bool force_update)
331 boost::shared_ptr<AutomationControl> ac = _stripable->gain_control();
335 /* doesn't seem possible but lets be safe */
339 /* track gain control could be on vpot or fader, depending in
343 if (_vpot->control() == ac) {
345 } else if (_fader->control() == ac) {
351 float gain_coefficient = ac->get_value();
352 float normalized_position = ac->internal_to_interface (gain_coefficient);
354 if (force_update || normalized_position != _last_gain_position_written) {
356 if (!control->in_use()) {
357 if (control == _vpot) {
358 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
360 _surface->write (_fader->set_position (normalized_position));
364 do_parameter_display (GainAutomation, gain_coefficient);
365 _last_gain_position_written = normalized_position;
370 Strip::notify_processor_changed (bool force_update)
375 Strip::notify_property_changed (const PropertyChange& what_changed)
377 if (what_changed.contains (ARDOUR::Properties::name)) {
378 show_stripable_name ();
381 if (what_changed.contains (ARDOUR::Properties::selected)) {
383 _surface->write (_select->set_state (_stripable->is_selected()));
384 _surface->mcp().update_selected (_stripable, _stripable->is_selected());
390 Strip::show_stripable_name ()
392 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
394 if (svm != MackieControlProtocol::None) {
395 /* subview mode is responsible for upper line */
399 string fullname = string();
403 fullname = _stripable->name();
406 if (fullname.length() <= 6) {
407 pending_display[0] = fullname;
409 pending_display[0] = PBD::short_version (fullname, 6);
414 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
416 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
419 /* not in subview mode */
423 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
424 /* no longer in Sends subview mode */
428 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
434 float val = control->get_value();
435 do_parameter_display (type, val);
437 if (_vpot->control() == control) {
438 /* update pot/encoder */
439 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
445 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
447 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
450 /* not in subview mode */
454 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
455 /* no longer in TrackViewsubview mode */
459 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();
487 /* Note: all of the displayed controllables require the display
488 * of their *actual* ("internal") value, not the version mapped
489 * into the normalized 0..1.0 ("interface") range.
492 do_parameter_display (type, val);
493 /* update pot/encoder */
494 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
499 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
501 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
504 /* not in subview mode */
508 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
509 /* no longer in EQ subview mode */
513 boost::shared_ptr<AutomationControl> control;
517 control = r->eq_gain_controllable (band);
520 control = r->eq_freq_controllable (band);
523 control = r->eq_q_controllable (band);
526 control = r->eq_shape_controllable (band);
529 control = r->eq_hpf_controllable ();
532 control = r->eq_enable_controllable ();
539 float val = control->get_value();
540 do_parameter_display (type, val);
541 /* update pot/encoder */
542 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
547 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
549 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
552 /* not in subview mode */
556 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
557 /* no longer in EQ subview mode */
561 boost::shared_ptr<AutomationControl> control;
562 bool reset_all = false;
566 control = r->comp_threshold_controllable ();
569 control = r->comp_speed_controllable ();
572 control = r->comp_mode_controllable ();
576 control = r->comp_makeup_controllable ();
579 control = r->comp_enable_controllable ();
585 if (propagate_mode && reset_all) {
586 _surface->subview_mode_changed ();
590 float val = control->get_value();
591 do_parameter_display (type, val);
592 /* update pot/encoder */
593 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
598 Strip::notify_panner_azi_changed (bool force_update)
604 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
606 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
609 /* basically impossible, since we're here because that control
610 * changed, but sure, whatever.
615 if (_vpot->control() != pan_control) {
619 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
620 double internal_pos = pan_control->get_value();
622 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
624 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
625 /* show actual internal value to user */
626 do_parameter_display (PanAzimuthAutomation, internal_pos);
628 _last_pan_azi_position_written = normalized_pos;
633 Strip::notify_panner_width_changed (bool force_update)
639 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
641 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_width_control ();
644 /* basically impossible, since we're here because that control
645 * changed, but sure, whatever.
650 if (_vpot->control() != pan_control) {
654 double pos = pan_control->internal_to_interface (pan_control->get_value());
656 if (force_update || pos != _last_pan_width_position_written) {
658 _surface->write (_vpot->set (pos, true, Pot::spread));
659 do_parameter_display (PanWidthAutomation, pos);
661 _last_pan_width_position_written = pos;
666 Strip::select_event (Button&, ButtonState bs)
668 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
672 int ms = _surface->mcp().main_modifier_state();
674 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
675 _controls_locked = !_controls_locked;
676 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
677 block_vpot_mode_display_for (1000);
681 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
682 _surface->mcp().add_down_select_button (_surface->number(), _index);
683 _surface->mcp().select_range (_surface->mcp().global_index (*this));
686 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
687 _surface->mcp().remove_down_select_button (_surface->number(), _index);
692 Strip::vselect_event (Button&, ButtonState bs)
694 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
696 /* most subview modes: vpot press acts like a button for toggle parameters */
702 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
704 boost::shared_ptr<AutomationControl> control = _vpot->control ();
709 Controllable::GroupControlDisposition gcd;
710 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
711 gcd = Controllable::InverseGroup;
713 gcd = Controllable::UseGroup;
716 if (control->toggled()) {
717 if (control->toggled()) {
718 control->set_value (!control->get_value(), gcd);
721 } else if (control->desc().enumeration || control->desc().integer_step) {
723 double val = control->get_value ();
724 if (val <= control->upper() - 1.0) {
725 control->set_value (val + 1.0, gcd);
727 control->set_value (control->lower(), gcd);
733 /* Send mode: press enables/disables the relevant
734 * send, but the vpot is bound to the send-level so we
735 * need to lookup the enable/disable control
739 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
743 const uint32_t global_pos = _surface->mcp().global_index (*this);
744 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
747 bool currently_enabled = (bool) control->get_value();
748 Controllable::GroupControlDisposition gcd;
750 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
751 gcd = Controllable::InverseGroup;
753 gcd = Controllable::UseGroup;
756 control->set_value (!currently_enabled, gcd);
758 if (currently_enabled) {
759 /* we just turned it off */
760 pending_display[1] = "off";
762 /* we just turned it on, show the level
764 control = _stripable->send_level_controllable (global_pos);
765 do_parameter_display (BusSendLevel, control->get_value());
771 /* done with this event in subview mode */
778 int ms = _surface->mcp().main_modifier_state();
780 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
782 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
786 /* reset to default/normal value */
787 ac->set_value (ac->normal(), Controllable::NoGroup);
794 boost::shared_ptr<AutomationControl> ac = _stripable->master_send_enable_controllable ();
796 Controllable::GroupControlDisposition gcd;
798 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
799 gcd = Controllable::InverseGroup;
801 gcd = Controllable::UseGroup;
804 bool enabled = ac->get_value();
805 ac->set_value (!enabled, gcd);
809 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
810 /* switch vpot to control next available parameter */
819 Strip::fader_touch_event (Button&, ButtonState bs)
821 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
825 boost::shared_ptr<AutomationControl> ac = _fader->control ();
827 _fader->set_in_use (true);
828 _fader->start_touch (_surface->mcp().transport_frame());
831 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
836 _fader->set_in_use (false);
837 _fader->stop_touch (_surface->mcp().transport_frame(), true);
844 Strip::handle_button (Button& button, ButtonState bs)
846 boost::shared_ptr<AutomationControl> control;
849 button.set_in_use (true);
851 button.set_in_use (false);
854 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
856 switch (button.bid()) {
858 select_event (button, bs);
861 case Button::VSelect:
862 vselect_event (button, bs);
865 case Button::FaderTouch:
866 fader_touch_event (button, bs);
870 if ((control = button.control ())) {
872 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
873 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
875 float new_value = control->get_value() ? 0.0 : 1.0;
877 /* get all controls that either have their
878 * button down or are within a range of
879 * several down buttons
882 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type(),
883 _surface->mcp().global_index(*this));
886 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
887 controls.size(), control->parameter().type(), new_value));
889 /* apply change, with potential modifier semantics */
891 Controllable::GroupControlDisposition gcd;
893 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
894 gcd = Controllable::InverseGroup;
896 gcd = Controllable::UseGroup;
899 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
900 (*c)->set_value (new_value, gcd);
904 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
905 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
913 Strip::do_parameter_display (AutomationType type, float val)
915 bool screen_hold = false;
921 pending_display[1] = " -inf ";
923 float dB = accurate_coefficient_to_dB (val);
924 snprintf (buf, sizeof (buf), "%6.1f", dB);
925 pending_display[1] = buf;
931 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
932 snprintf (buf, sizeof (buf), "%2.1f", val);
933 pending_display[1] = buf;
937 pending_display[1] = " -inf ";
939 float dB = accurate_coefficient_to_dB (val);
940 snprintf (buf, sizeof (buf), "%6.1f", dB);
941 pending_display[1] = buf;
947 case PanAzimuthAutomation:
948 if (Profile->get_mixbus()) {
949 snprintf (buf, sizeof (buf), "%2.1f", val);
950 pending_display[1] = buf;
954 boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
956 pending_display[1] = pa->get_user_string ();
963 case PanWidthAutomation:
965 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
966 pending_display[1] = buf;
973 float dB = accurate_coefficient_to_dB (val);
974 snprintf (buf, sizeof (buf), "%6.1f", dB);
975 pending_display[1] = buf;
980 case PhaseAutomation:
983 pending_display[1] = "Normal";
985 pending_display[1] = "Invert";
1000 snprintf (buf, sizeof (buf), "%6.1f", val);
1001 pending_display[1] = buf;
1007 pending_display[1] = "on";
1009 pending_display[1] = "off";
1013 if (_surface->mcp().subview_stripable()) {
1014 pending_display[1] = _surface->mcp().subview_stripable()->comp_mode_name (val);
1017 case SoloSafeAutomation:
1018 case SoloIsolateAutomation:
1020 pending_display[1] = "on";
1022 pending_display[1] = "off";
1025 case MonitoringAutomation:
1026 switch (MonitorChoice ((int) val)) {
1028 pending_display[1] = "auto";
1031 pending_display[1] = "input";
1034 pending_display[1] = "disk";
1036 case MonitorCue: /* XXX not implemented as of jan 2016 */
1037 pending_display[1] = "cue";
1046 /* we just queued up a parameter to be displayed.
1047 1 second from now, switch back to vpot mode display.
1049 block_vpot_mode_display_for (1000);
1054 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1057 fader.start_touch (_surface->mcp().transport_frame());
1059 fader.stop_touch (_surface->mcp().transport_frame(), false);
1064 Strip::handle_fader (Fader& fader, float position)
1066 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1067 boost::shared_ptr<AutomationControl> ac = fader.control();
1072 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1074 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1075 gcd = Controllable::InverseGroup;
1078 fader.set_value (position, gcd);
1080 /* From the Mackie Control MIDI implementation docs:
1082 In order to ensure absolute synchronization with the host software,
1083 Mackie Control uses a closed-loop servo system for the faders,
1084 meaning the faders will always move to their last received position.
1085 When a host receives a Fader Position Message, it must then
1086 re-transmit that message to the Mackie Control or else the faders
1087 will return to their last position.
1090 _surface->write (fader.set_position (position));
1094 Strip::handle_pot (Pot& pot, float delta)
1096 /* Pots only emit events when they move, not when they
1097 stop moving. So to get a stop event, we need to use a timeout.
1100 boost::shared_ptr<AutomationControl> ac = pot.control();
1105 Controllable::GroupControlDisposition gcd;
1107 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1108 gcd = Controllable::InverseGroup;
1110 gcd = Controllable::UseGroup;
1113 if (ac->toggled()) {
1115 /* make it like a single-step, directional switch */
1118 ac->set_value (1.0, gcd);
1120 ac->set_value (0.0, gcd);
1123 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1125 /* use Controllable::get_value() to avoid the
1126 * "scaling-to-interface" that takes place in
1127 * Control::get_value() via the pot member.
1129 * an enumeration with 4 values will have interface values of
1130 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1135 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1137 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1142 double p = ac->get_interface();
1149 ac->set_value ( ac->interface_to_internal(p), gcd);
1154 Strip::periodic (ARDOUR::microseconds_t now)
1157 update_automation ();
1161 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1163 if (_block_screen_redisplay_until >= now) {
1164 /* no drawing allowed */
1168 if (_block_screen_redisplay_until) {
1169 /* we were blocked, but the time period has elapsed, so we must
1173 _block_screen_redisplay_until = 0;
1176 if (force || (current_display[0] != pending_display[0])) {
1177 _surface->write (display (0, pending_display[0]));
1178 current_display[0] = pending_display[0];
1181 if (return_to_vpot_mode_display_at <= now) {
1182 return_to_vpot_mode_display_at = UINT64_MAX;
1183 return_to_vpot_mode_display ();
1186 if (force || (current_display[1] != pending_display[1])) {
1187 _surface->write (display (1, pending_display[1]));
1188 current_display[1] = pending_display[1];
1193 Strip::update_automation ()
1199 ARDOUR::AutoState state = _stripable->gain_control()->automation_state();
1201 if (state == Touch || state == Play) {
1202 notify_gain_changed (false);
1205 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
1207 state = pan_control->automation_state ();
1208 if (state == Touch || state == Play) {
1209 notify_panner_azi_changed (false);
1213 pan_control = _stripable->pan_width_control ();
1215 state = pan_control->automation_state ();
1216 if (state == Touch || state == Play) {
1217 notify_panner_width_changed (false);
1223 Strip::update_meter ()
1229 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1233 if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
1234 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
1235 _meter->send_update (*_surface, dB);
1243 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1244 _surface->write ((*it)->zero ());
1247 _surface->write (blank_display (0));
1248 _surface->write (blank_display (1));
1249 pending_display[0] = string();
1250 pending_display[1] = string();
1251 current_display[0] = string();
1252 current_display[1] = string();
1256 Strip::blank_display (uint32_t line_number)
1258 return display (line_number, string());
1262 Strip::display (uint32_t line_number, const std::string& line)
1264 assert (line_number <= 1);
1266 MidiByteArray retval;
1268 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1271 retval << _surface->sysex_hdr();
1275 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1276 retval << (_index * 7 + (line_number * 0x38));
1278 // ascii data to display. @param line is UTF-8
1279 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1280 string::size_type len = ascii.length();
1282 ascii = ascii.substr (0, 6);
1286 // pad with " " out to 6 chars
1287 for (int i = len; i < 6; ++i) {
1291 // column spacer, unless it's the right-hand column
1297 retval << MIDI::eox;
1303 Strip::lock_controls ()
1305 _controls_locked = true;
1309 Strip::unlock_controls ()
1311 _controls_locked = false;
1315 Strip::vpot_mode_string ()
1317 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1321 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1327 switch (ac->desc().type) {
1328 case PanAzimuthAutomation:
1330 case PanWidthAutomation:
1332 case PanElevationAutomation:
1334 case PanFrontBackAutomation:
1336 case PanLFEAutomation:
1342 //"None" mode, by definition (currently) shows the pan control above the fader.
1343 //Mixbus controllers are created from a LADSPA so they don't have ac->desc().type
1344 //For the forseeable future, we will just return "Pan" here.
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) {
1361 _vpot->set_control (fader_control);
1362 _fader->set_control (pot_control);
1364 /* update fader with pot value */
1366 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1368 /* update pot with fader value */
1370 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1373 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1374 do_parameter_display (GainAutomation, fader_control->get_value());
1376 do_parameter_display (BusSendLevel, pot_control->get_value());
1387 Strip::block_screen_display_for (uint32_t msecs)
1389 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1393 Strip::block_vpot_mode_display_for (uint32_t msecs)
1395 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1399 Strip::return_to_vpot_mode_display ()
1401 /* returns the second line of the two-line per-strip display
1402 back the mode where it shows what the VPot controls.
1405 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1406 /* do nothing - second line shows value of current subview parameter */
1408 } else if (_stripable) {
1409 pending_display[1] = vpot_mode_string();
1411 pending_display[1] = string();
1416 Strip::next_pot_mode ()
1418 vector<AutomationType>::iterator i;
1420 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1421 /* do not change vpot mode while in flipped mode */
1422 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1423 pending_display[1] = "Flip";
1424 block_vpot_mode_display_for (1000);
1429 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1436 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1440 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1444 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1445 if ((*i) == ac->parameter().type()) {
1450 /* move to the next mode in the list, or back to the start (which will
1451 also happen if the current mode is not in the current pot mode list)
1454 if (i != possible_pot_parameters.end()) {
1458 if (i == possible_pot_parameters.end()) {
1459 i = possible_pot_parameters.begin();
1462 set_vpot_parameter (*i);
1466 Strip::subview_mode_changed ()
1468 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
1470 subview_connections.drop_connections ();
1472 switch (_surface->mcp().subview_mode()) {
1473 case MackieControlProtocol::None:
1474 set_vpot_parameter (_pan_mode);
1475 /* need to show strip name again */
1476 show_stripable_name ();
1478 _surface->write (_vpot->set (0, true, Pot::wrap));
1479 _surface->write (_fader->set_position (0.0));
1481 notify_metering_state_changed ();
1485 case MackieControlProtocol::EQ:
1489 /* leave it as it was */
1493 case MackieControlProtocol::Dynamics:
1497 /* leave it as it was */
1502 case MackieControlProtocol::Sends:
1504 setup_sends_vpot (r);
1506 /* leave it as it was */
1510 case MackieControlProtocol::TrackView:
1512 setup_trackview_vpot (r);
1514 /* leave it as it was */
1522 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
1528 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1529 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1530 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1531 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1532 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1534 uint32_t pos = _surface->mcp().global_index (*this);
1536 /* we will control the pos-th available parameter, from the list in the
1537 * order shown above.
1540 vector<boost::shared_ptr<AutomationControl> > available;
1541 vector<AutomationType> params;
1543 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1544 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1545 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1546 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1547 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1549 if (pos >= available.size()) {
1550 /* this knob is not needed to control the available parameters */
1551 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1552 pending_display[0] = string();
1553 pending_display[1] = string();
1557 boost::shared_ptr<AutomationControl> pc;
1558 AutomationType param;
1560 pc = available[pos];
1561 param = params[pos];
1563 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1564 _vpot->set_control (pc);
1574 pot_id = r->comp_speed_name (mc->get_value());
1595 if (!pot_id.empty()) {
1596 pending_display[0] = pot_id;
1598 pending_display[0] = string();
1601 notify_dyn_change (param, true, false);
1605 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
1607 uint32_t bands = r->eq_band_cnt ();
1610 /* should never get here */
1614 /* figure out how many params per band are available */
1616 boost::shared_ptr<AutomationControl> pc;
1617 uint32_t params_per_band = 0;
1619 if ((pc = r->eq_gain_controllable (0))) {
1620 params_per_band += 1;
1622 if ((pc = r->eq_freq_controllable (0))) {
1623 params_per_band += 1;
1625 if ((pc = r->eq_q_controllable (0))) {
1626 params_per_band += 1;
1628 if ((pc = r->eq_shape_controllable (0))) {
1629 params_per_band += 1;
1632 /* pick the one for this strip, based on its global position across
1638 const uint32_t total_band_parameters = bands * params_per_band;
1639 const uint32_t global_pos = _surface->mcp().global_index (*this);
1640 AutomationType param = NullAutomation;
1645 if (global_pos < total_band_parameters) {
1647 /* show a parameter for an EQ band */
1649 const uint32_t parameter = global_pos % params_per_band;
1650 eq_band = global_pos / params_per_band;
1651 band_name = r->eq_band_name (eq_band);
1653 switch (parameter) {
1655 pc = r->eq_gain_controllable (eq_band);
1659 pc = r->eq_freq_controllable (eq_band);
1660 param = EQFrequency;
1663 pc = r->eq_q_controllable (eq_band);
1667 pc = r->eq_shape_controllable (eq_band);
1674 /* show a non-band parameter (HPF or enable)
1677 uint32_t parameter = global_pos - total_band_parameters;
1679 switch (parameter) {
1680 case 0: /* first control after band parameters */
1681 pc = r->eq_hpf_controllable();
1684 case 1: /* second control after band parameters */
1685 pc = r->eq_enable_controllable();
1689 /* nothing to control */
1690 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1691 pending_display[0] = string();
1692 pending_display[1] = string();
1701 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1702 _vpot->set_control (pc);
1708 pot_id = band_name + "Gain";
1711 pot_id = band_name + "Freq";
1714 pot_id = band_name + " Q";
1717 pot_id = band_name + " Shp";
1729 if (!pot_id.empty()) {
1730 pending_display[0] = pot_id;
1732 pending_display[0] = string();
1735 notify_eq_change (param, eq_band, true);
1740 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1746 const uint32_t global_pos = _surface->mcp().global_index (*this);
1748 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1751 /* nothing to control */
1752 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1753 pending_display[0] = string();
1754 pending_display[1] = string();
1758 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1759 _vpot->set_control (pc);
1761 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1763 notify_send_level_change (BusSendLevel, global_pos, true);
1767 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1773 const uint32_t global_pos = _surface->mcp().global_index (*this);
1775 if (global_pos >= 8) {
1776 /* nothing to control */
1777 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1778 pending_display[0] = string();
1779 pending_display[1] = string();
1783 boost::shared_ptr<AutomationControl> pc;
1784 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1787 switch (global_pos) {
1789 pc = r->trim_control ();
1791 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1792 pending_display[0] = "Trim";
1793 notify_trackview_change (TrimAutomation, global_pos, true);
1798 pc = track->monitoring_control();
1800 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1801 pending_display[0] = "Mon";
1802 notify_trackview_change (MonitoringAutomation, global_pos, true);
1807 pc = r->solo_isolate_control ();
1809 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1810 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1811 pending_display[0] = "S-Iso";
1815 pc = r->solo_safe_control ();
1817 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1818 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1819 pending_display[0] = "S-Safe";
1823 pc = r->phase_control();
1825 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1826 notify_trackview_change (PhaseAutomation, global_pos, true);
1827 pending_display[0] = "Phase";
1831 // pc = r->trim_control ();
1834 // pc = r->trim_control ();
1837 // pc = r->trim_control ();
1842 pending_display[0] = string();
1843 pending_display[1] = string();
1847 _vpot->set_control (pc);
1851 Strip::set_vpot_parameter (AutomationType p)
1853 if (!_stripable || (p == NullAutomation)) {
1854 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1855 pending_display[1] = string();
1859 boost::shared_ptr<AutomationControl> pan_control;
1861 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1863 reset_saved_values ();
1866 case PanAzimuthAutomation:
1867 pan_control = _stripable->pan_azimuth_control ();
1869 case PanWidthAutomation:
1870 pan_control = _stripable->pan_width_control ();
1872 case PanElevationAutomation:
1874 case PanFrontBackAutomation:
1876 case PanLFEAutomation:
1884 _vpot->set_control (pan_control);
1887 pending_display[1] = vpot_mode_string ();
1891 Strip::is_midi_track () const
1893 return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1897 Strip::reset_saved_values ()
1899 _last_pan_azi_position_written = -1.0;
1900 _last_pan_width_position_written = -1.0;
1901 _last_gain_position_written = -1.0;
1902 _last_trim_position_written = -1.0;
1907 Strip::notify_metering_state_changed()
1909 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1913 if (!_stripable || !_meter) {
1917 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1918 bool metering_active = _surface->mcp().metering_active ();
1920 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1924 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1926 if (!transport_is_rolling || !metering_active) {
1927 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1928 notify_panner_azi_changed (true);
1931 _transport_is_rolling = transport_is_rolling;
1932 _metering_active = metering_active;