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.
27 #include <glibmm/convert.h>
29 #include "midi++/port.h"
31 #include "pbd/compose.h"
32 #include "pbd/convert.h"
34 #include "ardour/amp.h"
35 #include "ardour/bundle.h"
36 #include "ardour/debug.h"
37 #include "ardour/midi_ui.h"
38 #include "ardour/meter.h"
39 #include "ardour/plugin_insert.h"
40 #include "ardour/pannable.h"
41 #include "ardour/panner.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/route.h"
45 #include "ardour/session.h"
46 #include "ardour/send.h"
47 #include "ardour/track.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/user_bundle.h"
50 #include "ardour/profile.h"
52 #include "mackie_control_protocol.h"
53 #include "surface_port.h"
64 using namespace ARDOUR;
66 using namespace ArdourSurface;
67 using namespace Mackie;
69 #ifndef timeradd /// only avail with __USE_BSD
70 #define timeradd(a,b,result) \
72 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
73 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
74 if ((result)->tv_usec >= 1000000) \
77 (result)->tv_usec -= 1000000; \
82 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
84 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
97 , _controls_locked (false)
98 , _transport_is_rolling (false)
99 , _metering_active (true)
100 , _block_vpot_mode_redisplay_until (0)
101 , _block_screen_redisplay_until (0)
103 , _pan_mode (PanAzimuthAutomation)
104 , _trim_mode (TrimAutomation)
105 , vpot_parameter (PanAzimuthAutomation)
106 , _last_gain_position_written (-1.0)
107 , _last_pan_azi_position_written (-1.0)
108 , _last_pan_width_position_written (-1.0)
109 , _last_trim_position_written (-1.0)
111 , redisplay_requests (256)
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);
381 if (force_update || normalized_position != _last_gain_position_written) {
383 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
384 if (!control->in_use()) {
385 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
387 queue_parameter_display (GainAutomation, gain_coefficient);
389 if (!control->in_use()) {
390 _surface->write (_fader->set_position (normalized_position));
392 queue_parameter_display (GainAutomation, gain_coefficient);
395 _last_gain_position_written = normalized_position;
401 Strip::notify_trim_changed (bool force_update)
405 if (!_route->trim() || !route()->trim()->active()) {
408 Control* control = 0;
409 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
411 if (i == control_by_parameter.end()) {
417 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
419 float gain_coefficient = ac->get_value();
420 float normalized_position = ac->internal_to_interface (gain_coefficient);
422 if (force_update || normalized_position != _last_trim_position_written) {
423 if (control == _fader) {
424 if (!_fader->in_use()) {
425 _surface->write (_fader->set_position (normalized_position));
426 queue_parameter_display (TrimAutomation, gain_coefficient);
428 } else if (control == _vpot) {
429 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
430 queue_parameter_display (TrimAutomation, gain_coefficient);
432 _last_trim_position_written = normalized_position;
438 Strip::notify_phase_changed (bool force_update)
441 if (!_route->phase_invert().size()) {
445 Control* control = 0;
446 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
448 if (i == control_by_parameter.end()) {
454 float normalized_position = _route->phase_control()->get_value();
456 if (control == _fader) {
457 if (!_fader->in_use()) {
458 _surface->write (_fader->set_position (normalized_position));
459 queue_parameter_display (PhaseAutomation, normalized_position);
461 } else if (control == _vpot) {
462 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
463 queue_parameter_display (PhaseAutomation, normalized_position);
469 Strip::notify_processor_changed (bool force_update)
474 Strip::notify_property_changed (const PropertyChange& what_changed)
476 if (!what_changed.contains (ARDOUR::Properties::name)) {
484 Strip::show_route_name ()
486 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
488 if (svm != MackieControlProtocol::None) {
489 /* subview mode is responsible for upper line */
493 string fullname = string();
495 // make sure first three strips get cleared of view mode
500 fullname = _route->name();
504 if (fullname.length() <= 6) {
507 line1 = PBD::short_version (fullname, 6);
510 _surface->write (display (0, line1));
514 Strip::notify_send_level_change (AutomationType type, uint32_t send_num, bool force_update)
516 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
519 /* not in subview mode */
523 if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
524 /* no longer in EQ subview mode */
528 boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
534 float val = control->get_value();
535 cerr << "Queue send level display of " << val << endl;
536 queue_parameter_display (type, val);
537 /* update pot/encoder */
538 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
543 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
545 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
548 /* not in subview mode */
552 if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
553 /* no longer in EQ subview mode */
557 boost::shared_ptr<AutomationControl> control;
561 control = r->eq_gain_controllable (band);
564 control = r->eq_freq_controllable (band);
567 control = r->eq_q_controllable (band);
570 control = r->eq_shape_controllable (band);
573 control = r->eq_hpf_controllable ();
576 control = r->eq_enable_controllable ();
583 float val = control->get_value();
584 queue_parameter_display (type, val);
585 /* update pot/encoder */
586 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
591 Strip::notify_dyn_change (AutomationType type, bool force_update, bool propagate_mode)
593 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
596 /* not in subview mode */
600 if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
601 /* no longer in EQ subview mode */
605 boost::shared_ptr<AutomationControl> control;
606 bool reset_all = false;
610 control = r->comp_threshold_controllable ();
613 control = r->comp_speed_controllable ();
616 control = r->comp_mode_controllable ();
620 control = r->comp_makeup_controllable ();
623 control = r->comp_redux_controllable ();
626 control = r->comp_enable_controllable ();
632 if (propagate_mode && reset_all) {
633 _surface->subview_mode_changed ();
637 float val = control->get_value();
638 queue_parameter_display (type, val);
639 /* update pot/encoder */
640 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
645 Strip::notify_panner_azi_changed (bool force_update)
651 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
653 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
659 Control* control = 0;
660 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
662 if (i == control_by_parameter.end()) {
668 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
669 double internal_pos = pan_control->get_value();
671 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
673 if (control == _fader) {
674 if (!_fader->in_use()) {
675 _surface->write (_fader->set_position (normalized_pos));
676 /* show actual internal value to user */
677 queue_parameter_display (PanAzimuthAutomation, internal_pos);
679 } else if (control == _vpot) {
680 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
681 /* show actual internal value to user */
682 queue_parameter_display (PanAzimuthAutomation, internal_pos);
685 _last_pan_azi_position_written = normalized_pos;
690 Strip::notify_panner_width_changed (bool force_update)
696 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
698 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
704 Control* control = 0;
705 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
707 if (i == control_by_parameter.end()) {
713 double pos = pan_control->internal_to_interface (pan_control->get_value());
715 if (force_update || pos != _last_pan_width_position_written) {
717 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
719 if (control == _fader) {
720 if (!control->in_use()) {
721 _surface->write (_fader->set_position (pos));
722 queue_parameter_display (PanWidthAutomation, pos);
726 } else if (control == _vpot) {
727 _surface->write (_vpot->set (pos, true, Pot::spread));
728 queue_parameter_display (PanWidthAutomation, pos);
731 _last_pan_width_position_written = pos;
736 Strip::select_event (Button&, ButtonState bs)
738 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
742 int ms = _surface->mcp().main_modifier_state();
744 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
745 _controls_locked = !_controls_locked;
746 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
747 block_vpot_mode_display_for (1000);
751 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
752 /* reset to default */
753 boost::shared_ptr<AutomationControl> ac = _fader->control ();
755 ac->set_value (ac->normal(), Controllable::NoGroup);
760 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
761 _surface->mcp().add_down_select_button (_surface->number(), _index);
762 _surface->mcp().select_range ();
765 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
766 _surface->mcp().remove_down_select_button (_surface->number(), _index);
771 Strip::vselect_event (Button&, ButtonState bs)
773 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
775 /* subview mode: vpot press acts like a button for toggle parameters */
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);
797 int ms = _surface->mcp().main_modifier_state();
799 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
801 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
805 /* reset to default/normal value */
806 ac->set_value (ac->normal(), Controllable::NoGroup);
811 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
819 Strip::fader_touch_event (Button&, ButtonState bs)
821 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
825 boost::shared_ptr<AutomationControl> ac = _fader->control ();
827 _fader->set_in_use (true);
828 _fader->start_touch (_surface->mcp().transport_frame());
831 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
836 _fader->set_in_use (false);
837 _fader->stop_touch (_surface->mcp().transport_frame(), true);
844 Strip::handle_button (Button& button, ButtonState bs)
846 boost::shared_ptr<AutomationControl> control;
849 button.set_in_use (true);
851 button.set_in_use (false);
854 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
856 switch (button.bid()) {
858 select_event (button, bs);
861 case Button::VSelect:
862 vselect_event (button, bs);
865 case Button::FaderTouch:
866 fader_touch_event (button, bs);
870 if ((control = button.control ())) {
872 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
873 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
875 float new_value = control->get_value() ? 0.0 : 1.0;
877 /* get all controls that either have their
878 * button down or are within a range of
879 * several down buttons
882 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
885 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
886 controls.size(), control->parameter().type(), new_value));
888 /* apply change, with potential modifier semantics */
890 Controllable::GroupControlDisposition gcd;
892 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
893 gcd = Controllable::NoGroup;
895 gcd = Controllable::UseGroup;
898 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
899 (*c)->set_value (new_value, gcd);
903 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
904 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
912 Strip::queue_parameter_display (AutomationType type, float val)
914 RedisplayRequest req;
919 redisplay_requests.write (&req, 1);
923 Strip::do_parameter_display (AutomationType type, float val)
925 bool screen_hold = false;
931 _surface->write (display (1, " -inf "));
933 float dB = accurate_coefficient_to_dB (val);
934 snprintf (buf, sizeof (buf), "%6.1f", dB);
935 _surface->write (display (1, buf));
940 case PanAzimuthAutomation:
941 if (Profile->get_mixbus()) {
942 snprintf (buf, sizeof (buf), "%2.1f", val);
943 _surface->write (display (1, buf));
947 boost::shared_ptr<Pannable> p = _route->pannable();
948 if (p && _route->panner()) {
949 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
950 _surface->write (display (1, str));
957 case PanWidthAutomation:
959 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
960 _surface->write (display (1, buf));
967 float dB = accurate_coefficient_to_dB (val);
968 snprintf (buf, sizeof (buf), "%6.1f", dB);
969 _surface->write (display (1, buf));
974 case PhaseAutomation:
976 if (_route->phase_control()->get_value() < 0.5) {
977 _surface->write (display (1, "Normal"));
979 _surface->write (display (1, "Invert"));
987 float dB = accurate_coefficient_to_dB (val);
988 snprintf (buf, sizeof (buf), "%6.1f", dB);
989 cerr << "send level write " << val << " as \"" << buf << '"' << endl;
990 _surface->write (display (1, buf));
1004 snprintf (buf, sizeof (buf), "%6.1f", val);
1005 _surface->write (display (1, buf));
1011 _surface->write (display (1, "on"));
1013 _surface->write (display (1, "off"));
1017 if (_surface->mcp().subview_route()) {
1018 _surface->write (display (1, _surface->mcp().subview_route()->comp_mode_name (val)));
1026 block_vpot_mode_display_for (1000);
1031 Strip::handle_fader_touch (Fader& fader, bool touch_on)
1034 fader.start_touch (_surface->mcp().transport_frame());
1036 fader.stop_touch (_surface->mcp().transport_frame(), false);
1041 Strip::handle_fader (Fader& fader, float position)
1043 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
1044 boost::shared_ptr<AutomationControl> ac = fader.control();
1049 Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
1051 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
1052 gcd = Controllable::NoGroup;
1055 fader.set_value (position, gcd);
1057 /* From the Mackie Control MIDI implementation docs:
1059 In order to ensure absolute synchronization with the host software,
1060 Mackie Control uses a closed-loop servo system for the faders,
1061 meaning the faders will always move to their last received position.
1062 When a host receives a Fader Position Message, it must then
1063 re-transmit that message to the Mackie Control or else the faders
1064 will return to their last position.
1067 _surface->write (fader.set_position (position));
1071 Strip::handle_pot (Pot& pot, float delta)
1073 /* Pots only emit events when they move, not when they
1074 stop moving. So to get a stop event, we need to use a timeout.
1077 boost::shared_ptr<AutomationControl> ac = pot.control();
1081 double p = pot.get_value ();
1083 // fader and pot should be the same and fader is hard coded 0 -> 1
1090 Strip::periodic (ARDOUR::microseconds_t now)
1092 bool reshow_vpot_mode = false;
1093 bool reshow_name = false;
1094 bool good_strip = true;
1097 // view mode may cover as many as 3 strips
1098 // needs to be cleared when there are less than 3 routes
1106 if (_block_screen_redisplay_until >= now) {
1107 if (_surface->mcp().device_info().has_separate_meters()) {
1110 /* no drawing here, for now */
1113 } else if (_block_screen_redisplay_until) {
1115 /* timeout reached, reset */
1117 _block_screen_redisplay_until = 0;
1118 reshow_vpot_mode = (true && good_strip);
1122 if (_block_vpot_mode_redisplay_until >= now) {
1124 } else if (_block_vpot_mode_redisplay_until) {
1126 /* timeout reached, reset */
1128 _block_vpot_mode_redisplay_until = 0;
1129 reshow_vpot_mode = (true && good_strip);
1136 if (reshow_vpot_mode) {
1137 return_to_vpot_mode_display ();
1138 } else if (good_strip) {
1139 /* no point doing this if we just switched back to vpot mode
1141 update_automation ();
1151 Strip::redisplay (ARDOUR::microseconds_t now)
1153 RedisplayRequest req;
1154 bool have_request = false;
1156 while (redisplay_requests.read (&req, 1) == 1) {
1158 have_request = true;
1161 if (_block_screen_redisplay_until >= now) {
1166 do_parameter_display (req.type, req.val);
1171 Strip::update_automation ()
1177 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1179 if (state == Touch || state == Play) {
1180 notify_gain_changed (false);
1183 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1185 state = pan_control->automation_state ();
1186 if (state == Touch || state == Play) {
1187 notify_panner_azi_changed (false);
1191 pan_control = _route->pan_width_control ();
1193 state = pan_control->automation_state ();
1194 if (state == Touch || state == Play) {
1195 notify_panner_width_changed (false);
1199 if (_route->trim() && route()->trim()->active()) {
1200 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1201 if (trim_state == Touch || trim_state == Play) {
1202 notify_trim_changed (false);
1208 Strip::update_meter ()
1210 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1214 if (_meter && _transport_is_rolling && _metering_active) {
1215 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1216 _meter->send_update (*_surface, dB);
1223 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1224 _surface->write ((*it)->zero ());
1227 _surface->write (blank_display (0));
1228 _surface->write (blank_display (1));
1232 Strip::blank_display (uint32_t line_number)
1234 return display (line_number, string());
1238 Strip::display (uint32_t line_number, const std::string& line)
1240 assert (line_number <= 1);
1242 MidiByteArray retval;
1244 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1247 retval << _surface->sysex_hdr();
1251 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1252 retval << (_index * 7 + (line_number * 0x38));
1254 // ascii data to display. @param line is UTF-8
1255 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1256 string::size_type len = ascii.length();
1258 ascii = ascii.substr (0, 6);
1262 // pad with " " out to 6 chars
1263 for (int i = len; i < 6; ++i) {
1267 // column spacer, unless it's the right-hand column
1273 retval << MIDI::eox;
1279 Strip::lock_controls ()
1281 _controls_locked = true;
1285 Strip::unlock_controls ()
1287 _controls_locked = false;
1291 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1293 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1294 if ((*i) == _route) {
1295 _surface->write (_select->set_state (on));
1300 _surface->write (_select->set_state (off));
1304 Strip::vpot_mode_string ()
1306 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1311 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1313 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1315 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1316 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1317 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1319 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1321 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1323 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1325 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1329 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1337 Strip::potmode_changed (bool notify)
1344 int pm = _surface->mcp().pot_mode();
1346 case MackieControlProtocol::Pan:
1347 // This needs to set current pan mode (azimuth or width... or whatever)
1348 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1349 set_vpot_parameter (_pan_mode);
1351 case MackieControlProtocol::Trim:
1352 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1353 set_vpot_parameter (_trim_mode);
1363 Strip::block_screen_display_for (uint32_t msecs)
1365 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1369 Strip::block_vpot_mode_display_for (uint32_t msecs)
1371 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1375 Strip::return_to_vpot_mode_display ()
1377 /* returns the second line of the two-line per-strip display
1378 back the mode where it shows what the VPot controls.
1381 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1382 /* do nothing - second line shows value of current subview parameter */
1384 } else if (_route) {
1385 _surface->write (display (1, vpot_mode_string()));
1387 _surface->write (blank_display (1));
1392 Strip::next_pot_mode ()
1394 vector<AutomationType>::iterator i;
1396 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1397 /* do not change vpot mode while in flipped mode */
1398 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1399 _surface->write (display (1, "Flip"));
1400 block_vpot_mode_display_for (1000);
1405 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1412 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1414 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
1418 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1419 if ((*i) == ac->parameter().type()) {
1424 /* move to the next mode in the list, or back to the start (which will
1425 also happen if the current mode is not in the current pot mode list)
1428 if (i != possible_pot_parameters.end()) {
1432 if (i == possible_pot_parameters.end()) {
1433 i = possible_pot_parameters.begin();
1436 set_vpot_parameter (*i);
1437 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1438 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter().type())) {
1442 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1443 if ((*i) == ac->parameter().type()) {
1447 if ((*i) == PhaseAutomation && _route->phase_invert().size() > 1) {
1448 // There are more than one channel of phase
1449 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1450 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1451 set_vpot_parameter (*i);
1454 _route->phase_control()->set_channel(0);
1457 /* move to the next mode in the list, or back to the start (which will
1458 also happen if the current mode is not in the current pot mode list)
1461 if (i != possible_trim_parameters.end()) {
1465 if (i == possible_trim_parameters.end()) {
1466 i = possible_trim_parameters.begin();
1468 set_vpot_parameter (*i);
1473 Strip::subview_mode_changed ()
1475 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1477 subview_connections.drop_connections ();
1479 switch (_surface->mcp().subview_mode()) {
1480 case MackieControlProtocol::None:
1481 set_vpot_parameter (vpot_parameter);
1482 notify_metering_state_changed ();
1486 case MackieControlProtocol::EQ:
1490 /* leave it as it was */
1494 case MackieControlProtocol::Dynamics:
1498 /* leave it as it was */
1503 case MackieControlProtocol::Sends:
1505 setup_sends_vpot (r);
1507 /* leave it as it was */
1515 Strip::setup_dyn_vpot (boost::shared_ptr<Route> r)
1521 boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
1522 boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
1523 boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
1524 boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
1525 boost::shared_ptr<AutomationControl> rc = r->comp_redux_controllable ();
1526 boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
1528 uint32_t pos = _surface->mcp().global_index (*this);
1530 /* we will control the pos-th available parameter, from the list in the
1531 * order shown above.
1534 vector<boost::shared_ptr<AutomationControl> > available;
1535 vector<AutomationType> params;
1537 if (tc) { available.push_back (tc); params.push_back (CompThreshold); }
1538 if (sc) { available.push_back (sc); params.push_back (CompSpeed); }
1539 if (mc) { available.push_back (mc); params.push_back (CompMode); }
1540 if (kc) { available.push_back (kc); params.push_back (CompMakeup); }
1541 if (rc) { available.push_back (rc); params.push_back (CompRedux); }
1542 if (ec) { available.push_back (ec); params.push_back (CompEnable); }
1544 if (pos >= available.size()) {
1545 /* this knob is not needed to control the available parameters */
1546 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1547 _surface->write (display (0, string()));
1548 _surface->write (display (1, string()));
1552 boost::shared_ptr<AutomationControl> pc;
1553 AutomationType param;
1555 pc = available[pos];
1556 param = params[pos];
1558 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, param, false, true), ui_context());
1559 _vpot->set_control (pc);
1569 pot_id = r->comp_speed_name (mc->get_value());
1590 if (!pot_id.empty()) {
1591 _surface->write (display (0, pot_id));
1594 notify_dyn_change (param, true, false);
1598 Strip::setup_eq_vpot (boost::shared_ptr<Route> r)
1600 uint32_t bands = r->eq_band_cnt ();
1603 /* should never get here */
1607 /* figure out how many params per band are available */
1609 boost::shared_ptr<AutomationControl> pc;
1610 uint32_t params_per_band = 0;
1612 if ((pc = r->eq_gain_controllable (0))) {
1613 params_per_band += 1;
1615 if ((pc = r->eq_freq_controllable (0))) {
1616 params_per_band += 1;
1618 if ((pc = r->eq_q_controllable (0))) {
1619 params_per_band += 1;
1621 if ((pc = r->eq_shape_controllable (0))) {
1622 params_per_band += 1;
1625 /* pick the one for this strip, based on its global position across
1631 const uint32_t total_band_parameters = bands * params_per_band;
1632 const uint32_t global_pos = _surface->mcp().global_index (*this);
1633 AutomationType param = NullAutomation;
1638 if (global_pos < total_band_parameters) {
1640 /* show a parameter for an EQ band */
1642 const uint32_t parameter = global_pos % params_per_band;
1643 eq_band = global_pos / params_per_band;
1644 band_name = r->eq_band_name (eq_band);
1646 switch (parameter) {
1648 pc = r->eq_gain_controllable (eq_band);
1652 pc = r->eq_freq_controllable (eq_band);
1653 param = EQFrequency;
1656 pc = r->eq_q_controllable (eq_band);
1660 pc = r->eq_shape_controllable (eq_band);
1667 /* show a non-band parameter (HPF or enable)
1670 uint32_t parameter = global_pos - total_band_parameters;
1672 switch (parameter) {
1673 case 0: /* first control after band parameters */
1674 pc = r->eq_hpf_controllable();
1677 case 1: /* second control after band parameters */
1678 pc = r->eq_enable_controllable();
1682 /* nothing to control */
1683 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1684 _surface->write (display (0, string()));
1685 _surface->write (display (1, string()));
1694 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1695 _vpot->set_control (pc);
1701 pot_id = band_name + "Gain";
1704 pot_id = band_name + "Freq";
1707 pot_id = band_name + " Q";
1710 pot_id = band_name + " Shp";
1722 if (!pot_id.empty()) {
1723 _surface->write (display (0, pot_id));
1726 notify_eq_change (param, eq_band, true);
1731 Strip::setup_sends_vpot (boost::shared_ptr<Route> r)
1737 const uint32_t global_pos = _surface->mcp().global_index (*this);
1739 boost::shared_ptr<Processor> send = r->nth_send (global_pos);
1742 _surface->write (display (0, string()));
1746 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
1752 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, BusSendLevel, global_pos, false), ui_context());
1753 _vpot->set_control (pc);
1755 cerr << "Send name @ " << global_pos << " = " << send->name() << endl;
1756 _surface->write (display (0, send->name()));
1758 notify_send_level_change (BusSendLevel, global_pos, true);
1762 Strip::set_vpot_parameter (AutomationType p)
1764 if (!_route || (p == NullAutomation)) {
1765 control_by_parameter[vpot_parameter] = 0;
1766 vpot_parameter = NullAutomation;
1767 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1768 _surface->write (display (1, string()));
1772 boost::shared_ptr<AutomationControl> pan_control;
1774 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1776 reset_saved_values ();
1778 /* unset any mapping between the vpot and any existing parameters */
1780 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1782 if (i != control_by_parameter.end() && i->second == _vpot) {
1788 case PanAzimuthAutomation:
1789 if ((pan_control = _route->pan_azimuth_control ())) {
1790 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1791 _pan_mode = PanAzimuthAutomation;
1792 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1793 /* gain to vpot, pan azi to fader */
1794 _vpot->set_control (_route->gain_control());
1795 vpot_parameter = GainAutomation;
1796 control_by_parameter[GainAutomation] = _vpot;
1797 _fader->set_control (pan_control);
1798 control_by_parameter[PanAzimuthAutomation] = _fader;
1800 _fader->set_control (boost::shared_ptr<AutomationControl>());
1801 control_by_parameter[PanAzimuthAutomation] = 0;
1804 /* gain to fader, pan azi to vpot */
1805 vpot_parameter = PanAzimuthAutomation;
1806 _fader->set_control (_route->gain_control());
1807 control_by_parameter[GainAutomation] = _fader;
1808 _vpot->set_control (pan_control);
1809 control_by_parameter[PanAzimuthAutomation] = _vpot;
1812 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1813 control_by_parameter[PanAzimuthAutomation] = 0;
1817 case PanWidthAutomation:
1818 if ((pan_control = _route->pan_width_control ())) {
1819 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1820 _pan_mode = PanWidthAutomation;
1821 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1822 /* gain to vpot, pan width to fader */
1823 _vpot->set_control (_route->gain_control());
1824 vpot_parameter = GainAutomation;
1825 control_by_parameter[GainAutomation] = _vpot;
1826 _fader->set_control (pan_control);
1827 control_by_parameter[PanWidthAutomation] = _fader;
1829 _fader->set_control (boost::shared_ptr<AutomationControl>());
1830 control_by_parameter[PanWidthAutomation] = 0;
1833 /* gain to fader, pan width to vpot */
1834 vpot_parameter = PanWidthAutomation;
1835 _fader->set_control (_route->gain_control());
1836 control_by_parameter[GainAutomation] = _fader;
1837 _vpot->set_control (pan_control);
1838 control_by_parameter[PanWidthAutomation] = _vpot;
1841 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1842 control_by_parameter[PanWidthAutomation] = 0;
1846 case PanElevationAutomation:
1848 case PanFrontBackAutomation:
1850 case PanLFEAutomation:
1852 case TrimAutomation:
1853 _trim_mode = TrimAutomation;
1854 vpot_parameter = TrimAutomation;
1855 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1856 /* gain to vpot, trim to fader */
1857 _vpot->set_control (_route->gain_control());
1858 control_by_parameter[GainAutomation] = _vpot;
1859 if (_route->trim() && route()->trim()->active()) {
1860 _fader->set_control (_route->trim_control());
1861 control_by_parameter[TrimAutomation] = _fader;
1863 _fader->set_control (boost::shared_ptr<AutomationControl>());
1864 control_by_parameter[TrimAutomation] = 0;
1867 /* gain to fader, trim to vpot */
1868 _fader->set_control (_route->gain_control());
1869 control_by_parameter[GainAutomation] = _fader;
1870 if (_route->trim() && route()->trim()->active()) {
1871 _vpot->set_control (_route->trim_control());
1872 control_by_parameter[TrimAutomation] = _vpot;
1874 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1875 control_by_parameter[TrimAutomation] = 0;
1879 case PhaseAutomation:
1880 _trim_mode = PhaseAutomation;
1881 vpot_parameter = PhaseAutomation;
1882 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1883 /* gain to vpot, phase to fader */
1884 _vpot->set_control (_route->gain_control());
1885 control_by_parameter[GainAutomation] = _vpot;
1886 if (_route->phase_invert().size()) {
1887 _fader->set_control (_route->phase_control());
1888 control_by_parameter[PhaseAutomation] = _fader;
1890 _fader->set_control (boost::shared_ptr<AutomationControl>());
1891 control_by_parameter[PhaseAutomation] = 0;
1894 /* gain to fader, phase to vpot */
1895 _fader->set_control (_route->gain_control());
1896 control_by_parameter[GainAutomation] = _fader;
1897 if (_route->phase_invert().size()) {
1898 _vpot->set_control (_route->phase_control());
1899 control_by_parameter[PhaseAutomation] = _vpot;
1901 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1902 control_by_parameter[PhaseAutomation] = 0;
1907 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1912 _surface->write (display (1, vpot_mode_string()));
1916 Strip::is_midi_track () const
1918 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1922 Strip::reset_saved_values ()
1924 _last_pan_azi_position_written = -1.0;
1925 _last_pan_width_position_written = -1.0;
1926 _last_gain_position_written = -1.0;
1927 _last_trim_position_written = -1.0;
1932 Strip::notify_metering_state_changed()
1934 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1938 if (!_route || !_meter) {
1942 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1943 bool metering_active = _surface->mcp().metering_active ();
1945 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1949 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1951 if (!transport_is_rolling || !metering_active) {
1952 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1953 notify_panner_azi_changed (true);
1956 _transport_is_rolling = transport_is_rolling;
1957 _metering_active = metering_active;