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->presentation_info().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_hpf_controllable ();
531 control = r->eq_enable_controllable ();
538 float val = control->get_value();
539 do_parameter_display (type, val);
540 /* update pot/encoder */
541 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
546 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
548 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
551 /* not in subview mode */
555 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
556 /* no longer in EQ subview mode */
560 boost::shared_ptr<AutomationControl> control;
561 bool reset_all = false;
565 control = r->comp_threshold_controllable ();
568 control = r->comp_speed_controllable ();
571 control = r->comp_mode_controllable ();
575 control = r->comp_makeup_controllable ();
578 control = r->comp_redux_controllable ();
581 control = r->comp_enable_controllable ();
587 if (propagate_mode && reset_all) {
588 _surface->subview_mode_changed ();
592 float val = control->get_value();
593 do_parameter_display (type, val);
594 /* update pot/encoder */
595 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
600 Strip::notify_panner_azi_changed (bool force_update)
606 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
608 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
611 /* basically impossible, since we're here because that control
612 * changed, but sure, whatever.
617 if (_vpot->control() != pan_control) {
621 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
622 double internal_pos = pan_control->get_value();
624 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
626 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
627 /* show actual internal value to user */
628 do_parameter_display (PanAzimuthAutomation, internal_pos);
630 _last_pan_azi_position_written = normalized_pos;
635 Strip::notify_panner_width_changed (bool force_update)
641 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
643 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_width_control ();
646 /* basically impossible, since we're here because that control
647 * changed, but sure, whatever.
652 if (_vpot->control() != pan_control) {
656 double pos = pan_control->internal_to_interface (pan_control->get_value());
658 if (force_update || pos != _last_pan_width_position_written) {
660 _surface->write (_vpot->set (pos, true, Pot::spread));
661 do_parameter_display (PanWidthAutomation, pos);
663 _last_pan_width_position_written = pos;
668 Strip::select_event (Button&, ButtonState bs)
670 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
674 int ms = _surface->mcp().main_modifier_state();
676 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
677 _controls_locked = !_controls_locked;
678 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
679 block_vpot_mode_display_for (1000);
683 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
684 _surface->mcp().add_down_select_button (_surface->number(), _index);
685 _surface->mcp().select_range ();
688 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
689 _surface->mcp().remove_down_select_button (_surface->number(), _index);
694 Strip::vselect_event (Button&, ButtonState bs)
696 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
698 /* most subview modes: vpot press acts like a button for toggle parameters */
704 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
706 boost::shared_ptr<AutomationControl> control = _vpot->control ();
711 Controllable::GroupControlDisposition gcd;
712 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
713 gcd = Controllable::InverseGroup;
715 gcd = Controllable::UseGroup;
718 if (control->toggled()) {
719 if (control->toggled()) {
720 control->set_value (!control->get_value(), gcd);
723 } else if (control->desc().enumeration || control->desc().integer_step) {
725 double val = control->get_value ();
726 if (val <= control->upper() - 1.0) {
727 control->set_value (val + 1.0, gcd);
729 control->set_value (control->lower(), gcd);
735 /* Send mode: press enables/disables the relevant
736 * send, but the vpot is bound to the send-level so we
737 * need to lookup the enable/disable control
741 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
745 const uint32_t global_pos = _surface->mcp().global_index (*this);
746 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
749 bool currently_enabled = (bool) control->get_value();
750 Controllable::GroupControlDisposition gcd;
752 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
753 gcd = Controllable::InverseGroup;
755 gcd = Controllable::UseGroup;
758 control->set_value (!currently_enabled, gcd);
760 if (currently_enabled) {
761 /* we just turned it off */
762 pending_display[1] = "off";
764 /* we just turned it on, show the level
766 control = _stripable->send_level_controllable (global_pos);
767 do_parameter_display (BusSendLevel, control->get_value());
773 /* done with this event in subview mode */
780 int ms = _surface->mcp().main_modifier_state();
782 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
784 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
788 /* reset to default/normal value */
789 ac->set_value (ac->normal(), Controllable::NoGroup);
796 boost::shared_ptr<AutomationControl> ac = _stripable->master_send_enable_controllable ();
798 Controllable::GroupControlDisposition gcd;
800 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
801 gcd = Controllable::InverseGroup;
803 gcd = Controllable::UseGroup;
806 bool enabled = ac->get_value();
807 ac->set_value (!enabled, gcd);
811 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
812 /* switch vpot to control next available parameter */
821 Strip::fader_touch_event (Button&, ButtonState bs)
823 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
827 boost::shared_ptr<AutomationControl> ac = _fader->control ();
829 _fader->set_in_use (true);
830 _fader->start_touch (_surface->mcp().transport_frame());
833 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
838 _fader->set_in_use (false);
839 _fader->stop_touch (_surface->mcp().transport_frame(), true);
846 Strip::handle_button (Button& button, ButtonState bs)
848 boost::shared_ptr<AutomationControl> control;
851 button.set_in_use (true);
853 button.set_in_use (false);
856 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
858 switch (button.bid()) {
860 select_event (button, bs);
863 case Button::VSelect:
864 vselect_event (button, bs);
867 case Button::FaderTouch:
868 fader_touch_event (button, bs);
872 if ((control = button.control ())) {
874 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
875 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
877 float new_value = control->get_value() ? 0.0 : 1.0;
879 /* get all controls that either have their
880 * button down or are within a range of
881 * several down buttons
884 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
887 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
888 controls.size(), control->parameter().type(), new_value));
890 /* apply change, with potential modifier semantics */
892 Controllable::GroupControlDisposition gcd;
894 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
895 gcd = Controllable::InverseGroup;
897 gcd = Controllable::UseGroup;
900 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
901 (*c)->set_value (new_value, gcd);
905 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
906 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
914 Strip::do_parameter_display (AutomationType type, float val)
916 bool screen_hold = false;
922 pending_display[1] = " -inf ";
924 float dB = accurate_coefficient_to_dB (val);
925 snprintf (buf, sizeof (buf), "%6.1f", dB);
926 pending_display[1] = buf;
932 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
933 snprintf (buf, sizeof (buf), "%2.1f", val);
934 pending_display[1] = buf;
938 pending_display[1] = " -inf ";
940 float dB = accurate_coefficient_to_dB (val);
941 snprintf (buf, sizeof (buf), "%6.1f", dB);
942 pending_display[1] = buf;
948 case PanAzimuthAutomation:
949 if (Profile->get_mixbus()) {
950 snprintf (buf, sizeof (buf), "%2.1f", val);
951 pending_display[1] = buf;
955 boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
957 pending_display[1] = pa->get_user_string ();
964 case PanWidthAutomation:
966 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
967 pending_display[1] = buf;
974 float dB = accurate_coefficient_to_dB (val);
975 snprintf (buf, sizeof (buf), "%6.1f", dB);
976 pending_display[1] = buf;
981 case PhaseAutomation:
984 pending_display[1] = "Normal";
986 pending_display[1] = "Invert";
1001 snprintf (buf, sizeof (buf), "%6.1f", val);
1002 pending_display[1] = buf;
1008 pending_display[1] = "on";
1010 pending_display[1] = "off";
1014 if (_surface->mcp().subview_stripable()) {
1015 pending_display[1] = _surface->mcp().subview_stripable()->comp_mode_name (val);
1018 case SoloSafeAutomation:
1019 case SoloIsolateAutomation:
1021 pending_display[1] = "on";
1023 pending_display[1] = "off";
1026 case MonitoringAutomation:
1027 switch (MonitorChoice ((int) val)) {
1029 pending_display[1] = "auto";
1032 pending_display[1] = "input";
1035 pending_display[1] = "disk";
1037 case MonitorCue: /* XXX not implemented as of jan 2016 */
1038 pending_display[1] = "cue";
1047 /* we just queued up a parameter to be displayed.
1048 1 second from now, switch back to vpot mode display.
1050 block_vpot_mode_display_for (1000);
1055 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1058 fader.start_touch (_surface->mcp().transport_frame());
1060 fader.stop_touch (_surface->mcp().transport_frame(), false);
1065 Strip::handle_fader (Fader& fader, float position)
1067 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1068 boost::shared_ptr<AutomationControl> ac = fader.control();
1073 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1075 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1076 gcd = Controllable::InverseGroup;
1079 fader.set_value (position, gcd);
1081 /* From the Mackie Control MIDI implementation docs:
1083 In order to ensure absolute synchronization with the host software,
1084 Mackie Control uses a closed-loop servo system for the faders,
1085 meaning the faders will always move to their last received position.
1086 When a host receives a Fader Position Message, it must then
1087 re-transmit that message to the Mackie Control or else the faders
1088 will return to their last position.
1091 _surface->write (fader.set_position (position));
1095 Strip::handle_pot (Pot& pot, float delta)
1097 /* Pots only emit events when they move, not when they
1098 stop moving. So to get a stop event, we need to use a timeout.
1101 boost::shared_ptr<AutomationControl> ac = pot.control();
1106 Controllable::GroupControlDisposition gcd;
1108 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1109 gcd = Controllable::InverseGroup;
1111 gcd = Controllable::UseGroup;
1114 if (ac->toggled()) {
1116 /* make it like a single-step, directional switch */
1119 ac->set_value (1.0, gcd);
1121 ac->set_value (0.0, gcd);
1124 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1126 /* use Controllable::get_value() to avoid the
1127 * "scaling-to-interface" that takes place in
1128 * Control::get_value() via the pot member.
1130 * an enumeration with 4 values will have interface values of
1131 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1136 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1138 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1143 double p = ac->get_interface();
1150 ac->set_value ( ac->interface_to_internal(p), gcd);
1155 Strip::periodic (ARDOUR::microseconds_t now)
1158 update_automation ();
1162 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1164 if (_block_screen_redisplay_until >= now) {
1165 /* no drawing allowed */
1169 if (_block_screen_redisplay_until) {
1170 /* we were blocked, but the time period has elapsed, so we must
1174 _block_screen_redisplay_until = 0;
1177 if (force || (current_display[0] != pending_display[0])) {
1178 _surface->write (display (0, pending_display[0]));
1179 current_display[0] = pending_display[0];
1182 if (return_to_vpot_mode_display_at <= now) {
1183 return_to_vpot_mode_display_at = UINT64_MAX;
1184 return_to_vpot_mode_display ();
1187 if (force || (current_display[1] != pending_display[1])) {
1188 _surface->write (display (1, pending_display[1]));
1189 current_display[1] = pending_display[1];
1194 Strip::update_automation ()
1200 ARDOUR::AutoState state = _stripable->gain_control()->automation_state();
1202 if (state == Touch || state == Play) {
1203 notify_gain_changed (false);
1206 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
1208 state = pan_control->automation_state ();
1209 if (state == Touch || state == Play) {
1210 notify_panner_azi_changed (false);
1214 pan_control = _stripable->pan_width_control ();
1216 state = pan_control->automation_state ();
1217 if (state == Touch || state == Play) {
1218 notify_panner_width_changed (false);
1224 Strip::update_meter ()
1230 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1234 if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
1235 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
1236 _meter->send_update (*_surface, dB);
1244 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1245 _surface->write ((*it)->zero ());
1248 _surface->write (blank_display (0));
1249 _surface->write (blank_display (1));
1250 pending_display[0] = string();
1251 pending_display[1] = string();
1252 current_display[0] = string();
1253 current_display[1] = string();
1257 Strip::blank_display (uint32_t line_number)
1259 return display (line_number, string());
1263 Strip::display (uint32_t line_number, const std::string& line)
1265 assert (line_number <= 1);
1267 MidiByteArray retval;
1269 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1272 retval << _surface->sysex_hdr();
1276 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1277 retval << (_index * 7 + (line_number * 0x38));
1279 // ascii data to display. @param line is UTF-8
1280 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1281 string::size_type len = ascii.length();
1283 ascii = ascii.substr (0, 6);
1287 // pad with " " out to 6 chars
1288 for (int i = len; i < 6; ++i) {
1292 // column spacer, unless it's the right-hand column
1298 retval << MIDI::eox;
1304 Strip::lock_controls ()
1306 _controls_locked = true;
1310 Strip::unlock_controls ()
1312 _controls_locked = false;
1316 Strip::vpot_mode_string ()
1318 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1322 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1328 switch (ac->desc().type) {
1329 case PanAzimuthAutomation:
1331 case PanWidthAutomation:
1333 case PanElevationAutomation:
1335 case PanFrontBackAutomation:
1337 case PanLFEAutomation:
1347 Strip::flip_mode_changed ()
1349 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1351 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1352 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1354 if (pot_control && fader_control) {
1355 _vpot->set_control (fader_control);
1356 _fader->set_control (pot_control);
1359 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1360 do_parameter_display (GainAutomation, fader_control->get_value());
1362 do_parameter_display (BusSendLevel, fader_control->get_value());
1367 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1371 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1380 Strip::block_screen_display_for (uint32_t msecs)
1382 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1386 Strip::block_vpot_mode_display_for (uint32_t msecs)
1388 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1392 Strip::return_to_vpot_mode_display ()
1394 /* returns the second line of the two-line per-strip display
1395 back the mode where it shows what the VPot controls.
1398 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1399 /* do nothing - second line shows value of current subview parameter */
1401 } else if (_stripable) {
1402 pending_display[1] = vpot_mode_string();
1404 pending_display[1] = string();
1409 Strip::next_pot_mode ()
1411 vector<AutomationType>::iterator i;
1413 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1414 /* do not change vpot mode while in flipped mode */
1415 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1416 pending_display[1] = "Flip";
1417 block_vpot_mode_display_for (1000);
1422 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1429 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1433 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1437 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1438 if ((*i) == ac->parameter().type()) {
1443 /* move to the next mode in the list, or back to the start (which will
1444 also happen if the current mode is not in the current pot mode list)
1447 if (i != possible_pot_parameters.end()) {
1451 if (i == possible_pot_parameters.end()) {
1452 i = possible_pot_parameters.begin();
1455 set_vpot_parameter (*i);
1459 Strip::subview_mode_changed ()
1461 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
1463 subview_connections.drop_connections ();
1465 switch (_surface->mcp().subview_mode()) {
1466 case MackieControlProtocol::None:
1467 set_vpot_parameter (_pan_mode);
1468 /* need to show strip name again */
1469 show_stripable_name ();
1471 _surface->write (_vpot->set (0, true, Pot::wrap));
1472 _surface->write (_fader->set_position (0.0));
1474 notify_metering_state_changed ();
1478 case MackieControlProtocol::EQ:
1482 /* leave it as it was */
1486 case MackieControlProtocol::Dynamics:
1490 /* leave it as it was */
1495 case MackieControlProtocol::Sends:
1497 setup_sends_vpot (r);
1499 /* leave it as it was */
1503 case MackieControlProtocol::TrackView:
1505 setup_trackview_vpot (r);
1507 /* leave it as it was */
1515 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
1521 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1522 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1523 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1524 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1525 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1526 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1528 uint32_t pos = _surface->mcp().global_index (*this);
1530 /* we will control the pos-th available parameter, from the list in the
1531 * order shown above.
1534 vector<boost::shared_ptr<AutomationControl> > available;
1535 vector<AutomationType> params;
1537 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1538 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1539 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1540 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1541 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1542 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1544 if (pos >= available.size()) {
1545 /* this knob is not needed to control the available parameters */
1546 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1547 pending_display[0] = string();
1548 pending_display[1] = string();
1552 boost::shared_ptr<AutomationControl> pc;
1553 AutomationType param;
1555 pc = available[pos];
1556 param = params[pos];
1558 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1559 _vpot->set_control (pc);
1569 pot_id = r->comp_speed_name (mc->get_value());
1590 if (!pot_id.empty()) {
1591 pending_display[0] = pot_id;
1593 pending_display[0] = string();
1596 notify_dyn_change (param, true, false);
1600 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
1602 uint32_t bands = r->eq_band_cnt ();
1605 /* should never get here */
1609 /* figure out how many params per band are available */
1611 boost::shared_ptr<AutomationControl> pc;
1612 uint32_t params_per_band = 0;
1614 if ((pc = r->eq_gain_controllable (0))) {
1615 params_per_band += 1;
1617 if ((pc = r->eq_freq_controllable (0))) {
1618 params_per_band += 1;
1620 if ((pc = r->eq_q_controllable (0))) {
1621 params_per_band += 1;
1623 if ((pc = r->eq_shape_controllable (0))) {
1624 params_per_band += 1;
1627 /* pick the one for this strip, based on its global position across
1633 const uint32_t total_band_parameters = bands * params_per_band;
1634 const uint32_t global_pos = _surface->mcp().global_index (*this);
1635 AutomationType param = NullAutomation;
1640 if (global_pos < total_band_parameters) {
1642 /* show a parameter for an EQ band */
1644 const uint32_t parameter = global_pos % params_per_band;
1645 eq_band = global_pos / params_per_band;
1646 band_name = r->eq_band_name (eq_band);
1648 switch (parameter) {
1650 pc = r->eq_gain_controllable (eq_band);
1654 pc = r->eq_freq_controllable (eq_band);
1655 param = EQFrequency;
1658 pc = r->eq_q_controllable (eq_band);
1662 pc = r->eq_shape_controllable (eq_band);
1669 /* show a non-band parameter (HPF or enable)
1672 uint32_t parameter = global_pos - total_band_parameters;
1674 switch (parameter) {
1675 case 0: /* first control after band parameters */
1676 pc = r->eq_hpf_controllable();
1679 case 1: /* second control after band parameters */
1680 pc = r->eq_enable_controllable();
1684 /* nothing to control */
1685 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1686 pending_display[0] = string();
1687 pending_display[1] = string();
1696 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1697 _vpot->set_control (pc);
1703 pot_id = band_name + "Gain";
1706 pot_id = band_name + "Freq";
1709 pot_id = band_name + " Q";
1712 pot_id = band_name + " Shp";
1724 if (!pot_id.empty()) {
1725 pending_display[0] = pot_id;
1727 pending_display[0] = string();
1730 notify_eq_change (param, eq_band, true);
1735 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1741 const uint32_t global_pos = _surface->mcp().global_index (*this);
1743 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1746 pending_display[0] = string();
1747 pending_display[1] = string();
1751 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1752 _vpot->set_control (pc);
1754 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1756 notify_send_level_change (BusSendLevel, global_pos, true);
1760 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1766 const uint32_t global_pos = _surface->mcp().global_index (*this);
1768 if (global_pos >= 8) {
1769 pending_display[0] = string();
1770 pending_display[1] = string();
1774 boost::shared_ptr<AutomationControl> pc;
1775 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1778 switch (global_pos) {
1780 pc = r->trim_control ();
1782 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1783 pending_display[0] = "Trim";
1784 notify_trackview_change (TrimAutomation, global_pos, true);
1789 pc = track->monitoring_control();
1791 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1792 pending_display[0] = "Mon";
1793 notify_trackview_change (MonitoringAutomation, global_pos, true);
1798 pc = r->solo_isolate_control ();
1800 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1801 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1802 pending_display[0] = "S-Iso";
1806 pc = r->solo_safe_control ();
1808 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1809 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1810 pending_display[0] = "S-Safe";
1814 pc = r->phase_control();
1816 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1817 notify_trackview_change (PhaseAutomation, global_pos, true);
1818 pending_display[0] = "Phase";
1822 // pc = r->trim_control ();
1825 // pc = r->trim_control ();
1828 // pc = r->trim_control ();
1833 pending_display[0] = string();
1834 pending_display[1] = string();
1838 _vpot->set_control (pc);
1842 Strip::set_vpot_parameter (AutomationType p)
1844 if (!_stripable || (p == NullAutomation)) {
1845 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1846 pending_display[1] = string();
1850 boost::shared_ptr<AutomationControl> pan_control;
1852 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1854 reset_saved_values ();
1857 case PanAzimuthAutomation:
1858 pan_control = _stripable->pan_azimuth_control ();
1860 case PanWidthAutomation:
1861 pan_control = _stripable->pan_width_control ();
1863 case PanElevationAutomation:
1865 case PanFrontBackAutomation:
1867 case PanLFEAutomation:
1875 _vpot->set_control (pan_control);
1878 pending_display[1] = vpot_mode_string ();
1882 Strip::is_midi_track () const
1884 return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1888 Strip::reset_saved_values ()
1890 _last_pan_azi_position_written = -1.0;
1891 _last_pan_width_position_written = -1.0;
1892 _last_gain_position_written = -1.0;
1893 _last_trim_position_written = -1.0;
1898 Strip::notify_metering_state_changed()
1900 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1904 if (!_stripable || !_meter) {
1908 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1909 bool metering_active = _surface->mcp().metering_active ();
1911 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1915 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1917 if (!transport_is_rolling || !metering_active) {
1918 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1919 notify_panner_azi_changed (true);
1922 _transport_is_rolling = transport_is_rolling;
1923 _metering_active = metering_active;