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/route.h"
48 #include "ardour/session.h"
49 #include "ardour/send.h"
50 #include "ardour/solo_isolate_control.h"
51 #include "ardour/track.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/user_bundle.h"
54 #include "ardour/profile.h"
56 #include "mackie_control_protocol.h"
57 #include "surface_port.h"
68 using namespace ARDOUR;
70 using namespace ArdourSurface;
71 using namespace Mackie;
73 #ifndef timeradd /// only avail with __USE_BSD
74 #define timeradd(a,b,result) \
76 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
77 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
78 if ((result)->tv_usec >= 1000000) \
81 (result)->tv_usec -= 1000000; \
86 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
88 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
101 , _controls_locked (false)
102 , _transport_is_rolling (false)
103 , _metering_active (true)
104 , _block_screen_redisplay_until (0)
105 , return_to_vpot_mode_display_at (UINT64_MAX)
107 , _pan_mode (PanAzimuthAutomation)
108 , _last_gain_position_written (-1.0)
109 , _last_pan_azi_position_written (-1.0)
110 , _last_pan_width_position_written (-1.0)
111 , _last_trim_position_written (-1.0)
113 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
114 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
116 if (s.mcp().device_info().has_meters()) {
117 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
120 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
121 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
122 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
123 _surface->number(), index, Button::id_to_name (bb->bid()),
124 bb->id(), b->second.base_id));
130 /* surface is responsible for deleting all controls */
134 Strip::add (Control & control)
138 Group::add (control);
140 /* fader, vpot, meter were all set explicitly */
142 if ((button = dynamic_cast<Button*>(&control)) != 0) {
143 switch (button->bid()) {
144 case Button::RecEnable:
156 case Button::VSelect:
159 case Button::FaderTouch:
160 _fader_touch = button;
169 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
171 if (_controls_locked) {
175 mb_pan_controllable.reset();
177 route_connections.drop_connections ();
179 _solo->set_control (boost::shared_ptr<AutomationControl>());
180 _mute->set_control (boost::shared_ptr<AutomationControl>());
181 _select->set_control (boost::shared_ptr<AutomationControl>());
182 _recenable->set_control (boost::shared_ptr<AutomationControl>());
183 _fader->set_control (boost::shared_ptr<AutomationControl>());
184 _vpot->set_control (boost::shared_ptr<AutomationControl>());
188 reset_saved_values ();
191 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
196 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
197 _surface->number(), _index, _route->name()));
199 _solo->set_control (_route->solo_control());
200 _mute->set_control (_route->mute_control());
202 _route->solo_control()->Changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
203 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
205 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control();
207 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
210 pan_control = _route->pan_width_control();
212 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
215 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
216 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
218 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
221 _recenable->set_control (trk->rec_enable_control());
222 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
225 // TODO this works when a currently-banked route is made inactive, but not
226 // when a route is activated which should be currently banked.
228 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
229 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
231 /* setup legal VPot modes for this route */
233 possible_pot_parameters.clear();
235 if (_route->pan_azimuth_control()) {
236 possible_pot_parameters.push_back (PanAzimuthAutomation);
238 if (_route->pan_width_control()) {
239 possible_pot_parameters.push_back (PanWidthAutomation);
241 if (_route->pan_elevation_control()) {
242 possible_pot_parameters.push_back (PanElevationAutomation);
244 if (_route->pan_frontback_control()) {
245 possible_pot_parameters.push_back (PanFrontBackAutomation);
247 if (_route->pan_lfe_control()) {
248 possible_pot_parameters.push_back (PanLFEAutomation);
251 _pan_mode = PanAzimuthAutomation;
253 if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
254 set_vpot_parameter (_pan_mode);
257 _fader->set_control (_route->gain_control());
269 // The active V-pot control may not be active for this strip
270 // But if we zero it in the controls function it may erase
271 // the one we do want
272 _surface->write (_vpot->zero());
274 notify_solo_changed ();
275 notify_mute_changed ();
276 notify_gain_changed ();
277 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
278 notify_panner_azi_changed ();
279 notify_panner_width_changed ();
280 notify_record_enable_changed ();
281 notify_processor_changed ();
285 Strip::notify_solo_changed ()
287 if (_route && _solo) {
288 _surface->write (_solo->set_state (_route->soloed() ? on : off));
293 Strip::notify_mute_changed ()
295 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
296 if (_route && _mute) {
297 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
298 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
300 _surface->write (_mute->set_state (_route->muted() ? on : off));
305 Strip::notify_record_enable_changed ()
307 if (_route && _recenable) {
308 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (_route);
310 _surface->write (_recenable->set_state (trk->rec_enable_control()->get_value() ? on : off));
316 Strip::notify_active_changed ()
318 _surface->mcp().refresh_current_bank();
322 Strip::notify_route_deleted ()
324 _surface->mcp().refresh_current_bank();
328 Strip::notify_gain_changed (bool force_update)
334 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
338 /* doesn't seem possible but lets be safe */
342 /* track gain control could be on vpot or fader, depending in
346 if (_vpot->control() == ac) {
348 } else if (_fader->control() == ac) {
354 float gain_coefficient = ac->get_value();
355 float normalized_position = ac->internal_to_interface (gain_coefficient);
357 if (force_update || normalized_position != _last_gain_position_written) {
359 if (!control->in_use()) {
360 if (control == _vpot) {
361 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
363 _surface->write (_fader->set_position (normalized_position));
367 do_parameter_display (GainAutomation, gain_coefficient);
368 _last_gain_position_written = normalized_position;
373 Strip::notify_processor_changed (bool force_update)
378 Strip::notify_property_changed (const PropertyChange& what_changed)
380 if (!what_changed.contains (ARDOUR::Properties::name)) {
388 Strip::show_route_name ()
390 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
392 if (svm != MackieControlProtocol::None) {
393 /* subview mode is responsible for upper line */
397 string fullname = string();
401 fullname = _route->name();
404 if (fullname.length() <= 6) {
405 pending_display[0] = fullname;
407 pending_display[0] = PBD::short_version (fullname, 6);
412 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
414 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
417 /* not in subview mode */
421 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
422 /* no longer in Sends subview mode */
426 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
432 float val = control->get_value();
433 do_parameter_display (type, val);
435 if (_vpot->control() == control) {
436 /* update pot/encoder */
437 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
443 Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
445 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
448 /* not in subview mode */
452 if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
453 /* no longer in TrackViewsubview mode */
457 boost::shared_ptr<AutomationControl> control;
458 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
462 control = r->trim_control();
464 case SoloIsolateAutomation:
465 control = r->solo_isolate_control ();
467 case SoloSafeAutomation:
468 control = r->solo_safe_control ();
470 case MonitoringAutomation:
472 control = track->monitoring_control();
475 case PhaseAutomation:
476 control = r->phase_control ();
483 float val = control->get_value();
485 /* Note: all of the displayed controllables require the display
486 * of their *actual* ("internal") value, not the version mapped
487 * into the normalized 0..1.0 ("interface") range.
490 do_parameter_display (type, val);
491 /* update pot/encoder */
492 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
497 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
499 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
502 /* not in subview mode */
506 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
507 /* no longer in EQ subview mode */
511 boost::shared_ptr<AutomationControl> control;
515 control = r->eq_gain_controllable (band);
518 control = r->eq_freq_controllable (band);
521 control = r->eq_q_controllable (band);
524 control = r->eq_shape_controllable (band);
527 control = r->eq_hpf_controllable ();
530 control = r->eq_enable_controllable ();
537 float val = control->get_value();
538 do_parameter_display (type, val);
539 /* update pot/encoder */
540 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
545 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
547 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
550 /* not in subview mode */
554 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
555 /* no longer in EQ subview mode */
559 boost::shared_ptr<AutomationControl> control;
560 bool reset_all = false;
564 control = r->comp_threshold_controllable ();
567 control = r->comp_speed_controllable ();
570 control = r->comp_mode_controllable ();
574 control = r->comp_makeup_controllable ();
577 control = r->comp_redux_controllable ();
580 control = r->comp_enable_controllable ();
586 if (propagate_mode && reset_all) {
587 _surface->subview_mode_changed ();
591 float val = control->get_value();
592 do_parameter_display (type, val);
593 /* update pot/encoder */
594 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
599 Strip::notify_panner_azi_changed (bool force_update)
605 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
607 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
610 /* basically impossible, since we're here because that control
611 * changed, but sure, whatever.
616 if (_vpot->control() != pan_control) {
620 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
621 double internal_pos = pan_control->get_value();
623 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
625 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
626 /* show actual internal value to user */
627 do_parameter_display (PanAzimuthAutomation, internal_pos);
629 _last_pan_azi_position_written = normalized_pos;
634 Strip::notify_panner_width_changed (bool force_update)
640 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
642 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
645 /* basically impossible, since we're here because that control
646 * changed, but sure, whatever.
651 if (_vpot->control() != pan_control) {
655 double pos = pan_control->internal_to_interface (pan_control->get_value());
657 if (force_update || pos != _last_pan_width_position_written) {
659 _surface->write (_vpot->set (pos, true, Pot::spread));
660 do_parameter_display (PanWidthAutomation, pos);
662 _last_pan_width_position_written = pos;
667 Strip::select_event (Button&, ButtonState bs)
669 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
673 int ms = _surface->mcp().main_modifier_state();
675 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
676 _controls_locked = !_controls_locked;
677 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
678 block_vpot_mode_display_for (1000);
682 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
683 _surface->mcp().add_down_select_button (_surface->number(), _index);
684 _surface->mcp().select_range ();
687 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
688 _surface->mcp().remove_down_select_button (_surface->number(), _index);
693 Strip::vselect_event (Button&, ButtonState bs)
695 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
697 /* most subview modes: vpot press acts like a button for toggle parameters */
703 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
705 boost::shared_ptr<AutomationControl> control = _vpot->control ();
710 Controllable::GroupControlDisposition gcd;
711 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
712 gcd = Controllable::InverseGroup;
714 gcd = Controllable::UseGroup;
717 if (control->toggled()) {
718 if (control->toggled()) {
719 control->set_value (!control->get_value(), gcd);
722 } else if (control->desc().enumeration || control->desc().integer_step) {
724 double val = control->get_value ();
725 if (val <= control->upper() - 1.0) {
726 control->set_value (val + 1.0, gcd);
728 control->set_value (control->lower(), gcd);
734 /* Send mode: press enables/disables the relevant
735 * send, but the vpot is bound to the send-level so we
736 * need to lookup the enable/disable control
740 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
744 const uint32_t global_pos = _surface->mcp().global_index (*this);
745 boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
748 bool currently_enabled = (bool) control->get_value();
749 Controllable::GroupControlDisposition gcd;
751 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
752 gcd = Controllable::InverseGroup;
754 gcd = Controllable::UseGroup;
757 control->set_value (!currently_enabled, gcd);
759 if (currently_enabled) {
760 /* we just turned it off */
761 pending_display[1] = "off";
763 /* we just turned it on, show the level
765 control = _route->send_level_controllable (global_pos);
766 do_parameter_display (BusSendLevel, control->get_value());
772 /* done with this event in subview mode */
779 int ms = _surface->mcp().main_modifier_state();
781 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
783 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
787 /* reset to default/normal value */
788 ac->set_value (ac->normal(), Controllable::NoGroup);
795 boost::shared_ptr<AutomationControl> ac = _route->master_send_enable_controllable ();
797 Controllable::GroupControlDisposition gcd;
799 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
800 gcd = Controllable::InverseGroup;
802 gcd = Controllable::UseGroup;
805 bool enabled = ac->get_value();
806 ac->set_value (!enabled, gcd);
810 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
811 /* switch vpot to control next available parameter */
820 Strip::fader_touch_event (Button&, ButtonState bs)
822 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
826 boost::shared_ptr<AutomationControl> ac = _fader->control ();
828 _fader->set_in_use (true);
829 _fader->start_touch (_surface->mcp().transport_frame());
832 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
837 _fader->set_in_use (false);
838 _fader->stop_touch (_surface->mcp().transport_frame(), true);
845 Strip::handle_button (Button& button, ButtonState bs)
847 boost::shared_ptr<AutomationControl> control;
850 button.set_in_use (true);
852 button.set_in_use (false);
855 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
857 switch (button.bid()) {
859 select_event (button, bs);
862 case Button::VSelect:
863 vselect_event (button, bs);
866 case Button::FaderTouch:
867 fader_touch_event (button, bs);
871 if ((control = button.control ())) {
873 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
874 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
876 float new_value = control->get_value() ? 0.0 : 1.0;
878 /* get all controls that either have their
879 * button down or are within a range of
880 * several down buttons
883 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
886 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
887 controls.size(), control->parameter().type(), new_value));
889 /* apply change, with potential modifier semantics */
891 Controllable::GroupControlDisposition gcd;
893 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
894 gcd = Controllable::InverseGroup;
896 gcd = Controllable::UseGroup;
899 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
900 (*c)->set_value (new_value, gcd);
904 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
905 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
913 Strip::do_parameter_display (AutomationType type, float val)
915 bool screen_hold = false;
921 pending_display[1] = " -inf ";
923 float dB = accurate_coefficient_to_dB (val);
924 snprintf (buf, sizeof (buf), "%6.1f", dB);
925 pending_display[1] = buf;
931 if (Profile->get_mixbus()) { //Mixbus sends are already stored in dB
932 snprintf (buf, sizeof (buf), "%2.1f", val);
933 pending_display[1] = buf;
937 pending_display[1] = " -inf ";
939 float dB = accurate_coefficient_to_dB (val);
940 snprintf (buf, sizeof (buf), "%6.1f", dB);
941 pending_display[1] = buf;
947 case PanAzimuthAutomation:
948 if (Profile->get_mixbus()) {
949 snprintf (buf, sizeof (buf), "%2.1f", val);
950 pending_display[1] = buf;
954 boost::shared_ptr<Pannable> p = _route->pannable();
955 if (p && _route->panner()) {
956 pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
963 case PanWidthAutomation:
965 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
966 pending_display[1] = buf;
973 float dB = accurate_coefficient_to_dB (val);
974 snprintf (buf, sizeof (buf), "%6.1f", dB);
975 pending_display[1] = buf;
980 case PhaseAutomation:
983 pending_display[1] = "Normal";
985 pending_display[1] = "Invert";
1000 snprintf (buf, sizeof (buf), "%6.1f", val);
1001 pending_display[1] = buf;
1007 pending_display[1] = "on";
1009 pending_display[1] = "off";
1013 if (_surface->mcp().subview_route()) {
1014 pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1017 case SoloSafeAutomation:
1018 case SoloIsolateAutomation:
1020 pending_display[1] = "on";
1022 pending_display[1] = "off";
1025 case MonitoringAutomation:
1026 switch (MonitorChoice ((int) val)) {
1028 pending_display[1] = "auto";
1031 pending_display[1] = "input";
1034 pending_display[1] = "disk";
1036 case MonitorCue: /* XXX not implemented as of jan 2016 */
1037 pending_display[1] = "cue";
1046 /* we just queued up a parameter to be displayed.
1047 1 second from now, switch back to vpot mode display.
1049 block_vpot_mode_display_for (1000);
1054 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1057 fader.start_touch (_surface->mcp().transport_frame());
1059 fader.stop_touch (_surface->mcp().transport_frame(), false);
1064 Strip::handle_fader (Fader& fader, float position)
1066 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1067 boost::shared_ptr<AutomationControl> ac = fader.control();
1072 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1074 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1075 gcd = Controllable::InverseGroup;
1078 fader.set_value (position, gcd);
1080 /* From the Mackie Control MIDI implementation docs:
1082 In order to ensure absolute synchronization with the host software,
1083 Mackie Control uses a closed-loop servo system for the faders,
1084 meaning the faders will always move to their last received position.
1085 When a host receives a Fader Position Message, it must then
1086 re-transmit that message to the Mackie Control or else the faders
1087 will return to their last position.
1090 _surface->write (fader.set_position (position));
1094 Strip::handle_pot (Pot& pot, float delta)
1096 /* Pots only emit events when they move, not when they
1097 stop moving. So to get a stop event, we need to use a timeout.
1100 boost::shared_ptr<AutomationControl> ac = pot.control();
1105 Controllable::GroupControlDisposition gcd;
1107 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1108 gcd = Controllable::InverseGroup;
1110 gcd = Controllable::UseGroup;
1113 if (ac->toggled()) {
1115 /* make it like a single-step, directional switch */
1118 ac->set_value (1.0, gcd);
1120 ac->set_value (0.0, gcd);
1123 } else if (ac->desc().enumeration || ac->desc().integer_step) {
1125 /* use Controllable::get_value() to avoid the
1126 * "scaling-to-interface" that takes place in
1127 * Control::get_value() via the pot member.
1129 * an enumeration with 4 values will have interface values of
1130 * 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
1135 ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
1137 ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
1142 double p = ac->get_interface();
1149 ac->set_value ( ac->interface_to_internal(p), gcd);
1154 Strip::periodic (ARDOUR::microseconds_t now)
1157 update_automation ();
1161 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1163 if (_block_screen_redisplay_until >= now) {
1164 /* no drawing allowed */
1168 if (_block_screen_redisplay_until) {
1169 /* we were blocked, but the time period has elapsed, so we must
1173 _block_screen_redisplay_until = 0;
1176 if (force || (current_display[0] != pending_display[0])) {
1177 _surface->write (display (0, pending_display[0]));
1178 current_display[0] = pending_display[0];
1181 if (return_to_vpot_mode_display_at <= now) {
1182 return_to_vpot_mode_display_at = UINT64_MAX;
1183 return_to_vpot_mode_display ();
1186 if (force || (current_display[1] != pending_display[1])) {
1187 _surface->write (display (1, pending_display[1]));
1188 current_display[1] = pending_display[1];
1193 Strip::update_automation ()
1199 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1201 if (state == Touch || state == Play) {
1202 notify_gain_changed (false);
1205 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1207 state = pan_control->automation_state ();
1208 if (state == Touch || state == Play) {
1209 notify_panner_azi_changed (false);
1213 pan_control = _route->pan_width_control ();
1215 state = pan_control->automation_state ();
1216 if (state == Touch || state == Play) {
1217 notify_panner_width_changed (false);
1223 Strip::update_meter ()
1229 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1233 if (_meter && _transport_is_rolling && _metering_active) {
1234 float dB = _route->peak_meter()->meter_level (0, MeterMCP);
1235 _meter->send_update (*_surface, dB);
1243 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1244 _surface->write ((*it)->zero ());
1247 _surface->write (blank_display (0));
1248 _surface->write (blank_display (1));
1249 pending_display[0] = string();
1250 pending_display[1] = string();
1251 current_display[0] = string();
1252 current_display[1] = string();
1256 Strip::blank_display (uint32_t line_number)
1258 return display (line_number, string());
1262 Strip::display (uint32_t line_number, const std::string& line)
1264 assert (line_number <= 1);
1266 MidiByteArray retval;
1268 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1271 retval << _surface->sysex_hdr();
1275 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1276 retval << (_index * 7 + (line_number * 0x38));
1278 // ascii data to display. @param line is UTF-8
1279 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1280 string::size_type len = ascii.length();
1282 ascii = ascii.substr (0, 6);
1286 // pad with " " out to 6 chars
1287 for (int i = len; i < 6; ++i) {
1291 // column spacer, unless it's the right-hand column
1297 retval << MIDI::eox;
1303 Strip::lock_controls ()
1305 _controls_locked = true;
1309 Strip::unlock_controls ()
1311 _controls_locked = false;
1315 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1317 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1318 if ((*i) == _route) {
1319 _surface->write (_select->set_state (on));
1324 _surface->write (_select->set_state (off));
1328 Strip::vpot_mode_string ()
1330 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1334 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1340 switch (ac->desc().type) {
1341 case PanAzimuthAutomation:
1343 case PanWidthAutomation:
1345 case PanElevationAutomation:
1347 case PanFrontBackAutomation:
1349 case PanLFEAutomation:
1359 Strip::flip_mode_changed ()
1361 if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
1363 boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
1364 boost::shared_ptr<AutomationControl> fader_control = _fader->control();
1366 if (pot_control && fader_control) {
1367 _vpot->set_control (fader_control);
1368 _fader->set_control (pot_control);
1371 if (_surface->mcp().flip_mode() == MackieControlProtocol::Normal) {
1372 do_parameter_display (GainAutomation, fader_control->get_value());
1374 do_parameter_display (BusSendLevel, fader_control->get_value());
1379 _surface->write (_fader->set_position (pot_control->internal_to_interface (pot_control->get_value ())));
1383 _surface->write (_vpot->set (fader_control->internal_to_interface (fader_control->get_value()), true, Pot::wrap));
1392 Strip::block_screen_display_for (uint32_t msecs)
1394 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1398 Strip::block_vpot_mode_display_for (uint32_t msecs)
1400 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1404 Strip::return_to_vpot_mode_display ()
1406 /* returns the second line of the two-line per-strip display
1407 back the mode where it shows what the VPot controls.
1410 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1411 /* do nothing - second line shows value of current subview parameter */
1413 } else if (_route) {
1414 pending_display[1] = vpot_mode_string();
1416 pending_display[1] = string();
1421 Strip::next_pot_mode ()
1423 vector<AutomationType>::iterator i;
1425 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1426 /* do not change vpot mode while in flipped mode */
1427 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1428 pending_display[1] = "Flip";
1429 block_vpot_mode_display_for (1000);
1434 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1441 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1445 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1449 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1450 if ((*i) == ac->parameter().type()) {
1455 /* move to the next mode in the list, or back to the start (which will
1456 also happen if the current mode is not in the current pot mode list)
1459 if (i != possible_pot_parameters.end()) {
1463 if (i == possible_pot_parameters.end()) {
1464 i = possible_pot_parameters.begin();
1467 set_vpot_parameter (*i);
1471 Strip::subview_mode_changed ()
1473 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1475 subview_connections.drop_connections ();
1477 switch (_surface->mcp().subview_mode()) {
1478 case MackieControlProtocol::None:
1479 set_vpot_parameter (_pan_mode);
1480 /* need to show strip name again */
1483 _surface->write (_vpot->set (0, true, Pot::wrap));
1484 _surface->write (_fader->set_position (0.0));
1486 notify_metering_state_changed ();
1490 case MackieControlProtocol::EQ:
1494 /* leave it as it was */
1498 case MackieControlProtocol::Dynamics:
1502 /* leave it as it was */
1507 case MackieControlProtocol::Sends:
1509 setup_sends_vpot (r);
1511 /* leave it as it was */
1515 case MackieControlProtocol::TrackView:
1517 setup_trackview_vpot (r);
1519 /* leave it as it was */
1527 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1533 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1534 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1535 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1536 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1537 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1538 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1540 uint32_t pos = _surface->mcp().global_index (*this);
1542 /* we will control the pos-th available parameter, from the list in the
1543 * order shown above.
1546 vector<boost::shared_ptr<AutomationControl> > available;
1547 vector<AutomationType> params;
1549 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1550 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1551 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1552 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1553 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1554 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1556 if (pos >= available.size()) {
1557 /* this knob is not needed to control the available parameters */
1558 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1559 pending_display[0] = string();
1560 pending_display[1] = string();
1564 boost::shared_ptr<AutomationControl> pc;
1565 AutomationType param;
1567 pc = available[pos];
1568 param = params[pos];
1570 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1571 _vpot->set_control (pc);
1581 pot_id = r->comp_speed_name (mc->get_value());
1602 if (!pot_id.empty()) {
1603 pending_display[0] = pot_id;
1605 pending_display[0] = string();
1608 notify_dyn_change (param, true, false);
1612 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1614 uint32_t bands = r->eq_band_cnt ();
1617 /* should never get here */
1621 /* figure out how many params per band are available */
1623 boost::shared_ptr<AutomationControl> pc;
1624 uint32_t params_per_band = 0;
1626 if ((pc = r->eq_gain_controllable (0))) {
1627 params_per_band += 1;
1629 if ((pc = r->eq_freq_controllable (0))) {
1630 params_per_band += 1;
1632 if ((pc = r->eq_q_controllable (0))) {
1633 params_per_band += 1;
1635 if ((pc = r->eq_shape_controllable (0))) {
1636 params_per_band += 1;
1639 /* pick the one for this strip, based on its global position across
1645 const uint32_t total_band_parameters = bands * params_per_band;
1646 const uint32_t global_pos = _surface->mcp().global_index (*this);
1647 AutomationType param = NullAutomation;
1652 if (global_pos < total_band_parameters) {
1654 /* show a parameter for an EQ band */
1656 const uint32_t parameter = global_pos % params_per_band;
1657 eq_band = global_pos / params_per_band;
1658 band_name = r->eq_band_name (eq_band);
1660 switch (parameter) {
1662 pc = r->eq_gain_controllable (eq_band);
1666 pc = r->eq_freq_controllable (eq_band);
1667 param = EQFrequency;
1670 pc = r->eq_q_controllable (eq_band);
1674 pc = r->eq_shape_controllable (eq_band);
1681 /* show a non-band parameter (HPF or enable)
1684 uint32_t parameter = global_pos - total_band_parameters;
1686 switch (parameter) {
1687 case 0: /* first control after band parameters */
1688 pc = r->eq_hpf_controllable();
1691 case 1: /* second control after band parameters */
1692 pc = r->eq_enable_controllable();
1696 /* nothing to control */
1697 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1698 pending_display[0] = string();
1699 pending_display[1] = string();
1708 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1709 _vpot->set_control (pc);
1715 pot_id = band_name + "Gain";
1718 pot_id = band_name + "Freq";
1721 pot_id = band_name + " Q";
1724 pot_id = band_name + " Shp";
1736 if (!pot_id.empty()) {
1737 pending_display[0] = pot_id;
1739 pending_display[0] = string();
1742 notify_eq_change (param, eq_band, true);
1747 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1753 const uint32_t global_pos = _surface->mcp().global_index (*this);
1755 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1758 pending_display[0] = string();
1759 pending_display[1] = string();
1763 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1764 _vpot->set_control (pc);
1766 pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
1768 notify_send_level_change (BusSendLevel, global_pos, true);
1772 Strip::setup_trackview_vpot (boost::shared_ptr<Route> r)
1778 const uint32_t global_pos = _surface->mcp().global_index (*this);
1780 if (global_pos >= 8) {
1781 pending_display[0] = string();
1782 pending_display[1] = string();
1786 boost::shared_ptr<AutomationControl> pc;
1787 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
1790 switch (global_pos) {
1792 pc = r->trim_control ();
1794 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
1795 pending_display[0] = "Trim";
1796 notify_trackview_change (TrimAutomation, global_pos, true);
1801 pc = track->monitoring_control();
1803 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
1804 pending_display[0] = "Mon";
1805 notify_trackview_change (MonitoringAutomation, global_pos, true);
1810 pc = r->solo_isolate_control ();
1812 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
1813 notify_trackview_change (SoloIsolateAutomation, global_pos, true);
1814 pending_display[0] = "S-Iso";
1818 pc = r->solo_safe_control ();
1820 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
1821 notify_trackview_change (SoloSafeAutomation, global_pos, true);
1822 pending_display[0] = "S-Safe";
1826 pc = r->phase_control();
1828 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
1829 notify_trackview_change (PhaseAutomation, global_pos, true);
1830 pending_display[0] = "Phase";
1834 // pc = r->trim_control ();
1837 // pc = r->trim_control ();
1840 // pc = r->trim_control ();
1845 pending_display[0] = string();
1846 pending_display[1] = string();
1850 _vpot->set_control (pc);
1854 Strip::set_vpot_parameter (AutomationType p)
1856 if (!_route || (p == NullAutomation)) {
1857 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1858 pending_display[1] = string();
1862 boost::shared_ptr<AutomationControl> pan_control;
1864 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1866 reset_saved_values ();
1869 case PanAzimuthAutomation:
1870 pan_control = _route->pan_azimuth_control ();
1872 case PanWidthAutomation:
1873 pan_control = _route->pan_width_control ();
1875 case PanElevationAutomation:
1877 case PanFrontBackAutomation:
1879 case PanLFEAutomation:
1887 _vpot->set_control (pan_control);
1890 pending_display[1] = vpot_mode_string ();
1894 Strip::is_midi_track () const
1896 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1900 Strip::reset_saved_values ()
1902 _last_pan_azi_position_written = -1.0;
1903 _last_pan_width_position_written = -1.0;
1904 _last_gain_position_written = -1.0;
1905 _last_trim_position_written = -1.0;
1910 Strip::notify_metering_state_changed()
1912 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1916 if (!_route || !_meter) {
1920 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1921 bool metering_active = _surface->mcp().metering_active ();
1923 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1927 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1929 if (!transport_is_rolling || !metering_active) {
1930 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1931 notify_panner_azi_changed (true);
1934 _transport_is_rolling = transport_is_rolling;
1935 _metering_active = metering_active;