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.
26 #include <glibmm/convert.h>
28 #include "midi++/port.h"
30 #include "pbd/compose.h"
31 #include "pbd/convert.h"
33 #include "ardour/amp.h"
34 #include "ardour/bundle.h"
35 #include "ardour/debug.h"
36 #include "ardour/midi_ui.h"
37 #include "ardour/meter.h"
38 #include "ardour/plugin_insert.h"
39 #include "ardour/pannable.h"
40 #include "ardour/panner.h"
41 #include "ardour/panner_shell.h"
42 #include "ardour/rc_configuration.h"
43 #include "ardour/route.h"
44 #include "ardour/session.h"
45 #include "ardour/send.h"
46 #include "ardour/track.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/user_bundle.h"
49 #include "ardour/profile.h"
51 #include "mackie_control_protocol.h"
52 #include "surface_port.h"
62 using namespace ARDOUR;
64 using namespace ArdourSurface;
65 using namespace Mackie;
67 #ifndef timeradd /// only avail with __USE_BSD
68 #define timeradd(a,b,result) \
70 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
71 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
72 if ((result)->tv_usec >= 1000000) \
75 (result)->tv_usec -= 1000000; \
80 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
82 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
95 , _controls_locked (false)
96 , _transport_is_rolling (false)
97 , _metering_active (true)
98 , _block_vpot_mode_redisplay_until (0)
99 , _block_screen_redisplay_until (0)
101 , _pan_mode (PanAzimuthAutomation)
102 , _trim_mode (TrimAutomation)
103 , vpot_parameter (PanAzimuthAutomation)
104 , _last_gain_position_written (-1.0)
105 , _last_pan_azi_position_written (-1.0)
106 , _last_pan_width_position_written (-1.0)
107 , _last_trim_position_written (-1.0)
109 , redisplay_requests (256)
111 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
112 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
114 if (s.mcp().device_info().has_meters()) {
115 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
118 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
119 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
120 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
121 _surface->number(), index, Button::id_to_name (bb->bid()),
122 bb->id(), b->second.base_id));
128 /* surface is responsible for deleting all controls */
132 Strip::add (Control & control)
136 Group::add (control);
138 /* fader, vpot, meter were all set explicitly */
140 if ((button = dynamic_cast<Button*>(&control)) != 0) {
141 switch (button->bid()) {
142 case Button::RecEnable:
154 case Button::VSelect:
157 case Button::FaderTouch:
158 _fader_touch = button;
167 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
169 if (_controls_locked) {
173 mb_pan_controllable.reset();
175 route_connections.drop_connections ();
177 _solo->set_control (boost::shared_ptr<AutomationControl>());
178 _mute->set_control (boost::shared_ptr<AutomationControl>());
179 _select->set_control (boost::shared_ptr<AutomationControl>());
180 _recenable->set_control (boost::shared_ptr<AutomationControl>());
181 _fader->set_control (boost::shared_ptr<AutomationControl>());
182 _vpot->set_control (boost::shared_ptr<AutomationControl>());
186 control_by_parameter.clear ();
188 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
189 control_by_parameter[PanWidthAutomation] = (Control*) 0;
190 control_by_parameter[PanElevationAutomation] = (Control*) 0;
191 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
192 control_by_parameter[PanLFEAutomation] = (Control*) 0;
193 control_by_parameter[GainAutomation] = (Control*) 0;
194 control_by_parameter[TrimAutomation] = (Control*) 0;
195 control_by_parameter[PhaseAutomation] = (Control*) 0;
196 control_by_parameter[SendAutomation] = (Control*) 0;
198 reset_saved_values ();
205 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
206 _surface->number(), _index, _route->name()));
208 _solo->set_control (_route->solo_control());
209 _mute->set_control (_route->mute_control());
211 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
212 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
214 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
216 if (_route->trim() && route()->trim()->active()) {
217 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
220 if (_route->phase_invert().size()) {
221 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
222 _route->phase_control()->set_channel(0);
225 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control();
227 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
230 pan_control = _route->pan_width_control();
232 pan_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
235 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
236 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
238 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
241 _recenable->set_control (trk->rec_enable_control());
242 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
245 // TODO this works when a currently-banked route is made inactive, but not
246 // when a route is activated which should be currently banked.
248 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
249 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
251 /* setup legal VPot modes for this route */
253 possible_pot_parameters.clear();
255 if (_route->pan_azimuth_control()) {
256 possible_pot_parameters.push_back (PanAzimuthAutomation);
258 if (_route->pan_width_control()) {
259 possible_pot_parameters.push_back (PanWidthAutomation);
261 if (_route->pan_elevation_control()) {
262 possible_pot_parameters.push_back (PanElevationAutomation);
264 if (_route->pan_frontback_control()) {
265 possible_pot_parameters.push_back (PanFrontBackAutomation);
267 if (_route->pan_lfe_control()) {
268 possible_pot_parameters.push_back (PanLFEAutomation);
271 if (_route->trim() && route()->trim()->active()) {
272 possible_pot_parameters.push_back (TrimAutomation);
275 possible_trim_parameters.clear();
277 if (_route->trim() && route()->trim()->active()) {
278 possible_trim_parameters.push_back (TrimAutomation);
279 _trim_mode = TrimAutomation;
282 if (_route->phase_invert().size()) {
283 possible_trim_parameters.push_back (PhaseAutomation);
284 _route->phase_control()->set_channel(0);
285 if (_trim_mode != TrimAutomation) {
286 _trim_mode = PhaseAutomation;
291 _pan_mode = PanAzimuthAutomation;
292 potmode_changed (false);
305 notify_solo_changed ();
306 notify_mute_changed ();
307 notify_gain_changed ();
308 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
309 notify_panner_azi_changed ();
310 notify_panner_width_changed ();
311 notify_record_enable_changed ();
312 notify_trim_changed ();
313 notify_phase_changed ();
314 notify_processor_changed ();
318 Strip::notify_solo_changed ()
320 if (_route && _solo) {
321 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
326 Strip::notify_mute_changed ()
328 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
329 if (_route && _mute) {
330 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
331 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
333 _surface->write (_mute->set_state (_route->muted() ? on : off));
338 Strip::notify_record_enable_changed ()
340 if (_route && _recenable) {
341 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
346 Strip::notify_active_changed ()
348 _surface->mcp().refresh_current_bank();
352 Strip::notify_route_deleted ()
354 _surface->mcp().refresh_current_bank();
358 Strip::notify_gain_changed (bool force_update)
364 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
370 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
372 float gain_coefficient = ac->get_value();
373 float normalized_position = ac->internal_to_interface (gain_coefficient);
376 if (force_update || normalized_position != _last_gain_position_written) {
378 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
379 if (!control->in_use()) {
380 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
382 queue_parameter_display (GainAutomation, gain_coefficient);
384 if (!control->in_use()) {
385 _surface->write (_fader->set_position (normalized_position));
387 queue_parameter_display (GainAutomation, gain_coefficient);
390 _last_gain_position_written = normalized_position;
396 Strip::notify_trim_changed (bool force_update)
400 if (!_route->trim() || !route()->trim()->active()) {
401 _surface->write (_vpot->zero());
404 Control* control = 0;
405 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
407 if (i == control_by_parameter.end()) {
413 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
415 float gain_coefficient = ac->get_value();
416 float normalized_position = ac->internal_to_interface (gain_coefficient);
418 if (force_update || normalized_position != _last_trim_position_written) {
419 if (control == _fader) {
420 if (!_fader->in_use()) {
421 _surface->write (_fader->set_position (normalized_position));
422 queue_parameter_display (TrimAutomation, gain_coefficient);
424 } else if (control == _vpot) {
425 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
426 queue_parameter_display (TrimAutomation, gain_coefficient);
428 _last_trim_position_written = normalized_position;
434 Strip::notify_phase_changed (bool force_update)
437 if (!_route->phase_invert().size()) {
438 _surface->write (_vpot->zero());
442 Control* control = 0;
443 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
445 if (i == control_by_parameter.end()) {
451 float normalized_position = _route->phase_control()->get_value();
453 if (control == _fader) {
454 if (!_fader->in_use()) {
455 _surface->write (_fader->set_position (normalized_position));
456 queue_parameter_display (PhaseAutomation, normalized_position);
458 } else if (control == _vpot) {
459 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
460 queue_parameter_display (PhaseAutomation, normalized_position);
466 Strip::notify_processor_changed (bool force_update)
469 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
471 _surface->write (_vpot->zero());
475 Control* control = 0;
476 ControlParameterMap::iterator i = control_by_parameter.find (SendAutomation);
478 if (i == control_by_parameter.end()) {
484 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
485 boost::shared_ptr<Amp> a = s->amp();
486 boost::shared_ptr<AutomationControl> ac = a->gain_control();
488 float gain_coefficient = ac->get_value();
489 float normalized_position = ac->internal_to_interface (gain_coefficient);
491 if (control == _fader) {
492 if (!_fader->in_use()) {
493 _surface->write (_fader->set_position (normalized_position));
494 queue_parameter_display (SendAutomation, gain_coefficient);
496 } else if (control == _vpot) {
497 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
498 queue_parameter_display (SendAutomation, gain_coefficient);
504 Strip::notify_property_changed (const PropertyChange& what_changed)
506 if (!what_changed.contains (ARDOUR::Properties::name)) {
514 Strip::show_route_name ()
516 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
518 if (svm != MackieControlProtocol::None) {
519 /* subview mode is responsible for upper line */
527 string fullname = _route->name();
529 if (fullname.length() <= 6) {
532 line1 = PBD::short_version (fullname, 6);
535 _surface->write (display (0, line1));
539 Strip::notify_eq_change (AutomationType type, uint32_t band, bool force_update)
541 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
544 /* not in subview mode */
548 if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
549 /* no longer in EQ subview mode */
553 boost::shared_ptr<AutomationControl> control;
557 control = r->eq_gain_controllable (band);
560 control = r->eq_freq_controllable (band);
563 control = r->eq_q_controllable (band);
566 control = r->eq_shape_controllable (band);
569 control = r->eq_hpf_controllable ();
572 control = r->eq_enable_controllable ();
579 float val = control->get_value();
580 queue_parameter_display (type, val);
581 /* update pot/encoder */
582 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
587 Strip::notify_panner_azi_changed (bool force_update)
593 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
595 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
598 _surface->write (_vpot->zero());
602 Control* control = 0;
603 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
605 if (i == control_by_parameter.end()) {
611 double normalized_pos = pan_control->internal_to_interface (pan_control->get_value());
612 double internal_pos = pan_control->get_value();
614 if (force_update || (normalized_pos != _last_pan_azi_position_written)) {
616 if (control == _fader) {
617 if (!_fader->in_use()) {
618 _surface->write (_fader->set_position (normalized_pos));
619 /* show actual internal value to user */
620 queue_parameter_display (PanAzimuthAutomation, internal_pos);
622 } else if (control == _vpot) {
623 _surface->write (_vpot->set (normalized_pos, true, Pot::dot));
624 /* show actual internal value to user */
625 queue_parameter_display (PanAzimuthAutomation, internal_pos);
628 _last_pan_azi_position_written = normalized_pos;
633 Strip::notify_panner_width_changed (bool force_update)
639 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
641 boost::shared_ptr<AutomationControl> pan_control = _route->pan_width_control ();
644 _surface->write (_vpot->zero());
648 Control* control = 0;
649 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
651 if (i == control_by_parameter.end()) {
657 double pos = pan_control->internal_to_interface (pan_control->get_value());
659 if (force_update || pos != _last_pan_width_position_written) {
661 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
663 if (control == _fader) {
664 if (!control->in_use()) {
665 _surface->write (_fader->set_position (pos));
666 queue_parameter_display (PanWidthAutomation, pos);
670 } else if (control == _vpot) {
671 _surface->write (_vpot->set (pos, true, Pot::spread));
672 queue_parameter_display (PanWidthAutomation, pos);
675 _last_pan_width_position_written = pos;
680 Strip::select_event (Button&, ButtonState bs)
682 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
686 int ms = _surface->mcp().main_modifier_state();
688 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
689 _controls_locked = !_controls_locked;
690 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
691 block_vpot_mode_display_for (1000);
695 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
696 /* reset to default */
697 boost::shared_ptr<AutomationControl> ac = _fader->control ();
699 ac->set_value (ac->normal());
704 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
705 _surface->mcp().add_down_select_button (_surface->number(), _index);
706 _surface->mcp().select_range ();
709 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
710 _surface->mcp().remove_down_select_button (_surface->number(), _index);
715 Strip::vselect_event (Button&, ButtonState bs)
719 int ms = _surface->mcp().main_modifier_state();
721 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
723 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
727 /* reset to default/normal value */
728 ac->set_value (ac->normal());
733 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
741 Strip::fader_touch_event (Button&, ButtonState bs)
743 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
747 boost::shared_ptr<AutomationControl> ac = _fader->control ();
749 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
751 ac->set_value (ac->normal());
755 _fader->set_in_use (true);
756 _fader->start_touch (_surface->mcp().transport_frame());
759 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
765 _fader->set_in_use (false);
766 _fader->stop_touch (_surface->mcp().transport_frame(), true);
773 Strip::handle_button (Button& button, ButtonState bs)
775 boost::shared_ptr<AutomationControl> control;
778 button.set_in_use (true);
780 button.set_in_use (false);
783 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
785 switch (button.bid()) {
787 select_event (button, bs);
790 case Button::VSelect:
791 vselect_event (button, bs);
794 case Button::FaderTouch:
795 fader_touch_event (button, bs);
799 if ((control = button.control ())) {
801 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
802 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
805 int ms = _surface->mcp().main_modifier_state();
807 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
808 /* reset to default/normal value */
809 new_value = control->normal();
811 new_value = control->get_value() ? 0.0 : 1.0;
814 /* get all controls that either have their
815 * button down or are within a range of
816 * several down buttons
819 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
822 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
823 controls.size(), control->parameter().type(), new_value));
827 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
828 (*c)->set_value (new_value);
832 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
833 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
841 Strip::queue_parameter_display (AutomationType type, float val)
843 RedisplayRequest req;
848 redisplay_requests.write (&req, 1);
852 Strip::do_parameter_display (AutomationType type, float val)
854 bool screen_hold = false;
860 _surface->write (display (1, " -inf "));
862 float dB = accurate_coefficient_to_dB (val);
863 snprintf (buf, sizeof (buf), "%6.1f", dB);
864 _surface->write (display (1, buf));
869 case PanAzimuthAutomation:
870 if (Profile->get_mixbus()) {
871 snprintf (buf, sizeof (buf), "%2.1f", val);
872 _surface->write (display (1, buf));
876 boost::shared_ptr<Pannable> p = _route->pannable();
877 if (p && _route->panner()) {
878 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
879 _surface->write (display (1, str));
886 case PanWidthAutomation:
888 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
889 _surface->write (display (1, buf));
896 float dB = accurate_coefficient_to_dB (val);
897 snprintf (buf, sizeof (buf), "%6.1f", dB);
898 _surface->write (display (1, buf));
903 case PhaseAutomation:
905 if (_route->phase_control()->get_value() < 0.5) {
906 _surface->write (display (1, "Normal"));
908 _surface->write (display (1, "Invert"));
916 _surface->write (display (1, " -inf "));
918 float dB = accurate_coefficient_to_dB (val);
919 snprintf (buf, sizeof (buf), "%6.1f", dB);
920 _surface->write (display (1, buf));
929 snprintf (buf, sizeof (buf), "%6.1f", val);
930 _surface->write (display (1, buf));
935 _surface->write (display (1, "on"));
937 _surface->write (display (1, "off"));
945 block_vpot_mode_display_for (1000);
950 Strip::handle_fader_touch (Fader& fader, bool touch_on)
953 fader.start_touch (_surface->mcp().transport_frame());
955 fader.stop_touch (_surface->mcp().transport_frame(), false);
960 Strip::handle_fader (Fader& fader, float position)
962 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
963 boost::shared_ptr<AutomationControl> ac = fader.control();
968 fader.set_value (position);
970 /* From the Mackie Control MIDI implementation docs:
972 In order to ensure absolute synchronization with the host software,
973 Mackie Control uses a closed-loop servo system for the faders,
974 meaning the faders will always move to their last received position.
975 When a host receives a Fader Position Message, it must then
976 re-transmit that message to the Mackie Control or else the faders
977 will return to their last position.
980 _surface->write (fader.set_position (position));
984 Strip::handle_pot (Pot& pot, float delta)
986 /* Pots only emit events when they move, not when they
987 stop moving. So to get a stop event, we need to use a timeout.
990 boost::shared_ptr<AutomationControl> ac = pot.control();
994 double p = pot.get_value ();
996 // fader and pot should be the same and fader is hard coded 0 -> 1
1003 Strip::periodic (ARDOUR::microseconds_t now)
1005 bool reshow_vpot_mode = false;
1006 bool reshow_name = false;
1012 if (_block_screen_redisplay_until >= now) {
1013 if (_surface->mcp().device_info().has_separate_meters()) {
1016 /* no drawing here, for now */
1019 } else if (_block_screen_redisplay_until) {
1021 /* timeout reached, reset */
1023 _block_screen_redisplay_until = 0;
1024 reshow_vpot_mode = true;
1028 if (_block_vpot_mode_redisplay_until >= now) {
1030 } else if (_block_vpot_mode_redisplay_until) {
1032 /* timeout reached, reset */
1034 _block_vpot_mode_redisplay_until = 0;
1035 reshow_vpot_mode = true;
1042 if (reshow_vpot_mode) {
1043 return_to_vpot_mode_display ();
1045 /* no point doing this if we just switched back to vpot mode
1047 update_automation ();
1055 Strip::redisplay (ARDOUR::microseconds_t now)
1057 RedisplayRequest req;
1058 bool have_request = false;
1060 while (redisplay_requests.read (&req, 1) == 1) {
1062 have_request = true;
1065 if (_block_screen_redisplay_until >= now) {
1070 do_parameter_display (req.type, req.val);
1075 Strip::update_automation ()
1081 ARDOUR::AutoState state = _route->gain_control()->automation_state();
1083 if (state == Touch || state == Play) {
1084 notify_gain_changed (false);
1087 boost::shared_ptr<AutomationControl> pan_control = _route->pan_azimuth_control ();
1089 state = pan_control->automation_state ();
1090 if (state == Touch || state == Play) {
1091 notify_panner_azi_changed (false);
1095 pan_control = _route->pan_width_control ();
1097 state = pan_control->automation_state ();
1098 if (state == Touch || state == Play) {
1099 notify_panner_width_changed (false);
1103 if (_route->trim() && route()->trim()->active()) {
1104 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1105 if (trim_state == Touch || trim_state == Play) {
1106 notify_trim_changed (false);
1112 Strip::update_meter ()
1114 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1118 if (_meter && _transport_is_rolling && _metering_active) {
1119 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1120 _meter->send_update (*_surface, dB);
1127 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1128 _surface->write ((*it)->zero ());
1131 _surface->write (blank_display (0));
1132 _surface->write (blank_display (1));
1136 Strip::blank_display (uint32_t line_number)
1138 return display (line_number, string());
1142 Strip::display (uint32_t line_number, const std::string& line)
1144 assert (line_number <= 1);
1146 MidiByteArray retval;
1148 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1151 retval << _surface->sysex_hdr();
1155 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1156 retval << (_index * 7 + (line_number * 0x38));
1158 // ascii data to display. @param line is UTF-8
1159 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1160 string::size_type len = ascii.length();
1162 ascii = ascii.substr (0, 6);
1166 // pad with " " out to 6 chars
1167 for (int i = len; i < 6; ++i) {
1171 // column spacer, unless it's the right-hand column
1177 retval << MIDI::eox;
1183 Strip::lock_controls ()
1185 _controls_locked = true;
1189 Strip::unlock_controls ()
1191 _controls_locked = false;
1195 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1197 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1198 if ((*i) == _route) {
1199 _surface->write (_select->set_state (on));
1204 _surface->write (_select->set_state (off));
1208 Strip::vpot_mode_string ()
1210 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1215 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1217 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1219 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1220 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1221 } else if (control_by_parameter.find (SendAutomation)->second == _vpot) {
1222 // should be bus name
1223 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1227 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1229 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1231 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1233 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1235 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1239 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1247 Strip::potmode_changed (bool notify)
1254 int pm = _surface->mcp().pot_mode();
1256 case MackieControlProtocol::Pan:
1257 // This needs to set current pan mode (azimuth or width... or whatever)
1258 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1259 set_vpot_parameter (_pan_mode);
1261 case MackieControlProtocol::Trim:
1262 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1263 set_vpot_parameter (_trim_mode);
1265 case MackieControlProtocol::Send:
1266 // _current_send has the number of the send we will show
1267 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1268 set_vpot_parameter (SendAutomation);
1278 Strip::block_screen_display_for (uint32_t msecs)
1280 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1284 Strip::block_vpot_mode_display_for (uint32_t msecs)
1286 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1290 Strip::return_to_vpot_mode_display ()
1292 /* returns the second line of the two-line per-strip display
1293 back the mode where it shows what the VPot controls.
1296 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1297 /* do nothing - second line shows value of current subview parameter */
1299 } else if (_route) {
1300 _surface->write (display (1, vpot_mode_string()));
1302 _surface->write (blank_display (1));
1307 Strip::next_pot_mode ()
1309 vector<AutomationType>::iterator i;
1311 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1312 /* do not change vpot mode while in flipped mode */
1313 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1314 _surface->write (display (1, "Flip"));
1315 block_vpot_mode_display_for (1000);
1320 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1325 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1326 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1330 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1331 if ((*i) == ac->parameter()) {
1336 /* move to the next mode in the list, or back to the start (which will
1337 also happen if the current mode is not in the current pot mode list)
1340 if (i != possible_pot_parameters.end()) {
1344 if (i == possible_pot_parameters.end()) {
1345 i = possible_pot_parameters.begin();
1347 set_vpot_parameter (*i);
1348 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1349 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1353 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1354 if ((*i) == ac->parameter()) {
1358 if ((*i) == PhaseAutomation && _route->phase_invert().size() > 1) {
1359 // There are more than one channel of phase
1360 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1361 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1362 set_vpot_parameter (*i);
1365 _route->phase_control()->set_channel(0);
1368 /* move to the next mode in the list, or back to the start (which will
1369 also happen if the current mode is not in the current pot mode list)
1372 if (i != possible_trim_parameters.end()) {
1376 if (i == possible_trim_parameters.end()) {
1377 i = possible_trim_parameters.begin();
1379 set_vpot_parameter (*i);
1380 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Send) {
1381 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1385 p = _route->nth_send (_current_send + 1);
1386 if (p && p->name() != "Monitor 1") {
1391 set_vpot_parameter (SendAutomation);
1396 Strip::subview_mode_changed ()
1398 boost::shared_ptr<Route> r = _surface->mcp().subview_route();
1400 subview_connections.drop_connections ();
1402 switch (_surface->mcp().subview_mode()) {
1403 case MackieControlProtocol::None:
1404 set_vpot_parameter (vpot_parameter);
1405 notify_metering_state_changed ();
1409 case MackieControlProtocol::EQ:
1413 case MackieControlProtocol::Dynamics:
1419 Strip::setup_eq_vpots (boost::shared_ptr<Route> r)
1421 uint32_t bands = r->eq_band_cnt ();
1424 /* should never get here */
1428 /* figure out how many params per band are available */
1430 boost::shared_ptr<AutomationControl> pc;
1431 uint32_t params_per_band = 0;
1433 if ((pc = r->eq_gain_controllable (0))) {
1434 params_per_band += 1;
1436 if ((pc = r->eq_freq_controllable (0))) {
1437 params_per_band += 1;
1439 if ((pc = r->eq_q_controllable (0))) {
1440 params_per_band += 1;
1442 if ((pc = r->eq_shape_controllable (0))) {
1443 params_per_band += 1;
1446 /* pick the one for this strip, based on its global position across
1452 const uint32_t total_band_parameters = bands * params_per_band;
1453 const uint32_t global_pos = _surface->mcp().global_index (*this);
1454 AutomationType param = NullAutomation;
1459 if (global_pos < total_band_parameters) {
1461 /* show a parameter for an EQ band */
1463 const uint32_t parameter = global_pos % params_per_band;
1464 eq_band = global_pos / params_per_band;
1465 band_name = r->eq_band_name (eq_band);
1467 switch (parameter) {
1469 pc = r->eq_gain_controllable (eq_band);
1473 pc = r->eq_freq_controllable (eq_band);
1474 param = EQFrequency;
1477 pc = r->eq_q_controllable (eq_band);
1481 pc = r->eq_shape_controllable (eq_band);
1488 /* show a non-band parameter (HPF or enable)
1491 uint32_t parameter = global_pos - total_band_parameters;
1493 switch (parameter) {
1494 case 0: /* first control after band parameters */
1495 pc = r->eq_hpf_controllable();
1498 case 1: /* second control after band parameters */
1499 pc = r->eq_enable_controllable();
1503 /* nothing to control */
1504 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1505 _surface->write (display (0, string()));
1506 _surface->write (display (1, string()));
1515 pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, eq_band, false), ui_context());
1516 _vpot->set_control (pc);
1522 pot_id = band_name + "Gain";
1525 pot_id = band_name + "Freq";
1528 pot_id = band_name + " Q";
1531 pot_id = band_name + " Shp";
1543 if (!pot_id.empty()) {
1544 _surface->write (display (0, pot_id));
1547 notify_eq_change (param, eq_band, true);
1552 Strip::set_vpot_parameter (AutomationType p)
1554 if (!_route || (p == NullAutomation)) {
1555 control_by_parameter[vpot_parameter] = 0;
1556 vpot_parameter = NullAutomation;
1557 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1558 _surface->write (display (1, string()));
1562 boost::shared_ptr<AutomationControl> pan_control;
1564 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
1566 reset_saved_values ();
1568 /* unset any mapping between the vpot and any existing parameters */
1570 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1572 if (i != control_by_parameter.end() && i->second == _vpot) {
1578 case PanAzimuthAutomation:
1579 if ((pan_control = _route->pan_azimuth_control ())) {
1580 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1581 _pan_mode = PanAzimuthAutomation;
1582 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1583 /* gain to vpot, pan azi to fader */
1584 _vpot->set_control (_route->group_gain_control());
1585 vpot_parameter = GainAutomation;
1586 control_by_parameter[GainAutomation] = _vpot;
1587 _fader->set_control (pan_control);
1588 control_by_parameter[PanAzimuthAutomation] = _fader;
1590 _fader->set_control (boost::shared_ptr<AutomationControl>());
1591 control_by_parameter[PanAzimuthAutomation] = 0;
1594 /* gain to fader, pan azi to vpot */
1595 vpot_parameter = PanAzimuthAutomation;
1596 _fader->set_control (_route->group_gain_control());
1597 control_by_parameter[GainAutomation] = _fader;
1598 _vpot->set_control (pan_control);
1599 control_by_parameter[PanAzimuthAutomation] = _vpot;
1602 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1603 control_by_parameter[PanAzimuthAutomation] = 0;
1607 case PanWidthAutomation:
1608 if ((pan_control = _route->pan_width_control ())) {
1609 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1610 _pan_mode = PanWidthAutomation;
1611 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1612 /* gain to vpot, pan width to fader */
1613 _vpot->set_control (_route->group_gain_control());
1614 vpot_parameter = GainAutomation;
1615 control_by_parameter[GainAutomation] = _vpot;
1616 _fader->set_control (pan_control);
1617 control_by_parameter[PanWidthAutomation] = _fader;
1619 _fader->set_control (boost::shared_ptr<AutomationControl>());
1620 control_by_parameter[PanWidthAutomation] = 0;
1623 /* gain to fader, pan width to vpot */
1624 vpot_parameter = PanWidthAutomation;
1625 _fader->set_control (_route->group_gain_control());
1626 control_by_parameter[GainAutomation] = _fader;
1627 _vpot->set_control (pan_control);
1628 control_by_parameter[PanWidthAutomation] = _vpot;
1631 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1632 control_by_parameter[PanWidthAutomation] = 0;
1636 case PanElevationAutomation:
1638 case PanFrontBackAutomation:
1640 case PanLFEAutomation:
1642 case TrimAutomation:
1643 _trim_mode = TrimAutomation;
1644 vpot_parameter = TrimAutomation;
1645 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1646 /* gain to vpot, trim to fader */
1647 _vpot->set_control (_route->group_gain_control());
1648 control_by_parameter[GainAutomation] = _vpot;
1649 if (_route->trim() && route()->trim()->active()) {
1650 _fader->set_control (_route->trim_control());
1651 control_by_parameter[TrimAutomation] = _fader;
1653 _fader->set_control (boost::shared_ptr<AutomationControl>());
1654 control_by_parameter[TrimAutomation] = 0;
1657 /* gain to fader, trim to vpot */
1658 _fader->set_control (_route->group_gain_control());
1659 control_by_parameter[GainAutomation] = _fader;
1660 if (_route->trim() && route()->trim()->active()) {
1661 _vpot->set_control (_route->trim_control());
1662 control_by_parameter[TrimAutomation] = _vpot;
1664 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1665 control_by_parameter[TrimAutomation] = 0;
1669 case PhaseAutomation:
1670 _trim_mode = PhaseAutomation;
1671 vpot_parameter = PhaseAutomation;
1672 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1673 /* gain to vpot, phase to fader */
1674 _vpot->set_control (_route->group_gain_control());
1675 control_by_parameter[GainAutomation] = _vpot;
1676 if (_route->phase_invert().size()) {
1677 _fader->set_control (_route->phase_control());
1678 control_by_parameter[PhaseAutomation] = _fader;
1680 _fader->set_control (boost::shared_ptr<AutomationControl>());
1681 control_by_parameter[PhaseAutomation] = 0;
1684 /* gain to fader, phase to vpot */
1685 _fader->set_control (_route->group_gain_control());
1686 control_by_parameter[GainAutomation] = _fader;
1687 if (_route->phase_invert().size()) {
1688 _vpot->set_control (_route->phase_control());
1689 control_by_parameter[PhaseAutomation] = _vpot;
1691 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1692 control_by_parameter[PhaseAutomation] = 0;
1696 case SendAutomation:
1697 if (!Profile->get_mixbus()) {
1698 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1699 // gain to vpot, send to fader
1700 _vpot->set_control (_route->group_gain_control());
1701 control_by_parameter[GainAutomation] = _vpot;
1702 // test for send to control
1703 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1704 if (p && p->name() != "Monitor 1") {
1705 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1706 boost::shared_ptr<Amp> a = s->amp();
1707 _fader->set_control (a->gain_control());
1708 // connect to signal
1709 send_connections.drop_connections ();
1710 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1711 control_by_parameter[SendAutomation] = _fader;
1713 _fader->set_control (boost::shared_ptr<AutomationControl>());
1714 control_by_parameter[SendAutomation] = 0;
1717 // gain to fader, send to vpot
1718 _fader->set_control (_route->group_gain_control());
1719 control_by_parameter[GainAutomation] = _fader;
1720 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1721 if (p && p->name() != "Monitor 1") {
1722 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1723 boost::shared_ptr<Amp> a = s->amp();
1724 _vpot->set_control (a->gain_control());
1725 // connect to signal
1726 send_connections.drop_connections ();
1727 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1728 control_by_parameter[SendAutomation] = _vpot;
1730 // gain to fader, send to vpot
1731 _fader->set_control (_route->group_gain_control());
1732 control_by_parameter[GainAutomation] = _fader;
1733 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1734 if (p && p->name() != "Monitor 1") {
1735 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1736 boost::shared_ptr<Amp> a = s->amp();
1737 _vpot->set_control (a->gain_control());
1738 // connect to signal
1739 send_connections.drop_connections ();
1740 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1741 control_by_parameter[SendAutomation] = _vpot;
1743 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1744 control_by_parameter[SendAutomation] = 0;
1750 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1755 _surface->write (display (1, vpot_mode_string()));
1759 Strip::is_midi_track () const
1761 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1765 Strip::reset_saved_values ()
1767 _last_pan_azi_position_written = -1.0;
1768 _last_pan_width_position_written = -1.0;
1769 _last_gain_position_written = -1.0;
1770 _last_trim_position_written = -1.0;
1775 Strip::notify_metering_state_changed()
1777 if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
1781 if (!_route || !_meter) {
1785 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1786 bool metering_active = _surface->mcp().metering_active ();
1788 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1792 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1794 if (!transport_is_rolling || !metering_active) {
1795 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1796 notify_panner_azi_changed (true);
1799 _transport_is_rolling = transport_is_rolling;
1800 _metering_active = metering_active;
1804 Strip::hookup_eq (AutomationType param, uint32_t band)