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()));
389 Strip::show_stripable_name ()
391 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
393 if (svm != MackieControlProtocol::None) {
394 /* subview mode is responsible for upper line */
398 string fullname = string();
402 fullname = _stripable->name();
405 if (fullname.length() <= 6) {
406 pending_display[0] = fullname;
408 pending_display[0] = PBD::short_version (fullname, 6);
413 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
415 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
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<Stripable> r = _surface->mcp().subview_stripable();
449 /* not in subview mode */
453 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
454 /* no longer in TrackViewsubview mode */
458 boost::shared_ptr<AutomationControl> control;
459 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
463 control = r->trim_control();
465 case SoloIsolateAutomation:
466 control = r->solo_isolate_control ();
468 case SoloSafeAutomation:
469 control = r->solo_safe_control ();
471 case MonitoringAutomation:
473 control = track->monitoring_control();
476 case PhaseAutomation:
477 control = r->phase_control ();
484 float val = control->get_value();
486 /* Note: all of the displayed controllables require the display
487 * of their *actual* ("internal") value, not the version mapped
488 * into the normalized 0..1.0 ("interface") range.
491 do_parameter_display (type, val);
492 /* update pot/encoder */
493 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
498 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
500 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
503 /* not in subview mode */
507 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
508 /* no longer in EQ subview mode */
512 boost::shared_ptr<AutomationControl> control;
516 control = r->eq_gain_controllable (band);
519 control = r->eq_freq_controllable (band);
522 control = r->eq_q_controllable (band);
525 control = r->eq_shape_controllable (band);
528 control = r->eq_enable_controllable ();
532 control = r->filter_freq_controllable (true);
540 float val = control->get_value();
541 do_parameter_display (type, val);
542 /* update pot/encoder */
543 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
548 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
550 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
553 /* not in subview mode */
557 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
558 /* no longer in EQ subview mode */
562 boost::shared_ptr<AutomationControl> control;
563 bool reset_all = false;
567 control = r->comp_threshold_controllable ();
570 control = r->comp_speed_controllable ();
573 control = r->comp_mode_controllable ();
577 control = r->comp_makeup_controllable ();
580 control = r->comp_enable_controllable ();
584 control = r->filter_freq_controllable (true);
587 control = r->filter_freq_controllable (false);
590 control = r->filter_enable_controllable (true); // both HP/LP
597 if (propagate_mode && reset_all) {
598 _surface->subview_mode_changed ();
602 float val = control->get_value();
603 do_parameter_display (type, val);
604 /* update pot/encoder */
605 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
610 Strip::notify_panner_azi_changed (bool force_update)
616 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
618 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
621 /* basically impossible, since we're here because that control
622 * changed, but sure, whatever.
627 if (_vpot->control() != pan_control) {
631 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
632 double internal_pos = pan_control->get_value();
634 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
636 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
637 /* show actual internal value to user */
638 do_parameter_display (PanAzimuthAutomation, internal_pos);
640 _last_pan_azi_position_written = normalized_pos;
645 Strip::notify_panner_width_changed (bool force_update)
651 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
653 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_width_control ();
656 /* basically impossible, since we're here because that control
657 * changed, but sure, whatever.
662 if (_vpot->control() != pan_control) {
666 double pos = pan_control->internal_to_interface (pan_control->get_value());
668 if (force_update || pos != _last_pan_width_position_written) {
670 _surface->write (_vpot->set (pos, true, Pot::spread));
671 do_parameter_display (PanWidthAutomation, pos);
673 _last_pan_width_position_written = pos;
678 Strip::select_event (Button&, ButtonState bs)
680 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
684 int ms = _surface->mcp().main_modifier_state();
686 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
687 _controls_locked = !_controls_locked;
688 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
689 block_vpot_mode_display_for (1000);
693 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
694 _surface->mcp().add_down_select_button (_surface->number(), _index);
695 _surface->mcp().select_range (_surface->mcp().global_index (*this));
698 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
699 _surface->mcp().remove_down_select_button (_surface->number(), _index);
704 Strip::vselect_event (Button&, ButtonState bs)
706 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
708 /* most subview modes: vpot press acts like a button for toggle parameters */
714 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
716 boost::shared_ptr<AutomationControl> control = _vpot->control ();
721 Controllable::GroupControlDisposition gcd;
722 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
723 gcd = Controllable::InverseGroup;
725 gcd = Controllable::UseGroup;
728 if (control->toggled()) {
729 if (control->toggled()) {
730 control->set_value (!control->get_value(), gcd);
733 } else if (control->desc().enumeration || control->desc().integer_step) {
735 double val = control->get_value ();
736 if (val <= control->upper() - 1.0) {
737 control->set_value (val + 1.0, gcd);
739 control->set_value (control->lower(), gcd);
745 /* Send mode: press enables/disables the relevant
746 * send, but the vpot is bound to the send-level so we
747 * need to lookup the enable/disable control
751 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
755 const uint32_t global_pos = _surface->mcp().global_index (*this);
756 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
759 bool currently_enabled = (bool) control->get_value();
760 Controllable::GroupControlDisposition gcd;
762 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
763 gcd = Controllable::InverseGroup;
765 gcd = Controllable::UseGroup;
768 control->set_value (!currently_enabled, gcd);
770 if (currently_enabled) {
771 /* we just turned it off */
772 pending_display[1] = "off";
774 /* we just turned it on, show the level
776 control = _stripable->send_level_controllable (global_pos);
777 do_parameter_display (BusSendLevel, control->get_value());
783 /* done with this event in subview mode */
790 int ms = _surface->mcp().main_modifier_state();
792 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
794 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
798 /* reset to default/normal value */
799 ac->set_value (ac->normal(), Controllable::NoGroup);
806 boost::shared_ptr<AutomationControl> ac = _stripable->master_send_enable_controllable ();
808 Controllable::GroupControlDisposition gcd;
810 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
811 gcd = Controllable::InverseGroup;
813 gcd = Controllable::UseGroup;
816 bool enabled = ac->get_value();
817 ac->set_value (!enabled, gcd);
821 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
822 /* switch vpot to control next available parameter */
831 Strip::fader_touch_event (Button&, ButtonState bs)
833 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
837 boost::shared_ptr<AutomationControl> ac = _fader->control ();
839 _fader->set_in_use (true);
840 _fader->start_touch (_surface->mcp().transport_frame());
843 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
848 _fader->set_in_use (false);
849 _fader->stop_touch (_surface->mcp().transport_frame(), true);
856 Strip::handle_button (Button& button, ButtonState bs)
858 boost::shared_ptr<AutomationControl> control;
861 button.set_in_use (true);
863 button.set_in_use (false);
866 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
868 switch (button.bid()) {
870 select_event (button, bs);
873 case Button::VSelect:
874 vselect_event (button, bs);
877 case Button::FaderTouch:
878 fader_touch_event (button, bs);
882 if ((control = button.control ())) {
884 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
885 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
887 float new_value = control->get_value() ? 0.0 : 1.0;
889 /* get all controls that either have their
890 * button down or are within a range of
891 * several down buttons
894 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type(),
895 _surface->mcp().global_index(*this));
898 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
899 controls.size(), control->parameter().type(), new_value));
901 /* apply change, with potential modifier semantics */
903 Controllable::GroupControlDisposition gcd;
905 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
906 gcd = Controllable::InverseGroup;
908 gcd = Controllable::UseGroup;
911 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
912 (*c)->set_value (new_value, gcd);
916 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
917 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
925 Strip::do_parameter_display (AutomationType type, float val)
927 bool screen_hold = false;
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 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
944 snprintf (buf, sizeof (buf), "%2.1f", val);
945 pending_display[1] = buf;
949 pending_display[1] = " -inf ";
951 float dB = accurate_coefficient_to_dB (val);
952 snprintf (buf, sizeof (buf), "%6.1f", dB);
953 pending_display[1] = buf;
959 case PanAzimuthAutomation:
960 if (Profile->get_mixbus()) {
961 snprintf (buf, sizeof (buf), "%2.1f", val);
962 pending_display[1] = buf;
966 boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
968 pending_display[1] = pa->get_user_string ();
975 case PanWidthAutomation:
977 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
978 pending_display[1] = buf;
985 float dB = accurate_coefficient_to_dB (val);
986 snprintf (buf, sizeof (buf), "%6.1f", dB);
987 pending_display[1] = buf;
992 case PhaseAutomation:
995 pending_display[1] = "Normal";
997 pending_display[1] = "Invert";
1013 snprintf (buf, sizeof (buf), "%6.1f", val);
1014 pending_display[1] = buf;
1017 case EQFilterEnable:
1021 pending_display[1] = "on";
1023 pending_display[1] = "off";
1027 if (_surface->mcp().subview_stripable()) {
1028 pending_display[1] = _surface->mcp().subview_stripable()->comp_mode_name (val);
1031 case SoloSafeAutomation:
1032 case SoloIsolateAutomation:
1034 pending_display[1] = "on";
1036 pending_display[1] = "off";
1039 case MonitoringAutomation:
1040 switch (MonitorChoice ((int) val)) {
1042 pending_display[1] = "auto";
1045 pending_display[1] = "input";
1048 pending_display[1] = "disk";
1050 case MonitorCue: /* XXX not implemented as of jan 2016 */
1051 pending_display[1] = "cue";
1060 /* we just queued up a parameter to be displayed.
1061 1 second from now, switch back to vpot mode display.
1063 block_vpot_mode_display_for (1000);
1068 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1071 fader.start_touch (_surface->mcp().transport_frame());
1073 fader.stop_touch (_surface->mcp().transport_frame(), false);
1078 Strip::handle_fader (Fader& fader, float position)
1080 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1081 boost::shared_ptr<AutomationControl> ac = fader.control();
1086 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1088 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1089 gcd = Controllable::InverseGroup;
1092 fader.set_value (position, gcd);
1094 /* From the Mackie Control MIDI implementation docs:
1096 In order to ensure absolute synchronization with the host software,
1097 Mackie Control uses a closed-loop servo system for the faders,
1098 meaning the faders will always move to their last received position.
1099 When a host receives a Fader Position Message, it must then
1100 re-transmit that message to the Mackie Control or else the faders
1101 will return to their last position.
1104 _surface->write (fader.set_position (position));
1108 Strip::handle_pot (Pot& pot, float delta)
1110 /* Pots only emit events when they move, not when they
1111 stop moving. So to get a stop event, we need to use a timeout.
1114 boost::shared_ptr<AutomationControl> ac = pot.control();
1119 Controllable::GroupControlDisposition gcd;
1121 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1122 gcd = Controllable::InverseGroup;
1124 gcd = Controllable::UseGroup;
1127 if (ac->toggled()) {
1129 /* make it like a single-step, directional switch */
1132 ac->set_value (1.0, gcd);
1134 ac->set_value (0.0, gcd);
1137 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1139 /* use Controllable::get_value() to avoid the
1140 * "scaling-to-interface" that takes place in
1141 * Control::get_value() via the pot member.
1143 * an enumeration with 4 values will have interface values of
1144 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1149 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1151 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1156 double p = ac->get_interface();
1163 ac->set_value ( ac->interface_to_internal(p), gcd);
1168 Strip::periodic (ARDOUR::microseconds_t now)
1171 update_automation ();
1175 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1177 if (_block_screen_redisplay_until >= now) {
1178 /* no drawing allowed */
1182 if (_block_screen_redisplay_until) {
1183 /* we were blocked, but the time period has elapsed, so we must
1187 _block_screen_redisplay_until = 0;
1190 if (force || (current_display[0] != pending_display[0])) {
1191 _surface->write (display (0, pending_display[0]));
1192 current_display[0] = pending_display[0];
1195 if (return_to_vpot_mode_display_at <= now) {
1196 return_to_vpot_mode_display_at = UINT64_MAX;
1197 return_to_vpot_mode_display ();
1200 if (force || (current_display[1] != pending_display[1])) {
1201 _surface->write (display (1, pending_display[1]));
1202 current_display[1] = pending_display[1];
1207 Strip::update_automation ()
1213 ARDOUR::AutoState state = _stripable->gain_control()->automation_state();
1215 if (state == Touch || state == Play) {
1216 notify_gain_changed (false);
1219 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
1221 state = pan_control->automation_state ();
1222 if (state == Touch || state == Play) {
1223 notify_panner_azi_changed (false);
1227 pan_control = _stripable->pan_width_control ();
1229 state = pan_control->automation_state ();
1230 if (state == Touch || state == Play) {
1231 notify_panner_width_changed (false);
1237 Strip::update_meter ()
1243 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1247 if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
1248 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
1249 _meter->send_update (*_surface, dB);
1257 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1258 _surface->write ((*it)->zero ());
1261 _surface->write (blank_display (0));
1262 _surface->write (blank_display (1));
1263 pending_display[0] = string();
1264 pending_display[1] = string();
1265 current_display[0] = string();
1266 current_display[1] = string();
1270 Strip::blank_display (uint32_t line_number)
1272 return display (line_number, string());
1276 Strip::display (uint32_t line_number, const std::string& line)
1278 assert (line_number <= 1);
1280 MidiByteArray retval;
1282 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1285 retval << _surface->sysex_hdr();
1289 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1290 retval << (_index * 7 + (line_number * 0x38));
1292 // ascii data to display. @param line is UTF-8
1293 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1294 string::size_type len = ascii.length();
1296 ascii = ascii.substr (0, 6);
1300 // pad with " " out to 6 chars
1301 for (int i = len; i < 6; ++i) {
1305 // column spacer, unless it's the right-hand column
1311 retval << MIDI::eox;
1317 Strip::lock_controls ()
1319 _controls_locked = true;
1323 Strip::unlock_controls ()
1325 _controls_locked = false;
1329 Strip::vpot_mode_string ()
1331 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1335 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1341 switch (ac->desc().type) {
1342 case PanAzimuthAutomation:
1344 case PanWidthAutomation:
1346 case PanElevationAutomation:
1348 case PanFrontBackAutomation:
1350 case PanLFEAutomation:
1356 //"None" mode, by definition (currently) shows the pan control above the fader.
1357 //Mixbus controllers are created from a LADSPA so they don't have ac->desc().type
1358 //For the forseeable future, we will just return "Pan" here.
1366 Strip::flip_mode_changed ()
1368 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1370 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1371 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1373 if (pot_control && fader_control) {
1375 _vpot->set_control (fader_control);
1376 _fader->set_control (pot_control);
1378 /* update fader with pot value */
1380 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1382 /* update pot with fader value */
1384 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1387 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1388 do_parameter_display (GainAutomation, fader_control->get_value());
1390 do_parameter_display (BusSendLevel, pot_control->get_value());
1401 Strip::block_screen_display_for (uint32_t msecs)
1403 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1407 Strip::block_vpot_mode_display_for (uint32_t msecs)
1409 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1413 Strip::return_to_vpot_mode_display ()
1415 /* returns the second line of the two-line per-strip display
1416 back the mode where it shows what the VPot controls.
1419 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1420 /* do nothing - second line shows value of current subview parameter */
1422 } else if (_stripable) {
1423 pending_display[1] = vpot_mode_string();
1425 pending_display[1] = string();
1430 Strip::next_pot_mode ()
1432 vector<AutomationType>::iterator i;
1434 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1435 /* do not change vpot mode while in flipped mode */
1436 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1437 pending_display[1] = "Flip";
1438 block_vpot_mode_display_for (1000);
1443 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1450 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1454 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1458 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1459 if ((*i) == ac->parameter().type()) {
1464 /* move to the next mode in the list, or back to the start (which will
1465 also happen if the current mode is not in the current pot mode list)
1468 if (i != possible_pot_parameters.end()) {
1472 if (i == possible_pot_parameters.end()) {
1473 i = possible_pot_parameters.begin();
1476 set_vpot_parameter (*i);
1480 Strip::subview_mode_changed ()
1482 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
1484 subview_connections.drop_connections ();
1486 switch (_surface->mcp().subview_mode()) {
1487 case MackieControlProtocol::None:
1488 set_vpot_parameter (_pan_mode);
1489 /* need to show strip name again */
1490 show_stripable_name ();
1492 _surface->write (_vpot->set (0, true, Pot::wrap));
1493 _surface->write (_fader->set_position (0.0));
1495 notify_metering_state_changed ();
1499 case MackieControlProtocol::EQ:
1503 /* leave it as it was */
1507 case MackieControlProtocol::Dynamics:
1511 /* leave it as it was */
1516 case MackieControlProtocol::Sends:
1518 setup_sends_vpot (r);
1520 /* leave it as it was */
1524 case MackieControlProtocol::TrackView:
1526 setup_trackview_vpot (r);
1528 /* leave it as it was */
1536 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
1542 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1543 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1544 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1545 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1546 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1548 #ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
1549 boost::shared_ptr<AutomationControl> hpfc = r->filter_freq_controllable (true);
1550 boost::shared_ptr<AutomationControl> lpfc = r->filter_freq_controllable (false);
1551 boost::shared_ptr<AutomationControl> fec = r->filter_enable_controllable (true); // shared HP/LP
1554 uint32_t pos = _surface->mcp().global_index (*this);
1556 /* we will control the pos-th available parameter, from the list in the
1557 * order shown above.
1560 vector<boost::shared_ptr<AutomationControl> > available;
1561 vector<AutomationType> params;
1563 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1564 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1565 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1566 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1567 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1569 #ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
1570 if (hpfc) { available.push_back (hpfc); params.push_back (EQHPF); }
1571 if (lpfc) { available.push_back (lpfc); params.push_back (EQLPF); }
1572 if (fec) { available.push_back (fec); params.push_back (EQFilterEnable); }
1575 if (pos >= available.size()) {
1576 /* this knob is not needed to control the available parameters */
1577 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1578 pending_display[0] = string();
1579 pending_display[1] = string();
1583 boost::shared_ptr<AutomationControl> pc;
1584 AutomationType param;
1586 pc = available[pos];
1587 param = params[pos];
1589 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1590 _vpot->set_control (pc);
1600 pot_id = r->comp_speed_name (mc->get_value());
1624 case EQFilterEnable:
1636 if (!pot_id.empty()) {
1637 pending_display[0] = pot_id;
1639 pending_display[0] = string();
1642 notify_dyn_change (param, true, false);
1646 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
1648 boost::shared_ptr<AutomationControl> pc;
1650 const uint32_t global_pos = _surface->mcp().global_index (*this);
1651 AutomationType param = NullAutomation;
1656 if ( r->is_input_strip() ) {
1659 switch (global_pos) {
1664 eq_band = global_pos / 2;
1665 pc = r->eq_freq_controllable (eq_band);
1666 band_name = r->eq_band_name (eq_band);
1667 param = EQFrequency;
1673 eq_band = global_pos / 2;
1674 pc = r->eq_gain_controllable (eq_band);
1675 band_name = r->eq_band_name (eq_band);
1679 pc = r->eq_shape_controllable(0); //low band "bell" button
1684 pc = r->eq_shape_controllable(3); //high band "bell" button
1689 pc = r->eq_enable_controllable();
1694 #else //regular Mixbus channel EQ
1696 switch (global_pos) {
1700 eq_band = global_pos / 2;
1701 pc = r->eq_gain_controllable (eq_band);
1702 band_name = r->eq_band_name (eq_band);
1708 eq_band = global_pos / 2;
1709 pc = r->eq_freq_controllable (eq_band);
1710 band_name = r->eq_band_name (eq_band);
1711 param = EQFrequency;
1714 pc = r->eq_enable_controllable();
1718 pc = r->filter_freq_controllable(true);
1725 } else { //mixbus or master bus ( these are currently the same for MB & 32C )
1726 switch (global_pos) {
1730 eq_band = global_pos;
1731 pc = r->eq_gain_controllable (eq_band);
1738 //If a controllable was found, connect it up, and put the labels in the display.
1740 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1741 _vpot->set_control (pc);
1747 pot_id = band_name + "Gain";
1750 pot_id = band_name + "Freq";
1753 pot_id = band_name + " Q";
1756 pot_id = band_name + " Shp";
1768 if (!pot_id.empty()) {
1769 pending_display[0] = pot_id;
1771 pending_display[0] = string();
1774 } else { //no controllable was found; just clear this knob
1775 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1776 pending_display[0] = string();
1777 pending_display[1] = string();
1780 notify_eq_change (param, eq_band, true);
1784 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1790 const uint32_t global_pos = _surface->mcp().global_index (*this);
1792 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1795 /* nothing to control */
1796 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1797 pending_display[0] = string();
1798 pending_display[1] = string();
1802 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1803 _vpot->set_control (pc);
1805 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1807 notify_send_level_change (BusSendLevel, global_pos, true);
1811 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1817 const uint32_t global_pos = _surface->mcp().global_index (*this);
1819 if (global_pos >= 8) {
1820 /* nothing to control */
1821 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1822 pending_display[0] = string();
1823 pending_display[1] = string();
1827 boost::shared_ptr<AutomationControl> pc;
1828 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1831 switch (global_pos) {
1833 pc = r->trim_control ();
1835 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1836 pending_display[0] = "Trim";
1837 notify_trackview_change (TrimAutomation, global_pos, true);
1842 pc = track->monitoring_control();
1844 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1845 pending_display[0] = "Mon";
1846 notify_trackview_change (MonitoringAutomation, global_pos, true);
1851 pc = r->solo_isolate_control ();
1853 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1854 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1855 pending_display[0] = "S-Iso";
1859 pc = r->solo_safe_control ();
1861 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1862 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1863 pending_display[0] = "S-Safe";
1867 pc = r->phase_control();
1869 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1870 notify_trackview_change (PhaseAutomation, global_pos, true);
1871 pending_display[0] = "Phase";
1875 // pc = r->trim_control ();
1878 // pc = r->trim_control ();
1881 // pc = r->trim_control ();
1886 pending_display[0] = string();
1887 pending_display[1] = string();
1891 _vpot->set_control (pc);
1895 Strip::set_vpot_parameter (AutomationType p)
1897 if (!_stripable || (p == NullAutomation)) {
1898 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1899 pending_display[1] = string();
1903 boost::shared_ptr<AutomationControl> pan_control;
1905 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1907 reset_saved_values ();
1910 case PanAzimuthAutomation:
1911 pan_control = _stripable->pan_azimuth_control ();
1913 case PanWidthAutomation:
1914 pan_control = _stripable->pan_width_control ();
1916 case PanElevationAutomation:
1918 case PanFrontBackAutomation:
1920 case PanLFEAutomation:
1928 _vpot->set_control (pan_control);
1931 pending_display[1] = vpot_mode_string ();
1935 Strip::is_midi_track () const
1937 return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1941 Strip::reset_saved_values ()
1943 _last_pan_azi_position_written = -1.0;
1944 _last_pan_width_position_written = -1.0;
1945 _last_gain_position_written = -1.0;
1946 _last_trim_position_written = -1.0;
1951 Strip::notify_metering_state_changed()
1953 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1957 if (!_stripable || !_meter) {
1961 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1962 bool metering_active = _surface->mcp().metering_active ();
1964 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1968 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1970 if (!transport_is_rolling || !metering_active) {
1971 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1972 notify_panner_azi_changed (true);
1975 _transport_is_rolling = transport_is_rolling;
1976 _metering_active = metering_active;