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()));
384 _surface->mcp().update_selected (_stripable, _stripable->presentation_info().selected());
390 Strip::show_stripable_name ()
392 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
394 if (svm != MackieControlProtocol::None) {
395 /* subview mode is responsible for upper line */
399 string fullname = string();
403 fullname = _stripable->name();
406 if (fullname.length() <= 6) {
407 pending_display[0] = fullname;
409 pending_display[0] = PBD::short_version (fullname, 6);
414 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
416 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
419 /* not in subview mode */
423 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
424 /* no longer in Sends subview mode */
428 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
434 float val = control->get_value();
435 do_parameter_display (type, val);
437 if (_vpot->control() == control) {
438 /* update pot/encoder */
439 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
445 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
447 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
450 /* not in subview mode */
454 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
455 /* no longer in TrackViewsubview mode */
459 boost::shared_ptr<AutomationControl> control;
460 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
464 control = r->trim_control();
466 case SoloIsolateAutomation:
467 control = r->solo_isolate_control ();
469 case SoloSafeAutomation:
470 control = r->solo_safe_control ();
472 case MonitoringAutomation:
474 control = track->monitoring_control();
477 case PhaseAutomation:
478 control = r->phase_control ();
485 float val = control->get_value();
487 /* Note: all of the displayed controllables require the display
488 * of their *actual* ("internal") value, not the version mapped
489 * into the normalized 0..1.0 ("interface") range.
492 do_parameter_display (type, val);
493 /* update pot/encoder */
494 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
499 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
501 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
504 /* not in subview mode */
508 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
509 /* no longer in EQ subview mode */
513 boost::shared_ptr<AutomationControl> control;
517 control = r->eq_gain_controllable (band);
520 control = r->eq_freq_controllable (band);
523 control = r->eq_q_controllable (band);
526 control = r->eq_shape_controllable (band);
529 control = r->eq_hpf_controllable ();
532 control = r->eq_enable_controllable ();
539 float val = control->get_value();
540 do_parameter_display (type, val);
541 /* update pot/encoder */
542 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
547 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
549 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
552 /* not in subview mode */
556 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
557 /* no longer in EQ subview mode */
561 boost::shared_ptr<AutomationControl> control;
562 bool reset_all = false;
566 control = r->comp_threshold_controllable ();
569 control = r->comp_speed_controllable ();
572 control = r->comp_mode_controllable ();
576 control = r->comp_makeup_controllable ();
579 control = r->comp_redux_controllable ();
582 control = r->comp_enable_controllable ();
588 if (propagate_mode && reset_all) {
589 _surface->subview_mode_changed ();
593 float val = control->get_value();
594 do_parameter_display (type, val);
595 /* update pot/encoder */
596 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
601 Strip::notify_panner_azi_changed (bool force_update)
607 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
609 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
612 /* basically impossible, since we're here because that control
613 * changed, but sure, whatever.
618 if (_vpot->control() != pan_control) {
622 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
623 double internal_pos = pan_control->get_value();
625 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
627 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
628 /* show actual internal value to user */
629 do_parameter_display (PanAzimuthAutomation, internal_pos);
631 _last_pan_azi_position_written = normalized_pos;
636 Strip::notify_panner_width_changed (bool force_update)
642 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
644 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_width_control ();
647 /* basically impossible, since we're here because that control
648 * changed, but sure, whatever.
653 if (_vpot->control() != pan_control) {
657 double pos = pan_control->internal_to_interface (pan_control->get_value());
659 if (force_update || pos != _last_pan_width_position_written) {
661 _surface->write (_vpot->set (pos, true, Pot::spread));
662 do_parameter_display (PanWidthAutomation, pos);
664 _last_pan_width_position_written = pos;
669 Strip::select_event (Button&, ButtonState bs)
671 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
675 int ms = _surface->mcp().main_modifier_state();
677 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
678 _controls_locked = !_controls_locked;
679 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
680 block_vpot_mode_display_for (1000);
684 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
685 _surface->mcp().add_down_select_button (_surface->number(), _index);
686 _surface->mcp().select_range ();
689 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
690 _surface->mcp().remove_down_select_button (_surface->number(), _index);
695 Strip::vselect_event (Button&, ButtonState bs)
697 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
699 /* most subview modes: vpot press acts like a button for toggle parameters */
705 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
707 boost::shared_ptr<AutomationControl> control = _vpot->control ();
712 Controllable::GroupControlDisposition gcd;
713 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
714 gcd = Controllable::InverseGroup;
716 gcd = Controllable::UseGroup;
719 if (control->toggled()) {
720 if (control->toggled()) {
721 control->set_value (!control->get_value(), gcd);
724 } else if (control->desc().enumeration || control->desc().integer_step) {
726 double val = control->get_value ();
727 if (val <= control->upper() - 1.0) {
728 control->set_value (val + 1.0, gcd);
730 control->set_value (control->lower(), gcd);
736 /* Send mode: press enables/disables the relevant
737 * send, but the vpot is bound to the send-level so we
738 * need to lookup the enable/disable control
742 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
746 const uint32_t global_pos = _surface->mcp().global_index (*this);
747 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
750 bool currently_enabled = (bool) control->get_value();
751 Controllable::GroupControlDisposition gcd;
753 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
754 gcd = Controllable::InverseGroup;
756 gcd = Controllable::UseGroup;
759 control->set_value (!currently_enabled, gcd);
761 if (currently_enabled) {
762 /* we just turned it off */
763 pending_display[1] = "off";
765 /* we just turned it on, show the level
767 control = _stripable->send_level_controllable (global_pos);
768 do_parameter_display (BusSendLevel, control->get_value());
774 /* done with this event in subview mode */
781 int ms = _surface->mcp().main_modifier_state();
783 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
785 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
789 /* reset to default/normal value */
790 ac->set_value (ac->normal(), Controllable::NoGroup);
797 boost::shared_ptr<AutomationControl> ac = _stripable->master_send_enable_controllable ();
799 Controllable::GroupControlDisposition gcd;
801 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
802 gcd = Controllable::InverseGroup;
804 gcd = Controllable::UseGroup;
807 bool enabled = ac->get_value();
808 ac->set_value (!enabled, gcd);
812 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
813 /* switch vpot to control next available parameter */
822 Strip::fader_touch_event (Button&, ButtonState bs)
824 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
828 boost::shared_ptr<AutomationControl> ac = _fader->control ();
830 _fader->set_in_use (true);
831 _fader->start_touch (_surface->mcp().transport_frame());
834 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
839 _fader->set_in_use (false);
840 _fader->stop_touch (_surface->mcp().transport_frame(), true);
847 Strip::handle_button (Button& button, ButtonState bs)
849 boost::shared_ptr<AutomationControl> control;
852 button.set_in_use (true);
854 button.set_in_use (false);
857 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
859 switch (button.bid()) {
861 select_event (button, bs);
864 case Button::VSelect:
865 vselect_event (button, bs);
868 case Button::FaderTouch:
869 fader_touch_event (button, bs);
873 if ((control = button.control ())) {
875 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
876 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
878 float new_value = control->get_value() ? 0.0 : 1.0;
880 /* get all controls that either have their
881 * button down or are within a range of
882 * several down buttons
885 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
888 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
889 controls.size(), control->parameter().type(), new_value));
891 /* apply change, with potential modifier semantics */
893 Controllable::GroupControlDisposition gcd;
895 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
896 gcd = Controllable::InverseGroup;
898 gcd = Controllable::UseGroup;
901 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
902 (*c)->set_value (new_value, gcd);
906 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
907 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
915 Strip::do_parameter_display (AutomationType type, float val)
917 bool screen_hold = false;
923 pending_display[1] = " -inf ";
925 float dB = accurate_coefficient_to_dB (val);
926 snprintf (buf, sizeof (buf), "%6.1f", dB);
927 pending_display[1] = buf;
933 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
934 snprintf (buf, sizeof (buf), "%2.1f", val);
935 pending_display[1] = buf;
939 pending_display[1] = " -inf ";
941 float dB = accurate_coefficient_to_dB (val);
942 snprintf (buf, sizeof (buf), "%6.1f", dB);
943 pending_display[1] = buf;
949 case PanAzimuthAutomation:
950 if (Profile->get_mixbus()) {
951 snprintf (buf, sizeof (buf), "%2.1f", val);
952 pending_display[1] = buf;
956 boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
958 pending_display[1] = pa->get_user_string ();
965 case PanWidthAutomation:
967 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
968 pending_display[1] = buf;
975 float dB = accurate_coefficient_to_dB (val);
976 snprintf (buf, sizeof (buf), "%6.1f", dB);
977 pending_display[1] = buf;
982 case PhaseAutomation:
985 pending_display[1] = "Normal";
987 pending_display[1] = "Invert";
1002 snprintf (buf, sizeof (buf), "%6.1f", val);
1003 pending_display[1] = buf;
1009 pending_display[1] = "on";
1011 pending_display[1] = "off";
1015 if (_surface->mcp().subview_stripable()) {
1016 pending_display[1] = _surface->mcp().subview_stripable()->comp_mode_name (val);
1019 case SoloSafeAutomation:
1020 case SoloIsolateAutomation:
1022 pending_display[1] = "on";
1024 pending_display[1] = "off";
1027 case MonitoringAutomation:
1028 switch (MonitorChoice ((int) val)) {
1030 pending_display[1] = "auto";
1033 pending_display[1] = "input";
1036 pending_display[1] = "disk";
1038 case MonitorCue: /* XXX not implemented as of jan 2016 */
1039 pending_display[1] = "cue";
1048 /* we just queued up a parameter to be displayed.
1049 1 second from now, switch back to vpot mode display.
1051 block_vpot_mode_display_for (1000);
1056 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1059 fader.start_touch (_surface->mcp().transport_frame());
1061 fader.stop_touch (_surface->mcp().transport_frame(), false);
1066 Strip::handle_fader (Fader& fader, float position)
1068 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1069 boost::shared_ptr<AutomationControl> ac = fader.control();
1074 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1076 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1077 gcd = Controllable::InverseGroup;
1080 fader.set_value (position, gcd);
1082 /* From the Mackie Control MIDI implementation docs:
1084 In order to ensure absolute synchronization with the host software,
1085 Mackie Control uses a closed-loop servo system for the faders,
1086 meaning the faders will always move to their last received position.
1087 When a host receives a Fader Position Message, it must then
1088 re-transmit that message to the Mackie Control or else the faders
1089 will return to their last position.
1092 _surface->write (fader.set_position (position));
1096 Strip::handle_pot (Pot& pot, float delta)
1098 /* Pots only emit events when they move, not when they
1099 stop moving. So to get a stop event, we need to use a timeout.
1102 boost::shared_ptr<AutomationControl> ac = pot.control();
1107 Controllable::GroupControlDisposition gcd;
1109 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1110 gcd = Controllable::InverseGroup;
1112 gcd = Controllable::UseGroup;
1115 if (ac->toggled()) {
1117 /* make it like a single-step, directional switch */
1120 ac->set_value (1.0, gcd);
1122 ac->set_value (0.0, gcd);
1125 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1127 /* use Controllable::get_value() to avoid the
1128 * "scaling-to-interface" that takes place in
1129 * Control::get_value() via the pot member.
1131 * an enumeration with 4 values will have interface values of
1132 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1137 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1139 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1144 double p = ac->get_interface();
1151 ac->set_value ( ac->interface_to_internal(p), gcd);
1156 Strip::periodic (ARDOUR::microseconds_t now)
1159 update_automation ();
1163 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1165 if (_block_screen_redisplay_until >= now) {
1166 /* no drawing allowed */
1170 if (_block_screen_redisplay_until) {
1171 /* we were blocked, but the time period has elapsed, so we must
1175 _block_screen_redisplay_until = 0;
1178 if (force || (current_display[0] != pending_display[0])) {
1179 _surface->write (display (0, pending_display[0]));
1180 current_display[0] = pending_display[0];
1183 if (return_to_vpot_mode_display_at <= now) {
1184 return_to_vpot_mode_display_at = UINT64_MAX;
1185 return_to_vpot_mode_display ();
1188 if (force || (current_display[1] != pending_display[1])) {
1189 _surface->write (display (1, pending_display[1]));
1190 current_display[1] = pending_display[1];
1195 Strip::update_automation ()
1201 ARDOUR::AutoState state = _stripable->gain_control()->automation_state();
1203 if (state == Touch || state == Play) {
1204 notify_gain_changed (false);
1207 boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control ();
1209 state = pan_control->automation_state ();
1210 if (state == Touch || state == Play) {
1211 notify_panner_azi_changed (false);
1215 pan_control = _stripable->pan_width_control ();
1217 state = pan_control->automation_state ();
1218 if (state == Touch || state == Play) {
1219 notify_panner_width_changed (false);
1225 Strip::update_meter ()
1231 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1235 if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
1236 float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
1237 _meter->send_update (*_surface, dB);
1245 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1246 _surface->write ((*it)->zero ());
1249 _surface->write (blank_display (0));
1250 _surface->write (blank_display (1));
1251 pending_display[0] = string();
1252 pending_display[1] = string();
1253 current_display[0] = string();
1254 current_display[1] = string();
1258 Strip::blank_display (uint32_t line_number)
1260 return display (line_number, string());
1264 Strip::display (uint32_t line_number, const std::string& line)
1266 assert (line_number <= 1);
1268 MidiByteArray retval;
1270 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1273 retval << _surface->sysex_hdr();
1277 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1278 retval << (_index * 7 + (line_number * 0x38));
1280 // ascii data to display. @param line is UTF-8
1281 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1282 string::size_type len = ascii.length();
1284 ascii = ascii.substr (0, 6);
1288 // pad with " " out to 6 chars
1289 for (int i = len; i < 6; ++i) {
1293 // column spacer, unless it's the right-hand column
1299 retval << MIDI::eox;
1305 Strip::lock_controls ()
1307 _controls_locked = true;
1311 Strip::unlock_controls ()
1313 _controls_locked = false;
1317 Strip::vpot_mode_string ()
1319 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1323 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1329 switch (ac->desc().type) {
1330 case PanAzimuthAutomation:
1332 case PanWidthAutomation:
1334 case PanElevationAutomation:
1336 case PanFrontBackAutomation:
1338 case PanLFEAutomation:
1348 Strip::flip_mode_changed ()
1350 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1352 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1353 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1355 if (pot_control && fader_control) {
1357 _vpot->set_control (fader_control);
1358 _fader->set_control (pot_control);
1360 /* update fader with pot value */
1362 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1364 /* update pot with fader value */
1366 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1369 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1370 do_parameter_display (GainAutomation, fader_control->get_value());
1372 do_parameter_display (BusSendLevel, pot_control->get_value());
1383 Strip::block_screen_display_for (uint32_t msecs)
1385 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1389 Strip::block_vpot_mode_display_for (uint32_t msecs)
1391 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1395 Strip::return_to_vpot_mode_display ()
1397 /* returns the second line of the two-line per-strip display
1398 back the mode where it shows what the VPot controls.
1401 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1402 /* do nothing - second line shows value of current subview parameter */
1404 } else if (_stripable) {
1405 pending_display[1] = vpot_mode_string();
1407 pending_display[1] = string();
1412 Strip::next_pot_mode ()
1414 vector<AutomationType>::iterator i;
1416 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1417 /* do not change vpot mode while in flipped mode */
1418 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1419 pending_display[1] = "Flip";
1420 block_vpot_mode_display_for (1000);
1425 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1432 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1436 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1440 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1441 if ((*i) == ac->parameter().type()) {
1446 /* move to the next mode in the list, or back to the start (which will
1447 also happen if the current mode is not in the current pot mode list)
1450 if (i != possible_pot_parameters.end()) {
1454 if (i == possible_pot_parameters.end()) {
1455 i = possible_pot_parameters.begin();
1458 set_vpot_parameter (*i);
1462 Strip::subview_mode_changed ()
1464 boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
1466 subview_connections.drop_connections ();
1468 switch (_surface->mcp().subview_mode()) {
1469 case MackieControlProtocol::None:
1470 set_vpot_parameter (_pan_mode);
1471 /* need to show strip name again */
1472 show_stripable_name ();
1474 _surface->write (_vpot->set (0, true, Pot::wrap));
1475 _surface->write (_fader->set_position (0.0));
1477 notify_metering_state_changed ();
1481 case MackieControlProtocol::EQ:
1485 /* leave it as it was */
1489 case MackieControlProtocol::Dynamics:
1493 /* leave it as it was */
1498 case MackieControlProtocol::Sends:
1500 setup_sends_vpot (r);
1502 /* leave it as it was */
1506 case MackieControlProtocol::TrackView:
1508 setup_trackview_vpot (r);
1510 /* leave it as it was */
1518 Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
1524 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1525 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1526 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1527 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1528 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1529 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1531 uint32_t pos = _surface->mcp().global_index (*this);
1533 /* we will control the pos-th available parameter, from the list in the
1534 * order shown above.
1537 vector<boost::shared_ptr<AutomationControl> > available;
1538 vector<AutomationType> params;
1540 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1541 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1542 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1543 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1544 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1545 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1547 if (pos >= available.size()) {
1548 /* this knob is not needed to control the available parameters */
1549 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1550 pending_display[0] = string();
1551 pending_display[1] = string();
1555 boost::shared_ptr<AutomationControl> pc;
1556 AutomationType param;
1558 pc = available[pos];
1559 param = params[pos];
1561 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1562 _vpot->set_control (pc);
1572 pot_id = r->comp_speed_name (mc->get_value());
1593 if (!pot_id.empty()) {
1594 pending_display[0] = pot_id;
1596 pending_display[0] = string();
1599 notify_dyn_change (param, true, false);
1603 Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
1605 uint32_t bands = r->eq_band_cnt ();
1608 /* should never get here */
1612 /* figure out how many params per band are available */
1614 boost::shared_ptr<AutomationControl> pc;
1615 uint32_t params_per_band = 0;
1617 if ((pc = r->eq_gain_controllable (0))) {
1618 params_per_band += 1;
1620 if ((pc = r->eq_freq_controllable (0))) {
1621 params_per_band += 1;
1623 if ((pc = r->eq_q_controllable (0))) {
1624 params_per_band += 1;
1626 if ((pc = r->eq_shape_controllable (0))) {
1627 params_per_band += 1;
1630 /* pick the one for this strip, based on its global position across
1636 const uint32_t total_band_parameters = bands * params_per_band;
1637 const uint32_t global_pos = _surface->mcp().global_index (*this);
1638 AutomationType param = NullAutomation;
1643 if (global_pos < total_band_parameters) {
1645 /* show a parameter for an EQ band */
1647 const uint32_t parameter = global_pos % params_per_band;
1648 eq_band = global_pos / params_per_band;
1649 band_name = r->eq_band_name (eq_band);
1651 switch (parameter) {
1653 pc = r->eq_gain_controllable (eq_band);
1657 pc = r->eq_freq_controllable (eq_band);
1658 param = EQFrequency;
1661 pc = r->eq_q_controllable (eq_band);
1665 pc = r->eq_shape_controllable (eq_band);
1672 /* show a non-band parameter (HPF or enable)
1675 uint32_t parameter = global_pos - total_band_parameters;
1677 switch (parameter) {
1678 case 0: /* first control after band parameters */
1679 pc = r->eq_hpf_controllable();
1682 case 1: /* second control after band parameters */
1683 pc = r->eq_enable_controllable();
1687 /* nothing to control */
1688 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1689 pending_display[0] = string();
1690 pending_display[1] = string();
1699 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1700 _vpot->set_control (pc);
1706 pot_id = band_name + "Gain";
1709 pot_id = band_name + "Freq";
1712 pot_id = band_name + " Q";
1715 pot_id = band_name + " Shp";
1727 if (!pot_id.empty()) {
1728 pending_display[0] = pot_id;
1730 pending_display[0] = string();
1733 notify_eq_change (param, eq_band, true);
1738 Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
1744 const uint32_t global_pos = _surface->mcp().global_index (*this);
1746 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1749 /* nothing to control */
1750 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1751 pending_display[0] = string();
1752 pending_display[1] = string();
1756 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1757 _vpot->set_control (pc);
1759 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1761 notify_send_level_change (BusSendLevel, global_pos, true);
1765 Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
1771 const uint32_t global_pos = _surface->mcp().global_index (*this);
1773 if (global_pos >= 8) {
1774 /* nothing to control */
1775 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1776 pending_display[0] = string();
1777 pending_display[1] = string();
1781 boost::shared_ptr<AutomationControl> pc;
1782 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1785 switch (global_pos) {
1787 pc = r->trim_control ();
1789 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1790 pending_display[0] = "Trim";
1791 notify_trackview_change (TrimAutomation, global_pos, true);
1796 pc = track->monitoring_control();
1798 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1799 pending_display[0] = "Mon";
1800 notify_trackview_change (MonitoringAutomation, global_pos, true);
1805 pc = r->solo_isolate_control ();
1807 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1808 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1809 pending_display[0] = "S-Iso";
1813 pc = r->solo_safe_control ();
1815 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1816 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1817 pending_display[0] = "S-Safe";
1821 pc = r->phase_control();
1823 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1824 notify_trackview_change (PhaseAutomation, global_pos, true);
1825 pending_display[0] = "Phase";
1829 // pc = r->trim_control ();
1832 // pc = r->trim_control ();
1835 // pc = r->trim_control ();
1840 pending_display[0] = string();
1841 pending_display[1] = string();
1845 _vpot->set_control (pc);
1849 Strip::set_vpot_parameter (AutomationType p)
1851 if (!_stripable || (p == NullAutomation)) {
1852 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1853 pending_display[1] = string();
1857 boost::shared_ptr<AutomationControl> pan_control;
1859 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1861 reset_saved_values ();
1864 case PanAzimuthAutomation:
1865 pan_control = _stripable->pan_azimuth_control ();
1867 case PanWidthAutomation:
1868 pan_control = _stripable->pan_width_control ();
1870 case PanElevationAutomation:
1872 case PanFrontBackAutomation:
1874 case PanLFEAutomation:
1882 _vpot->set_control (pan_control);
1885 pending_display[1] = vpot_mode_string ();
1889 Strip::is_midi_track () const
1891 return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
1895 Strip::reset_saved_values ()
1897 _last_pan_azi_position_written = -1.0;
1898 _last_pan_width_position_written = -1.0;
1899 _last_gain_position_written = -1.0;
1900 _last_trim_position_written = -1.0;
1905 Strip::notify_metering_state_changed()
1907 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1911 if (!_stripable || !_meter) {
1915 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1916 bool metering_active = _surface->mcp().metering_active ();
1918 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1922 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1924 if (!transport_is_rolling || !metering_active) {
1925 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1926 notify_panner_azi_changed (true);
1929 _transport_is_rolling = transport_is_rolling;
1930 _metering_active = metering_active;