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)
100 , _pan_mode (PanAzimuthAutomation)
101 , _trim_mode (TrimAutomation)
102 , _last_gain_position_written (-1.0)
103 , _last_pan_azi_position_written (-1.0)
104 , _last_pan_width_position_written (-1.0)
105 , _last_trim_position_written (-1.0)
107 , redisplay_requests (256)
109 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
110 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
112 if (s.mcp().device_info().has_meters()) {
113 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
116 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
117 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
118 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
119 _surface->number(), index, Button::id_to_name (bb->bid()),
120 bb->id(), b->second.base_id));
126 /* surface is responsible for deleting all controls */
130 Strip::add (Control & control)
134 Group::add (control);
136 /* fader, vpot, meter were all set explicitly */
138 if ((button = dynamic_cast<Button*>(&control)) != 0) {
139 switch (button->bid()) {
140 case Button::RecEnable:
152 case Button::VSelect:
155 case Button::FaderTouch:
156 _fader_touch = button;
165 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
167 if (_controls_locked) {
171 mb_pan_controllable.reset();
173 route_connections.drop_connections ();
175 _solo->set_control (boost::shared_ptr<AutomationControl>());
176 _mute->set_control (boost::shared_ptr<AutomationControl>());
177 _select->set_control (boost::shared_ptr<AutomationControl>());
178 _recenable->set_control (boost::shared_ptr<AutomationControl>());
179 _fader->set_control (boost::shared_ptr<AutomationControl>());
180 _vpot->set_control (boost::shared_ptr<AutomationControl>());
184 control_by_parameter.clear ();
186 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
187 control_by_parameter[PanWidthAutomation] = (Control*) 0;
188 control_by_parameter[PanElevationAutomation] = (Control*) 0;
189 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
190 control_by_parameter[PanLFEAutomation] = (Control*) 0;
191 control_by_parameter[GainAutomation] = (Control*) 0;
192 control_by_parameter[TrimAutomation] = (Control*) 0;
193 control_by_parameter[PhaseAutomation] = (Control*) 0;
194 control_by_parameter[SendAutomation] = (Control*) 0;
196 reset_saved_values ();
203 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
204 _surface->number(), _index, _route->name()));
206 _solo->set_control (_route->solo_control());
207 _mute->set_control (_route->mute_control());
209 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
210 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
212 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
214 if (_route->trim() && route()->trim()->active()) {
215 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
218 if (_route->phase_invert().size()) {
219 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
220 _route->phase_control()->set_channel(0);
223 boost::shared_ptr<Pannable> pannable = _route->pannable();
225 if(Profile->get_mixbus()) {
226 const uint32_t port_channel_post_pan = 2; // gtk2_ardour/mixbus_ports.h
227 boost::shared_ptr<ARDOUR::PluginInsert> plug = _route->ch_post();
228 mb_pan_controllable = boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_pan)));
230 mb_pan_controllable->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
232 if (pannable && _route->panner()) {
233 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
234 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
238 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
239 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
241 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
244 _recenable->set_control (trk->rec_enable_control());
245 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
250 // TODO this works when a currently-banked route is made inactive, but not
251 // when a route is activated which should be currently banked.
253 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
254 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
256 /* setup legal VPot modes for this route */
258 possible_pot_parameters.clear();
260 if (Profile->get_mixbus()) {
261 possible_pot_parameters.push_back (PanAzimuthAutomation);
264 boost::shared_ptr<Panner> panner = _route->panner();
266 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
267 set<Evoral::Parameter>::iterator a;
269 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
270 possible_pot_parameters.push_back (PanAzimuthAutomation);
273 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
274 possible_pot_parameters.push_back (PanWidthAutomation);
280 if (_route->trim() && route()->trim()->active()) {
281 possible_pot_parameters.push_back (TrimAutomation);
284 possible_trim_parameters.clear();
286 if (_route->trim() && route()->trim()->active()) {
287 possible_trim_parameters.push_back (TrimAutomation);
288 _trim_mode = TrimAutomation;
291 if (_route->phase_invert().size()) {
292 possible_trim_parameters.push_back (PhaseAutomation);
293 _route->phase_control()->set_channel(0);
294 if (_trim_mode != TrimAutomation) {
295 _trim_mode = PhaseAutomation;
300 _pan_mode = PanAzimuthAutomation;
301 potmode_changed (false);
314 notify_solo_changed ();
315 notify_mute_changed ();
316 notify_gain_changed ();
317 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
318 notify_panner_azi_changed ();
319 notify_panner_width_changed ();
320 notify_record_enable_changed ();
321 notify_trim_changed ();
322 notify_phase_changed ();
323 notify_processor_changed ();
327 Strip::notify_solo_changed ()
329 if (_route && _solo) {
330 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
335 Strip::notify_mute_changed ()
337 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
338 if (_route && _mute) {
339 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
340 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
342 _surface->write (_mute->set_state (_route->muted() ? on : off));
347 Strip::notify_record_enable_changed ()
349 if (_route && _recenable) {
350 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
355 Strip::notify_active_changed ()
357 _surface->mcp().refresh_current_bank();
361 Strip::notify_route_deleted ()
363 _surface->mcp().refresh_current_bank();
367 Strip::notify_gain_changed (bool force_update)
373 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
379 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
381 float gain_coefficient = ac->get_value();
382 float normalized_position = ac->internal_to_interface (gain_coefficient);
385 if (force_update || normalized_position != _last_gain_position_written) {
387 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
388 if (!control->in_use()) {
389 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
391 queue_parameter_display (GainAutomation, gain_coefficient);
393 if (!control->in_use()) {
394 _surface->write (_fader->set_position (normalized_position));
396 queue_parameter_display (GainAutomation, gain_coefficient);
399 _last_gain_position_written = normalized_position;
405 Strip::notify_trim_changed (bool force_update)
409 if (!_route->trim() || !route()->trim()->active()) {
410 _surface->write (_vpot->zero());
413 Control* control = 0;
414 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
416 if (i == control_by_parameter.end()) {
422 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
424 float gain_coefficient = ac->get_value();
425 float normalized_position = ac->internal_to_interface (gain_coefficient);
427 if (force_update || normalized_position != _last_trim_position_written) {
428 if (control == _fader) {
429 if (!_fader->in_use()) {
430 _surface->write (_fader->set_position (normalized_position));
431 queue_parameter_display (TrimAutomation, gain_coefficient);
433 } else if (control == _vpot) {
434 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
435 queue_parameter_display (TrimAutomation, gain_coefficient);
437 _last_trim_position_written = normalized_position;
443 Strip::notify_phase_changed (bool force_update)
446 if (!_route->phase_invert().size()) {
447 _surface->write (_vpot->zero());
451 Control* control = 0;
452 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
454 if (i == control_by_parameter.end()) {
460 float normalized_position = _route->phase_control()->get_value();
462 if (control == _fader) {
463 if (!_fader->in_use()) {
464 _surface->write (_fader->set_position (normalized_position));
465 queue_parameter_display (PhaseAutomation, normalized_position);
467 } else if (control == _vpot) {
468 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
469 queue_parameter_display (PhaseAutomation, normalized_position);
475 Strip::notify_processor_changed (bool force_update)
478 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
480 _surface->write (_vpot->zero());
484 Control* control = 0;
485 ControlParameterMap::iterator i = control_by_parameter.find (SendAutomation);
487 if (i == control_by_parameter.end()) {
493 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
494 boost::shared_ptr<Amp> a = s->amp();
495 boost::shared_ptr<AutomationControl> ac = a->gain_control();
497 float gain_coefficient = ac->get_value();
498 float normalized_position = ac->internal_to_interface (gain_coefficient);
500 if (control == _fader) {
501 if (!_fader->in_use()) {
502 _surface->write (_fader->set_position (normalized_position));
503 queue_parameter_display (SendAutomation, gain_coefficient);
505 } else if (control == _vpot) {
506 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
507 queue_parameter_display (SendAutomation, gain_coefficient);
513 Strip::notify_property_changed (const PropertyChange& what_changed)
515 if (!what_changed.contains (ARDOUR::Properties::name)) {
523 Strip::show_route_name ()
529 string fullname = _route->name();
531 if (fullname.length() <= 6) {
534 line1 = PBD::short_version (fullname, 6);
537 _surface->write (display (0, line1));
541 Strip::notify_panner_azi_changed (bool force_update)
545 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
547 boost::shared_ptr<Pannable> pannable = _route->pannable();
549 if (!pannable || !_route->panner()) {
550 _surface->write (_vpot->zero());
554 Control* control = 0;
555 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
557 if (i == control_by_parameter.end()) {
563 double pos = mb_pan_controllable->internal_to_interface (mb_pan_controllable->get_value());
565 if (force_update || pos != _last_pan_azi_position_written) {
567 if (control == _fader) {
568 if (!_fader->in_use()) {
569 _surface->write (_fader->set_position (pos));
570 queue_parameter_display (PanAzimuthAutomation, pos);
572 } else if (control == _vpot) {
573 _surface->write (_vpot->set (pos, true, Pot::dot));
574 queue_parameter_display (PanAzimuthAutomation, pos);
577 _last_pan_azi_position_written = pos;
583 Strip::notify_panner_width_changed (bool force_update)
587 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
589 boost::shared_ptr<Pannable> pannable = _route->pannable();
591 if (!pannable || !_route->panner()) {
592 _surface->write (_vpot->zero());
596 Control* control = 0;
597 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
599 if (i == control_by_parameter.end()) {
605 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
607 if (force_update || pos != _last_pan_width_position_written) {
609 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
611 if (control == _fader) {
612 if (!control->in_use()) {
613 _surface->write (_fader->set_position (pos));
614 queue_parameter_display (PanWidthAutomation, pos);
618 } else if (control == _vpot) {
619 _surface->write (_vpot->set (pos, true, Pot::spread));
620 queue_parameter_display (PanWidthAutomation, pos);
623 _last_pan_width_position_written = pos;
629 Strip::select_event (Button&, ButtonState bs)
631 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
635 int ms = _surface->mcp().main_modifier_state();
637 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
638 _controls_locked = !_controls_locked;
639 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
640 block_vpot_mode_display_for (1000);
644 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
645 /* reset to default */
646 boost::shared_ptr<AutomationControl> ac = _fader->control ();
648 ac->set_value (ac->normal());
653 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
654 _surface->mcp().add_down_select_button (_surface->number(), _index);
655 _surface->mcp().select_range ();
658 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
659 _surface->mcp().remove_down_select_button (_surface->number(), _index);
664 Strip::vselect_event (Button&, ButtonState bs)
668 int ms = _surface->mcp().main_modifier_state();
670 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
672 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
676 /* reset to default/normal value */
677 ac->set_value (ac->normal());
682 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
690 Strip::fader_touch_event (Button&, ButtonState bs)
692 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
696 boost::shared_ptr<AutomationControl> ac = _fader->control ();
698 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
700 ac->set_value (ac->normal());
704 _fader->set_in_use (true);
705 _fader->start_touch (_surface->mcp().transport_frame());
708 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
714 _fader->set_in_use (false);
715 _fader->stop_touch (_surface->mcp().transport_frame(), true);
722 Strip::handle_button (Button& button, ButtonState bs)
724 boost::shared_ptr<AutomationControl> control;
727 button.set_in_use (true);
729 button.set_in_use (false);
732 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
734 switch (button.bid()) {
736 select_event (button, bs);
739 case Button::VSelect:
740 vselect_event (button, bs);
743 case Button::FaderTouch:
744 fader_touch_event (button, bs);
748 if ((control = button.control ())) {
750 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
751 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
754 int ms = _surface->mcp().main_modifier_state();
756 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
757 /* reset to default/normal value */
758 new_value = control->normal();
760 new_value = control->get_value() ? 0.0 : 1.0;
763 /* get all controls that either have their
764 * button down or are within a range of
765 * several down buttons
768 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
771 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
772 controls.size(), control->parameter().type(), new_value));
776 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
777 (*c)->set_value (new_value);
781 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
782 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
790 Strip::queue_parameter_display (AutomationType type, float val)
792 RedisplayRequest req;
797 redisplay_requests.write (&req, 1);
801 Strip::do_parameter_display (AutomationType type, float val)
803 bool screen_hold = false;
808 _surface->write (display (1, " -inf "));
811 float dB = accurate_coefficient_to_dB (val);
812 snprintf (buf, sizeof (buf), "%6.1f", dB);
813 _surface->write (display (1, buf));
818 case PanAzimuthAutomation:
819 if (Profile->get_mixbus()) {
821 snprintf (buf, sizeof (buf), "%2.1f", val);
822 _surface->write (display (1, buf));
826 boost::shared_ptr<Pannable> p = _route->pannable();
827 if (p && _route->panner()) {
828 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
829 _surface->write (display (1, str));
836 case PanWidthAutomation:
839 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
840 _surface->write (display (1, buf));
848 float dB = accurate_coefficient_to_dB (val);
849 snprintf (buf, sizeof (buf), "%6.1f", dB);
850 _surface->write (display (1, buf));
855 case PhaseAutomation:
857 if (_route->phase_control()->get_value() < 0.5) {
858 _surface->write (display (1, "Normal"));
860 _surface->write (display (1, "Invert"));
868 _surface->write (display (1, " -inf "));
871 float dB = accurate_coefficient_to_dB (val);
872 snprintf (buf, sizeof (buf), "%6.1f", dB);
873 _surface->write (display (1, buf));
883 block_vpot_mode_display_for (1000);
888 Strip::handle_fader_touch (Fader& fader, bool touch_on)
891 fader.start_touch (_surface->mcp().transport_frame());
893 fader.stop_touch (_surface->mcp().transport_frame(), false);
898 Strip::handle_fader (Fader& fader, float position)
900 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
901 boost::shared_ptr<AutomationControl> ac = fader.control();
906 fader.set_value (position);
908 /* From the Mackie Control MIDI implementation docs:
910 In order to ensure absolute synchronization with the host software,
911 Mackie Control uses a closed-loop servo system for the faders,
912 meaning the faders will always move to their last received position.
913 When a host receives a Fader Position Message, it must then
914 re-transmit that message to the Mackie Control or else the faders
915 will return to their last position.
918 _surface->write (fader.set_position (position));
922 Strip::handle_pot (Pot& pot, float delta)
924 /* Pots only emit events when they move, not when they
925 stop moving. So to get a stop event, we need to use a timeout.
928 boost::shared_ptr<AutomationControl> ac = pot.control();
932 double p = pot.get_value ();
934 // fader and pot should be the same and fader is hard coded 0 -> 1
941 Strip::periodic (ARDOUR::microseconds_t now)
943 bool reshow_vpot_mode = false;
944 bool reshow_name = false;
950 if (_block_screen_redisplay_until >= now) {
951 if (_surface->mcp().device_info().has_separate_meters()) {
954 /* no drawing here, for now */
957 } else if (_block_screen_redisplay_until) {
959 /* timeout reached, reset */
961 _block_screen_redisplay_until = 0;
962 reshow_vpot_mode = true;
966 if (_block_vpot_mode_redisplay_until >= now) {
968 } else if (_block_vpot_mode_redisplay_until) {
970 /* timeout reached, reset */
972 _block_vpot_mode_redisplay_until = 0;
973 reshow_vpot_mode = true;
980 if (reshow_vpot_mode) {
981 return_to_vpot_mode_display ();
983 /* no point doing this if we just switched back to vpot mode
985 update_automation ();
993 Strip::redisplay (ARDOUR::microseconds_t now)
995 RedisplayRequest req;
996 bool have_request = false;
998 while (redisplay_requests.read (&req, 1) == 1) {
1000 have_request = true;
1003 if (_block_screen_redisplay_until >= now) {
1008 do_parameter_display (req.type, req.val);
1013 Strip::update_automation ()
1015 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
1017 if (gain_state == Touch || gain_state == Play) {
1018 notify_gain_changed (false);
1021 if ( Profile->get_mixbus() ) {
1022 ARDOUR::AutoState panner_state = mb_pan_controllable->automation_state();
1023 if (panner_state == Touch || panner_state == Play) {
1024 notify_panner_azi_changed (false);
1027 if (_route->panner()) {
1028 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
1029 if (panner_state == Touch || panner_state == Play) {
1030 notify_panner_azi_changed (false);
1031 notify_panner_width_changed (false);
1035 if (_route->trim() && route()->trim()->active()) {
1036 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1037 if (trim_state == Touch || trim_state == Play) {
1038 notify_trim_changed (false);
1044 Strip::update_meter ()
1046 if (_meter && _transport_is_rolling && _metering_active) {
1047 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1048 _meter->send_update (*_surface, dB);
1055 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1056 _surface->write ((*it)->zero ());
1059 _surface->write (blank_display (0));
1060 _surface->write (blank_display (1));
1064 Strip::blank_display (uint32_t line_number)
1066 return display (line_number, string());
1070 Strip::display (uint32_t line_number, const std::string& line)
1072 assert (line_number <= 1);
1074 MidiByteArray retval;
1076 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1079 retval << _surface->sysex_hdr();
1083 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1084 retval << (_index * 7 + (line_number * 0x38));
1086 // ascii data to display. @param line is UTF-8
1087 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1088 string::size_type len = ascii.length();
1090 ascii = ascii.substr (0, 6);
1094 // pad with " " out to 6 chars
1095 for (int i = len; i < 6; ++i) {
1099 // column spacer, unless it's the right-hand column
1105 retval << MIDI::eox;
1111 Strip::lock_controls ()
1113 _controls_locked = true;
1117 Strip::unlock_controls ()
1119 _controls_locked = false;
1123 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1125 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1126 if ((*i) == _route) {
1127 _surface->write (_select->set_state (on));
1132 _surface->write (_select->set_state (off));
1136 Strip::vpot_mode_string ()
1138 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1143 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1145 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1147 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1148 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1149 } else if (control_by_parameter.find (SendAutomation)->second == _vpot) {
1150 // should be bus name
1151 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1155 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1157 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1159 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1161 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1163 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1171 Strip::potmode_changed (bool notify)
1178 int pm = _surface->mcp().pot_mode();
1180 case MackieControlProtocol::Pan:
1181 // This needs to set current pan mode (azimuth or width... or whatever)
1182 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1183 set_vpot_parameter (_pan_mode);
1185 case MackieControlProtocol::Trim:
1186 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1187 set_vpot_parameter (_trim_mode);
1189 case MackieControlProtocol::Send:
1190 // _current_send has the number of the send we will show
1191 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1192 set_vpot_parameter (SendAutomation);
1202 Strip::block_screen_display_for (uint32_t msecs)
1204 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1208 Strip::block_vpot_mode_display_for (uint32_t msecs)
1210 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1214 Strip::return_to_vpot_mode_display ()
1216 /* returns the second line of the two-line per-strip display
1217 back the mode where it shows what the VPot controls.
1221 _surface->write (display (1, vpot_mode_string()));
1223 _surface->write (blank_display (1));
1228 Strip::next_pot_mode ()
1230 vector<Evoral::Parameter>::iterator i;
1232 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1233 /* do not change vpot mode while in flipped mode */
1234 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1235 _surface->write (display (1, "Flip"));
1236 block_vpot_mode_display_for (1000);
1241 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1246 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1247 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1251 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1252 if ((*i) == ac->parameter()) {
1257 /* move to the next mode in the list, or back to the start (which will
1258 also happen if the current mode is not in the current pot mode list)
1261 if (i != possible_pot_parameters.end()) {
1265 if (i == possible_pot_parameters.end()) {
1266 i = possible_pot_parameters.begin();
1268 set_vpot_parameter (*i);
1269 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1270 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1274 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1275 if ((*i) == ac->parameter()) {
1279 if ((*i).type() == PhaseAutomation && _route->phase_invert().size() > 1) {
1280 // There are more than one channel of phase
1281 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1282 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1283 set_vpot_parameter (*i);
1286 _route->phase_control()->set_channel(0);
1289 /* move to the next mode in the list, or back to the start (which will
1290 also happen if the current mode is not in the current pot mode list)
1293 if (i != possible_trim_parameters.end()) {
1297 if (i == possible_trim_parameters.end()) {
1298 i = possible_trim_parameters.begin();
1300 set_vpot_parameter (*i);
1301 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Send) {
1302 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1306 p = _route->nth_send (_current_send + 1);
1307 if (p && p->name() != "Monitor 1") {
1312 set_vpot_parameter (SendAutomation);
1317 Strip::set_vpot_parameter (Evoral::Parameter p)
1319 boost::shared_ptr<Pannable> pannable;
1321 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p.type()));
1323 reset_saved_values ();
1325 /* unset any mapping between the vpot and any existing parameters */
1327 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1329 if (i != control_by_parameter.end() && i->second == _vpot) {
1335 case PanAzimuthAutomation:
1336 _pan_mode = PanAzimuthAutomation;
1337 pannable = _route->pannable ();
1338 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1339 /* gain to vpot, pan azi to fader */
1340 _vpot->set_control (_route->group_gain_control());
1341 control_by_parameter[GainAutomation] = _vpot;
1343 _fader->set_control (mb_pan_controllable);
1344 control_by_parameter[PanAzimuthAutomation] = _fader;
1346 _fader->set_control (boost::shared_ptr<AutomationControl>());
1347 control_by_parameter[PanAzimuthAutomation] = 0;
1350 /* gain to fader, pan azi to vpot */
1351 _fader->set_control (_route->group_gain_control());
1352 control_by_parameter[GainAutomation] = _fader;
1354 _vpot->set_control (mb_pan_controllable);
1355 control_by_parameter[PanAzimuthAutomation] = _vpot;
1357 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1358 control_by_parameter[PanAzimuthAutomation] = 0;
1362 case PanWidthAutomation:
1363 _pan_mode = PanWidthAutomation;
1364 pannable = _route->pannable ();
1365 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1366 /* gain to vpot, pan width to fader */
1367 _vpot->set_control (_route->group_gain_control());
1368 control_by_parameter[GainAutomation] = _vpot;
1370 _fader->set_control (pannable->pan_width_control);
1371 control_by_parameter[PanWidthAutomation] = _fader;
1373 _fader->set_control (boost::shared_ptr<AutomationControl>());
1374 control_by_parameter[PanWidthAutomation] = 0;
1377 /* gain to fader, pan width to vpot */
1378 _fader->set_control (_route->group_gain_control());
1379 control_by_parameter[GainAutomation] = _fader;
1381 _vpot->set_control (pannable->pan_width_control);
1382 control_by_parameter[PanWidthAutomation] = _vpot;
1384 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1385 control_by_parameter[PanWidthAutomation] = 0;
1389 case PanElevationAutomation:
1391 case PanFrontBackAutomation:
1393 case PanLFEAutomation:
1395 case TrimAutomation:
1396 _trim_mode = TrimAutomation;
1397 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1398 /* gain to vpot, trim to fader */
1399 _vpot->set_control (_route->group_gain_control());
1400 control_by_parameter[GainAutomation] = _vpot;
1401 if (_route->trim() && route()->trim()->active()) {
1402 _fader->set_control (_route->trim_control());
1403 control_by_parameter[TrimAutomation] = _fader;
1405 _fader->set_control (boost::shared_ptr<AutomationControl>());
1406 control_by_parameter[TrimAutomation] = 0;
1409 /* gain to fader, trim to vpot */
1410 _fader->set_control (_route->group_gain_control());
1411 control_by_parameter[GainAutomation] = _fader;
1412 if (_route->trim() && route()->trim()->active()) {
1413 _vpot->set_control (_route->trim_control());
1414 control_by_parameter[TrimAutomation] = _vpot;
1416 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1417 control_by_parameter[TrimAutomation] = 0;
1421 case PhaseAutomation:
1422 _trim_mode = PhaseAutomation;
1423 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1424 /* gain to vpot, phase to fader */
1425 _vpot->set_control (_route->group_gain_control());
1426 control_by_parameter[GainAutomation] = _vpot;
1427 if (_route->phase_invert().size()) {
1428 _fader->set_control (_route->phase_control());
1429 control_by_parameter[PhaseAutomation] = _fader;
1431 _fader->set_control (boost::shared_ptr<AutomationControl>());
1432 control_by_parameter[PhaseAutomation] = 0;
1435 /* gain to fader, phase to vpot */
1436 _fader->set_control (_route->group_gain_control());
1437 control_by_parameter[GainAutomation] = _fader;
1438 if (_route->phase_invert().size()) {
1439 _vpot->set_control (_route->phase_control());
1440 control_by_parameter[PhaseAutomation] = _vpot;
1442 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1443 control_by_parameter[PhaseAutomation] = 0;
1447 case SendAutomation:
1448 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1449 // gain to vpot, send to fader
1450 _vpot->set_control (_route->group_gain_control());
1451 control_by_parameter[GainAutomation] = _vpot;
1452 // test for send to control
1453 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1454 if (p && p->name() != "Monitor 1") {
1455 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1456 boost::shared_ptr<Amp> a = s->amp();
1457 _fader->set_control (a->gain_control());
1458 // connect to signal
1459 send_connections.drop_connections ();
1460 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1461 control_by_parameter[SendAutomation] = _fader;
1463 _fader->set_control (boost::shared_ptr<AutomationControl>());
1464 control_by_parameter[SendAutomation] = 0;
1467 // gain to fader, send to vpot
1468 _fader->set_control (_route->group_gain_control());
1469 control_by_parameter[GainAutomation] = _fader;
1470 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1471 if (p && p->name() != "Monitor 1") {
1472 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1473 boost::shared_ptr<Amp> a = s->amp();
1474 _vpot->set_control (a->gain_control());
1475 // connect to signal
1476 send_connections.drop_connections ();
1477 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1478 control_by_parameter[SendAutomation] = _vpot;
1480 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1481 control_by_parameter[SendAutomation] = 0;
1486 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1491 _surface->write (display (1, vpot_mode_string()));
1495 Strip::is_midi_track () const
1497 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1501 Strip::reset_saved_values ()
1503 _last_pan_azi_position_written = -1.0;
1504 _last_pan_width_position_written = -1.0;
1505 _last_gain_position_written = -1.0;
1506 _last_trim_position_written = -1.0;
1511 Strip::notify_metering_state_changed()
1513 if (!_route || !_meter) {
1517 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1518 bool metering_active = _surface->mcp().metering_active ();
1520 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1524 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1526 if (!transport_is_rolling || !metering_active) {
1527 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1528 notify_panner_azi_changed (true);
1531 _transport_is_rolling = transport_is_rolling;
1532 _metering_active = metering_active;