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 uint32_t bands = r->eq_band_cnt ();
1651 /* should never get here */
1655 /* figure out how many params per band are available */
1657 boost::shared_ptr<AutomationControl> pc;
1658 uint32_t params_per_band = 0;
1660 if ((pc = r->eq_gain_controllable (0))) {
1661 params_per_band += 1;
1663 if ((pc = r->eq_freq_controllable (0))) {
1664 params_per_band += 1;
1666 if ((pc = r->eq_q_controllable (0))) {
1667 params_per_band += 1;
1669 if ((pc = r->eq_shape_controllable (0))) {
1670 params_per_band += 1;
1673 /* pick the one for this strip, based on its global position across
1679 const uint32_t total_band_parameters = bands * params_per_band;
1680 const uint32_t global_pos = _surface->mcp().global_index (*this);
1681 AutomationType param = NullAutomation;
1686 if (global_pos < total_band_parameters) {
1688 /* show a parameter for an EQ band */
1690 const uint32_t parameter = global_pos % params_per_band;
1691 eq_band = global_pos / params_per_band;
1692 band_name = r->eq_band_name (eq_band);
1694 switch (parameter) {
1695 #ifdef MIXBUS32C //in 32C, we swap the order of freq/gain to match the GUI
1697 pc = r->eq_freq_controllable (eq_band);
1698 param = EQFrequency;
1701 pc = r->eq_gain_controllable (eq_band);
1706 pc = r->eq_gain_controllable (eq_band);
1710 pc = r->eq_freq_controllable (eq_band);
1711 param = EQFrequency;
1715 pc = r->eq_q_controllable (eq_band);
1719 pc = r->eq_shape_controllable (eq_band);
1726 /* show a non-band parameter (HPF or enable)
1729 uint32_t parameter = global_pos - total_band_parameters;
1731 switch (parameter) {
1733 case 0: /* first control after band parameters */
1734 pc = r->filter_freq_controllable(true);
1737 case 1: /* second control after band parameters */
1738 pc = r->eq_enable_controllable();
1743 /* nothing to control */
1744 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1745 pending_display[0] = string();
1746 pending_display[1] = string();
1755 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1756 _vpot->set_control (pc);
1762 pot_id = band_name + "Gain";
1765 pot_id = band_name + "Freq";
1768 pot_id = band_name + " Q";
1771 pot_id = band_name + " Shp";
1785 if (!pot_id.empty()) {
1786 pending_display[0] = pot_id;
1788 pending_display[0] = string();
1791 notify_eq_change (param, eq_band, true);
1796 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1802 const uint32_t global_pos = _surface->mcp().global_index (*this);
1804 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1807 /* nothing to control */
1808 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1809 pending_display[0] = string();
1810 pending_display[1] = string();
1814 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1815 _vpot->set_control (pc);
1817 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1819 notify_send_level_change (BusSendLevel, global_pos, true);
1823 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1829 const uint32_t global_pos = _surface->mcp().global_index (*this);
1831 if (global_pos >= 8) {
1832 /* nothing to control */
1833 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1834 pending_display[0] = string();
1835 pending_display[1] = string();
1839 boost::shared_ptr<AutomationControl> pc;
1840 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1843 switch (global_pos) {
1845 pc = r->trim_control ();
1847 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1848 pending_display[0] = "Trim";
1849 notify_trackview_change (TrimAutomation, global_pos, true);
1854 pc = track->monitoring_control();
1856 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1857 pending_display[0] = "Mon";
1858 notify_trackview_change (MonitoringAutomation, global_pos, true);
1863 pc = r->solo_isolate_control ();
1865 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1866 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1867 pending_display[0] = "S-Iso";
1871 pc = r->solo_safe_control ();
1873 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1874 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1875 pending_display[0] = "S-Safe";
1879 pc = r->phase_control();
1881 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1882 notify_trackview_change (PhaseAutomation, global_pos, true);
1883 pending_display[0] = "Phase";
1887 // pc = r->trim_control ();
1890 // pc = r->trim_control ();
1893 // pc = r->trim_control ();
1898 pending_display[0] = string();
1899 pending_display[1] = string();
1903 _vpot->set_control (pc);
1907 Strip::set_vpot_parameter (AutomationType p)
1909 if (!_stripable || (p == NullAutomation)) {
1910 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1911 pending_display[1] = string();
1915 boost::shared_ptr<AutomationControl> pan_control;
1917 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1919 reset_saved_values ();
1922 case PanAzimuthAutomation:
1923 pan_control = _stripable->pan_azimuth_control ();
1925 case PanWidthAutomation:
1926 pan_control = _stripable->pan_width_control ();
1928 case PanElevationAutomation:
1930 case PanFrontBackAutomation:
1932 case PanLFEAutomation:
1940 _vpot->set_control (pan_control);
1943 pending_display[1] = vpot_mode_string ();
1947 Strip::is_midi_track () const
1949 return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1953 Strip::reset_saved_values ()
1955 _last_pan_azi_position_written = -1.0;
1956 _last_pan_width_position_written = -1.0;
1957 _last_gain_position_written = -1.0;
1958 _last_trim_position_written = -1.0;
1963 Strip::notify_metering_state_changed()
1965 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1969 if (!_stripable || !_meter) {
1973 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1974 bool metering_active = _surface->mcp().metering_active ();
1976 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1980 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1982 if (!transport_is_rolling || !metering_active) {
1983 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1984 notify_panner_azi_changed (true);
1987 _transport_is_rolling = transport_is_rolling;
1988 _metering_active = metering_active;