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/plugin_insert.h"
41 #include "ardour/pannable.h"
42 #include "ardour/panner.h"
43 #include "ardour/panner_shell.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/route.h"
46 #include "ardour/session.h"
47 #include "ardour/send.h"
48 #include "ardour/track.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/profile.h"
53 #include "mackie_control_protocol.h"
54 #include "surface_port.h"
65 using namespace ARDOUR;
67 using namespace ArdourSurface;
68 using namespace Mackie;
70 #ifndef timeradd /// only avail with __USE_BSD
71 #define timeradd(a,b,result) \
73 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
74 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
75 if ((result)->tv_usec >= 1000000) \
78 (result)->tv_usec -= 1000000; \
83 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
85 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
98 , _controls_locked (false)
99 , _transport_is_rolling (false)
100 , _metering_active (true)
101 , _block_screen_redisplay_until (0)
102 , return_to_vpot_mode_display_at (UINT64_MAX)
104 , _pan_mode (PanAzimuthAutomation)
105 , _trim_mode (TrimAutomation)
106 , vpot_parameter (PanAzimuthAutomation)
107 , _last_gain_position_written (-1.0)
108 , _last_pan_azi_position_written (-1.0)
109 , _last_pan_width_position_written (-1.0)
110 , _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 control_by_parameter.clear ();
190 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
191 control_by_parameter[PanWidthAutomation] = (Control*) 0;
192 control_by_parameter[PanElevationAutomation] = (Control*) 0;
193 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
194 control_by_parameter[PanLFEAutomation] = (Control*) 0;
195 control_by_parameter[GainAutomation] = (Control*) 0;
196 control_by_parameter[TrimAutomation] = (Control*) 0;
197 control_by_parameter[PhaseAutomation] = (Control*) 0;
199 reset_saved_values ();
206 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
207 _surface->number(), _index, _route->name()));
209 _solo->set_control (_route->solo_control());
210 _mute->set_control (_route->mute_control());
212 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
213 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
215 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
217 if (_route->trim() && route()->trim()->active()) {
218 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
221 if (_route->phase_invert().size()) {
222 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
223 _route->phase_control()->set_channel(0);
226 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control();
228 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
231 pan_control = _route->pan_width_control();
233 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
236 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
237 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
239 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
242 _recenable->set_control (trk->rec_enable_control());
243 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
246 // TODO this works when a currently-banked route is made inactive, but not
247 // when a route is activated which should be currently banked.
249 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
250 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
252 /* setup legal VPot modes for this route */
254 possible_pot_parameters.clear();
256 if (_route->pan_azimuth_control()) {
257 possible_pot_parameters.push_back (PanAzimuthAutomation);
259 if (_route->pan_width_control()) {
260 possible_pot_parameters.push_back (PanWidthAutomation);
262 if (_route->pan_elevation_control()) {
263 possible_pot_parameters.push_back (PanElevationAutomation);
265 if (_route->pan_frontback_control()) {
266 possible_pot_parameters.push_back (PanFrontBackAutomation);
268 if (_route->pan_lfe_control()) {
269 possible_pot_parameters.push_back (PanLFEAutomation);
272 if (_route->trim() && route()->trim()->active()) {
273 possible_pot_parameters.push_back (TrimAutomation);
276 possible_trim_parameters.clear();
278 if (_route->trim() && route()->trim()->active()) {
279 possible_trim_parameters.push_back (TrimAutomation);
280 _trim_mode = TrimAutomation;
283 if (_route->phase_invert().size()) {
284 possible_trim_parameters.push_back (PhaseAutomation);
285 _route->phase_control()->set_channel(0);
286 if (_trim_mode != TrimAutomation) {
287 _trim_mode = PhaseAutomation;
292 _pan_mode = PanAzimuthAutomation;
293 potmode_changed (false);
305 // The active V-pot control may not be active for this strip
306 // But if we zero it in the controls function it may erase
307 // the one we do want
308 _surface->write (_vpot->zero());
310 notify_solo_changed ();
311 notify_mute_changed ();
312 notify_gain_changed ();
313 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
314 notify_panner_azi_changed ();
315 notify_panner_width_changed ();
316 notify_record_enable_changed ();
317 notify_trim_changed ();
318 notify_phase_changed ();
319 notify_processor_changed ();
323 Strip::notify_solo_changed ()
325 if (_route && _solo) {
326 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
331 Strip::notify_mute_changed ()
333 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
334 if (_route && _mute) {
335 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
336 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
338 _surface->write (_mute->set_state (_route->muted() ? on : off));
343 Strip::notify_record_enable_changed ()
345 if (_route && _recenable) {
346 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
351 Strip::notify_active_changed ()
353 _surface->mcp().refresh_current_bank();
357 Strip::notify_route_deleted ()
359 _surface->mcp().refresh_current_bank();
363 Strip::notify_gain_changed (bool force_update)
369 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
375 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
377 float gain_coefficient = ac->get_value();
378 float normalized_position = ac->internal_to_interface (gain_coefficient);
380 if (force_update || normalized_position != _last_gain_position_written) {
382 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
383 if (!control->in_use()) {
384 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
386 do_parameter_display (GainAutomation, gain_coefficient);
388 if (!control->in_use()) {
389 _surface->write (_fader->set_position (normalized_position));
391 do_parameter_display (GainAutomation, gain_coefficient);
394 _last_gain_position_written = normalized_position;
400 Strip::notify_trim_changed (bool force_update)
404 if (!_route->trim() || !route()->trim()->active()) {
407 Control* control = 0;
408 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
410 if (i == control_by_parameter.end()) {
416 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
418 float gain_coefficient = ac->get_value();
419 float normalized_position = ac->internal_to_interface (gain_coefficient);
421 if (force_update || normalized_position != _last_trim_position_written) {
422 if (control == _fader) {
423 if (!_fader->in_use()) {
424 _surface->write (_fader->set_position (normalized_position));
425 do_parameter_display (TrimAutomation, gain_coefficient);
427 } else if (control == _vpot) {
428 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
429 do_parameter_display (TrimAutomation, gain_coefficient);
431 _last_trim_position_written = normalized_position;
437 Strip::notify_phase_changed (bool force_update)
440 if (!_route->phase_invert().size()) {
444 Control* control = 0;
445 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
447 if (i == control_by_parameter.end()) {
453 float normalized_position = _route->phase_control()->get_value();
455 if (control == _fader) {
456 if (!_fader->in_use()) {
457 _surface->write (_fader->set_position (normalized_position));
458 do_parameter_display (PhaseAutomation, normalized_position);
460 } else if (control == _vpot) {
461 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
462 do_parameter_display (PhaseAutomation, normalized_position);
468 Strip::notify_processor_changed (bool force_update)
473 Strip::notify_property_changed (const PropertyChange& what_changed)
475 if (!what_changed.contains (ARDOUR::Properties::name)) {
483 Strip::show_route_name ()
485 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
487 if (svm != MackieControlProtocol::None) {
488 /* subview mode is responsible for upper line */
492 string fullname = string();
494 // make sure first three strips get cleared of view mode
499 fullname = _route->name();
503 if (fullname.length() <= 6) {
506 line1 = PBD::short_version (fullname, 6);
509 pending_display[0] = line1;
513 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
515 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
518 /* not in subview mode */
522 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
523 /* no longer in EQ subview mode */
527 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
533 float val = control->get_value();
534 do_parameter_display (type, control->internal_to_interface (val));
535 /* update pot/encoder */
536 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
541 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
543 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
546 /* not in subview mode */
550 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
551 /* no longer in EQ subview mode */
555 boost::shared_ptr<AutomationControl> control;
559 control = r->eq_gain_controllable (band);
562 control = r->eq_freq_controllable (band);
565 control = r->eq_q_controllable (band);
568 control = r->eq_shape_controllable (band);
571 control = r->eq_hpf_controllable ();
574 control = r->eq_enable_controllable ();
581 float val = control->get_value();
582 do_parameter_display (type, val);
583 /* update pot/encoder */
584 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
589 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
591 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
594 /* not in subview mode */
598 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
599 /* no longer in EQ subview mode */
603 boost::shared_ptr<AutomationControl> control;
604 bool reset_all = false;
608 control = r->comp_threshold_controllable ();
611 control = r->comp_speed_controllable ();
614 control = r->comp_mode_controllable ();
618 control = r->comp_makeup_controllable ();
621 control = r->comp_redux_controllable ();
624 control = r->comp_enable_controllable ();
630 if (propagate_mode && reset_all) {
631 _surface->subview_mode_changed ();
635 float val = control->get_value();
636 do_parameter_display (type, val);
637 /* update pot/encoder */
638 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
643 Strip::notify_panner_azi_changed (bool force_update)
649 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
651 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
657 Control* control = 0;
658 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
660 if (i == control_by_parameter.end()) {
666 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
667 double internal_pos = pan_control->get_value();
669 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
671 if (control == _fader) {
672 if (!_fader->in_use()) {
673 _surface->write (_fader->set_position (normalized_pos));
674 /* show actual internal value to user */
675 do_parameter_display (PanAzimuthAutomation, internal_pos);
677 } else if (control == _vpot) {
678 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
679 /* show actual internal value to user */
680 do_parameter_display (PanAzimuthAutomation, internal_pos);
683 _last_pan_azi_position_written = normalized_pos;
688 Strip::notify_panner_width_changed (bool force_update)
694 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
696 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
702 Control* control = 0;
703 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
705 if (i == control_by_parameter.end()) {
711 double pos = pan_control->internal_to_interface (pan_control->get_value());
713 if (force_update || pos != _last_pan_width_position_written) {
715 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
717 if (control == _fader) {
718 if (!control->in_use()) {
719 _surface->write (_fader->set_position (pos));
720 do_parameter_display (PanWidthAutomation, pos);
724 } else if (control == _vpot) {
725 _surface->write (_vpot->set (pos, true, Pot::spread));
726 do_parameter_display (PanWidthAutomation, pos);
729 _last_pan_width_position_written = pos;
734 Strip::select_event (Button&, ButtonState bs)
736 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
740 int ms = _surface->mcp().main_modifier_state();
742 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
743 _controls_locked = !_controls_locked;
744 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
745 block_vpot_mode_display_for (1000);
749 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
750 /* reset to default */
751 boost::shared_ptr<AutomationControl> ac = _fader->control ();
753 ac->set_value (ac->normal(), Controllable::NoGroup);
758 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
759 _surface->mcp().add_down_select_button (_surface->number(), _index);
760 _surface->mcp().select_range ();
763 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
764 _surface->mcp().remove_down_select_button (_surface->number(), _index);
769 Strip::vselect_event (Button&, ButtonState bs)
771 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
773 /* most subview modes: vpot press acts like a button for toggle parameters */
779 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
781 boost::shared_ptr<AutomationControl> control = _vpot->control ();
786 if (control->toggled()) {
787 if (control->toggled()) {
788 control->set_value (!control->get_value(), Controllable::NoGroup);
793 /* Send mode: press enables/disables the relevant send */
797 const uint32_t global_pos = _surface->mcp().global_index (*this);
798 boost::shared_ptr<AutomationControl> control = _route->send_enable_controllable (global_pos);
801 bool currently_enabled = (bool) control->get_value();
802 control->set_value (!currently_enabled, Controllable::UseGroup);
804 if (currently_enabled) {
805 /* we just turned it off */
806 pending_display[1] = "off";
808 /* we just turned it on, show the level
810 control = _route->send_level_controllable (global_pos);
811 do_parameter_display (BusSendLevel, control->get_value());
817 /* done with this event in subview mode */
824 int ms = _surface->mcp().main_modifier_state();
826 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
828 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
832 /* reset to default/normal value */
833 ac->set_value (ac->normal(), Controllable::NoGroup);
838 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
846 Strip::fader_touch_event (Button&, ButtonState bs)
848 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
852 boost::shared_ptr<AutomationControl> ac = _fader->control ();
854 _fader->set_in_use (true);
855 _fader->start_touch (_surface->mcp().transport_frame());
858 do_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
863 _fader->set_in_use (false);
864 _fader->stop_touch (_surface->mcp().transport_frame(), true);
871 Strip::handle_button (Button& button, ButtonState bs)
873 boost::shared_ptr<AutomationControl> control;
876 button.set_in_use (true);
878 button.set_in_use (false);
881 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
883 switch (button.bid()) {
885 select_event (button, bs);
888 case Button::VSelect:
889 vselect_event (button, bs);
892 case Button::FaderTouch:
893 fader_touch_event (button, bs);
897 if ((control = button.control ())) {
899 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
900 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
902 float new_value = control->get_value() ? 0.0 : 1.0;
904 /* get all controls that either have their
905 * button down or are within a range of
906 * several down buttons
909 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
912 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
913 controls.size(), control->parameter().type(), new_value));
915 /* apply change, with potential modifier semantics */
917 Controllable::GroupControlDisposition gcd;
919 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
920 gcd = Controllable::NoGroup;
922 gcd = Controllable::UseGroup;
925 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
926 (*c)->set_value (new_value, gcd);
930 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
931 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
939 Strip::do_parameter_display (AutomationType type, float val)
941 bool screen_hold = false;
947 pending_display[1] = " -inf ";
949 float dB = accurate_coefficient_to_dB (val);
950 snprintf (buf, sizeof (buf), "%6.1f", dB);
951 pending_display[1] = buf;
956 case PanAzimuthAutomation:
957 if (Profile->get_mixbus()) {
958 snprintf (buf, sizeof (buf), "%2.1f", val);
959 pending_display[1] = buf;
963 boost::shared_ptr<Pannable> p = _route->pannable();
964 if (p && _route->panner()) {
965 pending_display[1] =_route->panner()->value_as_string (p->pan_azimuth_control);
972 case PanWidthAutomation:
974 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
975 pending_display[1] = buf;
982 float dB = accurate_coefficient_to_dB (val);
983 snprintf (buf, sizeof (buf), "%6.1f", dB);
984 pending_display[1] = buf;
989 case PhaseAutomation:
991 if (_route->phase_control()->get_value() < 0.5) {
992 pending_display[1] = "Normal";
994 pending_display[1] = "Invert";
1002 float dB = accurate_coefficient_to_dB (val);
1003 snprintf (buf, sizeof (buf), "%6.1f", dB);
1004 pending_display[1] = buf;
1018 snprintf (buf, sizeof (buf), "%6.1f", val);
1019 pending_display[1] = buf;
1025 pending_display[1] = "on";
1027 pending_display[1] = "off";
1031 if (_surface->mcp().subview_route()) {
1032 pending_display[1] = _surface->mcp().subview_route()->comp_mode_name (val);
1040 /* we just queued up a parameter to be displayed.
1041 1 second from now, switch back to vpot mode display.
1043 block_vpot_mode_display_for (1000);
1048 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1051 fader.start_touch (_surface->mcp().transport_frame());
1053 fader.stop_touch (_surface->mcp().transport_frame(), false);
1058 Strip::handle_fader (Fader& fader, float position)
1060 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1061 boost::shared_ptr<AutomationControl> ac = fader.control();
1066 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1068 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1069 gcd = Controllable::NoGroup;
1072 fader.set_value (position, gcd);
1074 /* From the Mackie Control MIDI implementation docs:
1076 In order to ensure absolute synchronization with the host software,
1077 Mackie Control uses a closed-loop servo system for the faders,
1078 meaning the faders will always move to their last received position.
1079 When a host receives a Fader Position Message, it must then
1080 re-transmit that message to the Mackie Control or else the faders
1081 will return to their last position.
1084 _surface->write (fader.set_position (position));
1088 Strip::handle_pot (Pot& pot, float delta)
1090 /* Pots only emit events when they move, not when they
1091 stop moving. So to get a stop event, we need to use a timeout.
1094 boost::shared_ptr<AutomationControl> ac = pot.control();
1098 double p = pot.get_value ();
1100 // fader and pot should be the same and fader is hard coded 0 -> 1
1107 Strip::periodic (ARDOUR::microseconds_t now)
1110 update_automation ();
1114 Strip::redisplay (ARDOUR::microseconds_t now, bool force)
1116 if (_block_screen_redisplay_until >= now) {
1117 /* no drawing allowed */
1121 if (_block_screen_redisplay_until) {
1122 /* we were blocked, but the time period has elapsed, so we must
1126 _block_screen_redisplay_until = 0;
1129 if (force || (current_display[0] != pending_display[0])) {
1130 _surface->write (display (0, pending_display[0]));
1131 current_display[0] = pending_display[0];
1134 if (return_to_vpot_mode_display_at <= now) {
1135 return_to_vpot_mode_display_at = UINT64_MAX;
1136 return_to_vpot_mode_display ();
1139 if (force || (current_display[1] != pending_display[1])) {
1140 _surface->write (display (1, pending_display[1]));
1141 current_display[1] = pending_display[1];
1146 Strip::update_automation ()
1152 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1154 if (state == Touch || state == Play) {
1155 notify_gain_changed (false);
1158 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1160 state = pan_control->automation_state ();
1161 if (state == Touch || state == Play) {
1162 notify_panner_azi_changed (false);
1166 pan_control = _route->pan_width_control ();
1168 state = pan_control->automation_state ();
1169 if (state == Touch || state == Play) {
1170 notify_panner_width_changed (false);
1174 if (_route->trim() && route()->trim()->active()) {
1175 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1176 if (trim_state == Touch || trim_state == Play) {
1177 notify_trim_changed (false);
1183 Strip::update_meter ()
1189 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1193 if (_meter && _transport_is_rolling && _metering_active) {
1194 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1195 _meter->send_update (*_surface, dB);
1203 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1204 _surface->write ((*it)->zero ());
1207 _surface->write (blank_display (0));
1208 _surface->write (blank_display (1));
1209 pending_display[0] = string();
1210 pending_display[1] = string();
1211 current_display[0] = string();
1212 current_display[1] = string();
1216 Strip::blank_display (uint32_t line_number)
1218 return display (line_number, string());
1222 Strip::display (uint32_t line_number, const std::string& line)
1224 assert (line_number <= 1);
1226 MidiByteArray retval;
1228 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1231 retval << _surface->sysex_hdr();
1235 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1236 retval << (_index * 7 + (line_number * 0x38));
1238 // ascii data to display. @param line is UTF-8
1239 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1240 string::size_type len = ascii.length();
1242 ascii = ascii.substr (0, 6);
1246 // pad with " " out to 6 chars
1247 for (int i = len; i < 6; ++i) {
1251 // column spacer, unless it's the right-hand column
1257 retval << MIDI::eox;
1263 Strip::lock_controls ()
1265 _controls_locked = true;
1269 Strip::unlock_controls ()
1271 _controls_locked = false;
1275 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1277 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1278 if ((*i) == _route) {
1279 _surface->write (_select->set_state (on));
1284 _surface->write (_select->set_state (off));
1288 Strip::vpot_mode_string ()
1290 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1295 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1297 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1299 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1300 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1301 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1303 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1305 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1307 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1309 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1313 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1321 Strip::potmode_changed (bool notify)
1328 int pm = _surface->mcp().pot_mode();
1330 case MackieControlProtocol::Pan:
1331 // This needs to set current pan mode (azimuth or width... or whatever)
1332 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1333 set_vpot_parameter (_pan_mode);
1335 case MackieControlProtocol::Trim:
1336 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1337 set_vpot_parameter (_trim_mode);
1347 Strip::block_screen_display_for (uint32_t msecs)
1349 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1353 Strip::block_vpot_mode_display_for (uint32_t msecs)
1355 return_to_vpot_mode_display_at = ARDOUR::get_microseconds() + (msecs * 1000);
1359 Strip::return_to_vpot_mode_display ()
1361 /* returns the second line of the two-line per-strip display
1362 back the mode where it shows what the VPot controls.
1365 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1366 /* do nothing - second line shows value of current subview parameter */
1368 } else if (_route) {
1369 pending_display[1] = vpot_mode_string();
1371 pending_display[1] = string();
1376 Strip::next_pot_mode ()
1378 vector<AutomationType>::iterator i;
1380 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1381 /* do not change vpot mode while in flipped mode */
1382 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1383 pending_display[1] = "Flip";
1384 block_vpot_mode_display_for (1000);
1389 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1396 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1398 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1402 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1403 if ((*i) == ac->parameter().type()) {
1408 /* move to the next mode in the list, or back to the start (which will
1409 also happen if the current mode is not in the current pot mode list)
1412 if (i != possible_pot_parameters.end()) {
1416 if (i == possible_pot_parameters.end()) {
1417 i = possible_pot_parameters.begin();
1420 set_vpot_parameter (*i);
1421 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1422 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter().type())) {
1426 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1427 if ((*i) == ac->parameter().type()) {
1431 if ((*i) == PhaseAutomation && _route->phase_invert().size() > 1) {
1432 // There are more than one channel of phase
1433 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1434 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1435 set_vpot_parameter (*i);
1438 _route->phase_control()->set_channel(0);
1441 /* move to the next mode in the list, or back to the start (which will
1442 also happen if the current mode is not in the current pot mode list)
1445 if (i != possible_trim_parameters.end()) {
1449 if (i == possible_trim_parameters.end()) {
1450 i = possible_trim_parameters.begin();
1452 set_vpot_parameter (*i);
1457 Strip::subview_mode_changed ()
1459 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1461 subview_connections.drop_connections ();
1463 switch (_surface->mcp().subview_mode()) {
1464 case MackieControlProtocol::None:
1465 set_vpot_parameter (vpot_parameter);
1466 /* need to show strip name again */
1468 notify_metering_state_changed ();
1472 case MackieControlProtocol::EQ:
1476 /* leave it as it was */
1480 case MackieControlProtocol::Dynamics:
1484 /* leave it as it was */
1489 case MackieControlProtocol::Sends:
1491 setup_sends_vpot (r);
1493 /* leave it as it was */
1501 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1507 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1508 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1509 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1510 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1511 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1512 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1514 uint32_t pos = _surface->mcp().global_index (*this);
1516 /* we will control the pos-th available parameter, from the list in the
1517 * order shown above.
1520 vector<boost::shared_ptr<AutomationControl> > available;
1521 vector<AutomationType> params;
1523 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1524 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1525 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1526 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1527 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1528 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1530 if (pos >= available.size()) {
1531 /* this knob is not needed to control the available parameters */
1532 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1533 pending_display[0] = string();
1534 pending_display[1] = string();
1538 boost::shared_ptr<AutomationControl> pc;
1539 AutomationType param;
1541 pc = available[pos];
1542 param = params[pos];
1544 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1545 _vpot->set_control (pc);
1555 pot_id = r->comp_speed_name (mc->get_value());
1576 if (!pot_id.empty()) {
1577 pending_display[0] = pot_id;
1579 pending_display[0] = string();
1582 notify_dyn_change (param, true, false);
1586 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1588 uint32_t bands = r->eq_band_cnt ();
1591 /* should never get here */
1595 /* figure out how many params per band are available */
1597 boost::shared_ptr<AutomationControl> pc;
1598 uint32_t params_per_band = 0;
1600 if ((pc = r->eq_gain_controllable (0))) {
1601 params_per_band += 1;
1603 if ((pc = r->eq_freq_controllable (0))) {
1604 params_per_band += 1;
1606 if ((pc = r->eq_q_controllable (0))) {
1607 params_per_band += 1;
1609 if ((pc = r->eq_shape_controllable (0))) {
1610 params_per_band += 1;
1613 /* pick the one for this strip, based on its global position across
1619 const uint32_t total_band_parameters = bands * params_per_band;
1620 const uint32_t global_pos = _surface->mcp().global_index (*this);
1621 AutomationType param = NullAutomation;
1626 if (global_pos < total_band_parameters) {
1628 /* show a parameter for an EQ band */
1630 const uint32_t parameter = global_pos % params_per_band;
1631 eq_band = global_pos / params_per_band;
1632 band_name = r->eq_band_name (eq_band);
1634 switch (parameter) {
1636 pc = r->eq_gain_controllable (eq_band);
1640 pc = r->eq_freq_controllable (eq_band);
1641 param = EQFrequency;
1644 pc = r->eq_q_controllable (eq_band);
1648 pc = r->eq_shape_controllable (eq_band);
1655 /* show a non-band parameter (HPF or enable)
1658 uint32_t parameter = global_pos - total_band_parameters;
1660 switch (parameter) {
1661 case 0: /* first control after band parameters */
1662 pc = r->eq_hpf_controllable();
1665 case 1: /* second control after band parameters */
1666 pc = r->eq_enable_controllable();
1670 /* nothing to control */
1671 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1672 pending_display[0] = string();
1673 pending_display[1] = string();
1682 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1683 _vpot->set_control (pc);
1689 pot_id = band_name + "Gain";
1692 pot_id = band_name + "Freq";
1695 pot_id = band_name + " Q";
1698 pot_id = band_name + " Shp";
1710 if (!pot_id.empty()) {
1711 pending_display[0] = pot_id;
1713 pending_display[0] = string();
1716 notify_eq_change (param, eq_band, true);
1721 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1727 const uint32_t global_pos = _surface->mcp().global_index (*this);
1729 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1732 pending_display[0] = string();
1733 pending_display[1] = string();
1737 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1738 _vpot->set_control (pc);
1740 pending_display[0] = r->send_name (global_pos);
1742 notify_send_level_change (BusSendLevel, global_pos, true);
1746 Strip::set_vpot_parameter (AutomationType p)
1748 if (!_route || (p == NullAutomation)) {
1749 control_by_parameter[vpot_parameter] = 0;
1750 vpot_parameter = NullAutomation;
1751 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1752 pending_display[1] = string();
1756 boost::shared_ptr<AutomationControl> pan_control;
1758 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1760 reset_saved_values ();
1762 /* unset any mapping between the vpot and any existing parameters */
1764 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1766 if (i != control_by_parameter.end() && i->second == _vpot) {
1772 case PanAzimuthAutomation:
1773 if ((pan_control = _route->pan_azimuth_control ())) {
1774 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1775 _pan_mode = PanAzimuthAutomation;
1776 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1777 /* gain to vpot, pan azi to fader */
1778 _vpot->set_control (_route->gain_control());
1779 vpot_parameter = GainAutomation;
1780 control_by_parameter[GainAutomation] = _vpot;
1781 _fader->set_control (pan_control);
1782 control_by_parameter[PanAzimuthAutomation] = _fader;
1784 _fader->set_control (boost::shared_ptr<AutomationControl>());
1785 control_by_parameter[PanAzimuthAutomation] = 0;
1788 /* gain to fader, pan azi to vpot */
1789 vpot_parameter = PanAzimuthAutomation;
1790 _fader->set_control (_route->gain_control());
1791 control_by_parameter[GainAutomation] = _fader;
1792 _vpot->set_control (pan_control);
1793 control_by_parameter[PanAzimuthAutomation] = _vpot;
1796 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1797 control_by_parameter[PanAzimuthAutomation] = 0;
1801 case PanWidthAutomation:
1802 if ((pan_control = _route->pan_width_control ())) {
1803 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1804 _pan_mode = PanWidthAutomation;
1805 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1806 /* gain to vpot, pan width to fader */
1807 _vpot->set_control (_route->gain_control());
1808 vpot_parameter = GainAutomation;
1809 control_by_parameter[GainAutomation] = _vpot;
1810 _fader->set_control (pan_control);
1811 control_by_parameter[PanWidthAutomation] = _fader;
1813 _fader->set_control (boost::shared_ptr<AutomationControl>());
1814 control_by_parameter[PanWidthAutomation] = 0;
1817 /* gain to fader, pan width to vpot */
1818 vpot_parameter = PanWidthAutomation;
1819 _fader->set_control (_route->gain_control());
1820 control_by_parameter[GainAutomation] = _fader;
1821 _vpot->set_control (pan_control);
1822 control_by_parameter[PanWidthAutomation] = _vpot;
1825 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1826 control_by_parameter[PanWidthAutomation] = 0;
1830 case PanElevationAutomation:
1832 case PanFrontBackAutomation:
1834 case PanLFEAutomation:
1836 case TrimAutomation:
1837 _trim_mode = TrimAutomation;
1838 vpot_parameter = TrimAutomation;
1839 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1840 /* gain to vpot, trim to fader */
1841 _vpot->set_control (_route->gain_control());
1842 control_by_parameter[GainAutomation] = _vpot;
1843 if (_route->trim() && route()->trim()->active()) {
1844 _fader->set_control (_route->trim_control());
1845 control_by_parameter[TrimAutomation] = _fader;
1847 _fader->set_control (boost::shared_ptr<AutomationControl>());
1848 control_by_parameter[TrimAutomation] = 0;
1851 /* gain to fader, trim to vpot */
1852 _fader->set_control (_route->gain_control());
1853 control_by_parameter[GainAutomation] = _fader;
1854 if (_route->trim() && route()->trim()->active()) {
1855 _vpot->set_control (_route->trim_control());
1856 control_by_parameter[TrimAutomation] = _vpot;
1858 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1859 control_by_parameter[TrimAutomation] = 0;
1863 case PhaseAutomation:
1864 _trim_mode = PhaseAutomation;
1865 vpot_parameter = PhaseAutomation;
1866 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1867 /* gain to vpot, phase to fader */
1868 _vpot->set_control (_route->gain_control());
1869 control_by_parameter[GainAutomation] = _vpot;
1870 if (_route->phase_invert().size()) {
1871 _fader->set_control (_route->phase_control());
1872 control_by_parameter[PhaseAutomation] = _fader;
1874 _fader->set_control (boost::shared_ptr<AutomationControl>());
1875 control_by_parameter[PhaseAutomation] = 0;
1878 /* gain to fader, phase to vpot */
1879 _fader->set_control (_route->gain_control());
1880 control_by_parameter[GainAutomation] = _fader;
1881 if (_route->phase_invert().size()) {
1882 _vpot->set_control (_route->phase_control());
1883 control_by_parameter[PhaseAutomation] = _vpot;
1885 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1886 control_by_parameter[PhaseAutomation] = 0;
1891 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1896 pending_display[1] = vpot_mode_string ();
1900 Strip::is_midi_track () const
1902 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1906 Strip::reset_saved_values ()
1908 _last_pan_azi_position_written = -1.0;
1909 _last_pan_width_position_written = -1.0;
1910 _last_gain_position_written = -1.0;
1911 _last_trim_position_written = -1.0;
1916 Strip::notify_metering_state_changed()
1918 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1922 if (!_route || !_meter) {
1926 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1927 bool metering_active = _surface->mcp().metering_active ();
1929 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1933 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1935 if (!transport_is_rolling || !metering_active) {
1936 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1937 notify_panner_azi_changed (true);
1940 _transport_is_rolling = transport_is_rolling;
1941 _metering_active = metering_active;