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/pannable.h"
39 #include "ardour/panner.h"
40 #include "ardour/panner_shell.h"
41 #include "ardour/rc_configuration.h"
42 #include "ardour/route.h"
43 #include "ardour/session.h"
44 #include "ardour/send.h"
45 #include "ardour/track.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/user_bundle.h"
49 #include "mackie_control_protocol.h"
50 #include "surface_port.h"
60 using namespace ARDOUR;
62 using namespace ArdourSurface;
63 using namespace Mackie;
65 #ifndef timeradd /// only avail with __USE_BSD
66 #define timeradd(a,b,result) \
68 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
69 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
70 if ((result)->tv_usec >= 1000000) \
73 (result)->tv_usec -= 1000000; \
78 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
80 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
93 , _controls_locked (false)
94 , _transport_is_rolling (false)
95 , _metering_active (true)
96 , _block_vpot_mode_redisplay_until (0)
97 , _block_screen_redisplay_until (0)
98 , _pan_mode (PanAzimuthAutomation)
99 , _trim_mode (TrimAutomation)
100 , _last_gain_position_written (-1.0)
101 , _last_pan_azi_position_written (-1.0)
102 , _last_pan_width_position_written (-1.0)
103 , _last_trim_position_written (-1.0)
105 , redisplay_requests (256)
107 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
108 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
110 if (s.mcp().device_info().has_meters()) {
111 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
114 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
115 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
116 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
117 _surface->number(), index, Button::id_to_name (bb->bid()),
118 bb->id(), b->second.base_id));
124 /* surface is responsible for deleting all controls */
128 Strip::add (Control & control)
132 Group::add (control);
134 /* fader, vpot, meter were all set explicitly */
136 if ((button = dynamic_cast<Button*>(&control)) != 0) {
137 switch (button->bid()) {
138 case Button::RecEnable:
150 case Button::VSelect:
153 case Button::FaderTouch:
154 _fader_touch = button;
163 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
165 if (_controls_locked) {
169 route_connections.drop_connections ();
171 _solo->set_control (boost::shared_ptr<AutomationControl>());
172 _mute->set_control (boost::shared_ptr<AutomationControl>());
173 _select->set_control (boost::shared_ptr<AutomationControl>());
174 _recenable->set_control (boost::shared_ptr<AutomationControl>());
175 _fader->set_control (boost::shared_ptr<AutomationControl>());
176 _vpot->set_control (boost::shared_ptr<AutomationControl>());
180 control_by_parameter.clear ();
182 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
183 control_by_parameter[PanWidthAutomation] = (Control*) 0;
184 control_by_parameter[PanElevationAutomation] = (Control*) 0;
185 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
186 control_by_parameter[PanLFEAutomation] = (Control*) 0;
187 control_by_parameter[GainAutomation] = (Control*) 0;
188 control_by_parameter[TrimAutomation] = (Control*) 0;
189 control_by_parameter[PhaseAutomation] = (Control*) 0;
190 control_by_parameter[SendAutomation] = (Control*) 0;
192 reset_saved_values ();
199 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
200 _surface->number(), _index, _route->name()));
202 _solo->set_control (_route->solo_control());
203 _mute->set_control (_route->mute_control());
205 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
206 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
208 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
210 if (_route->trim() && route()->trim()->active()) {
211 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
214 if (_route->phase_invert().size()) {
215 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
216 _route->phase_control()->set_channel(0);
219 boost::shared_ptr<Pannable> pannable = _route->pannable();
221 if (pannable && _route->panner()) {
222 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
223 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
225 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
226 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
228 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
231 _recenable->set_control (trk->rec_enable_control());
232 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
237 // TODO this works when a currently-banked route is made inactive, but not
238 // when a route is activated which should be currently banked.
240 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
241 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
243 /* setup legal VPot modes for this route */
245 possible_pot_parameters.clear();
248 boost::shared_ptr<Panner> panner = _route->panner();
250 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
251 set<Evoral::Parameter>::iterator a;
253 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
254 possible_pot_parameters.push_back (PanAzimuthAutomation);
257 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
258 possible_pot_parameters.push_back (PanWidthAutomation);
263 if (_route->trim() && route()->trim()->active()) {
264 possible_pot_parameters.push_back (TrimAutomation);
267 possible_trim_parameters.clear();
269 if (_route->trim() && route()->trim()->active()) {
270 possible_trim_parameters.push_back (TrimAutomation);
271 _trim_mode = TrimAutomation;
274 if (_route->phase_invert().size()) {
275 possible_trim_parameters.push_back (PhaseAutomation);
276 _route->phase_control()->set_channel(0);
277 if (_trim_mode != TrimAutomation) {
278 _trim_mode = PhaseAutomation;
283 _pan_mode = PanAzimuthAutomation;
284 potmode_changed (false);
297 notify_solo_changed ();
298 notify_mute_changed ();
299 notify_gain_changed ();
300 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
301 notify_panner_azi_changed ();
302 notify_panner_width_changed ();
303 notify_record_enable_changed ();
304 notify_trim_changed ();
305 notify_phase_changed ();
306 notify_processor_changed ();
310 Strip::notify_solo_changed ()
312 if (_route && _solo) {
313 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
318 Strip::notify_mute_changed ()
320 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
321 if (_route && _mute) {
322 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
323 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
325 _surface->write (_mute->set_state (_route->muted() ? on : off));
330 Strip::notify_record_enable_changed ()
332 if (_route && _recenable) {
333 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
338 Strip::notify_active_changed ()
340 _surface->mcp().refresh_current_bank();
344 Strip::notify_route_deleted ()
346 _surface->mcp().refresh_current_bank();
350 Strip::notify_gain_changed (bool force_update)
356 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
362 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
364 float gain_coefficient = ac->get_value();
365 float normalized_position = ac->internal_to_interface (gain_coefficient);
368 if (force_update || normalized_position != _last_gain_position_written) {
370 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
371 if (!control->in_use()) {
372 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
374 queue_parameter_display (GainAutomation, gain_coefficient);
376 if (!control->in_use()) {
377 _surface->write (_fader->set_position (normalized_position));
379 queue_parameter_display (GainAutomation, gain_coefficient);
382 _last_gain_position_written = normalized_position;
388 Strip::notify_trim_changed (bool force_update)
392 if (!_route->trim() || !route()->trim()->active()) {
393 _surface->write (_vpot->zero());
396 Control* control = 0;
397 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
399 if (i == control_by_parameter.end()) {
405 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
407 float gain_coefficient = ac->get_value();
408 float normalized_position = ac->internal_to_interface (gain_coefficient);
410 if (force_update || normalized_position != _last_trim_position_written) {
411 if (control == _fader) {
412 if (!_fader->in_use()) {
413 _surface->write (_fader->set_position (normalized_position));
414 queue_parameter_display (TrimAutomation, gain_coefficient);
416 } else if (control == _vpot) {
417 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
418 queue_parameter_display (TrimAutomation, gain_coefficient);
420 _last_trim_position_written = normalized_position;
426 Strip::notify_phase_changed (bool force_update)
429 if (!_route->phase_invert().size()) {
430 _surface->write (_vpot->zero());
434 Control* control = 0;
435 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
437 if (i == control_by_parameter.end()) {
443 float normalized_position = _route->phase_control()->get_value();
445 if (control == _fader) {
446 if (!_fader->in_use()) {
447 _surface->write (_fader->set_position (normalized_position));
448 queue_parameter_display (PhaseAutomation, normalized_position);
450 } else if (control == _vpot) {
451 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
452 queue_parameter_display (PhaseAutomation, normalized_position);
458 Strip::notify_processor_changed (bool force_update)
461 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
463 _surface->write (_vpot->zero());
467 Control* control = 0;
468 ControlParameterMap::iterator i = control_by_parameter.find (SendAutomation);
470 if (i == control_by_parameter.end()) {
476 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
477 boost::shared_ptr<Amp> a = s->amp();
478 boost::shared_ptr<AutomationControl> ac = a->gain_control();
480 float gain_coefficient = ac->get_value();
481 float normalized_position = ac->internal_to_interface (gain_coefficient);
483 if (control == _fader) {
484 if (!_fader->in_use()) {
485 _surface->write (_fader->set_position (normalized_position));
486 queue_parameter_display (SendAutomation, normalized_position);
488 } else if (control == _vpot) {
489 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
490 queue_parameter_display (SendAutomation, normalized_position);
496 Strip::notify_property_changed (const PropertyChange& what_changed)
498 if (!what_changed.contains (ARDOUR::Properties::name)) {
506 Strip::show_route_name ()
512 string fullname = _route->name();
514 if (fullname.length() <= 6) {
517 line1 = PBD::short_version (fullname, 6);
520 _surface->write (display (0, line1));
524 Strip::notify_panner_azi_changed (bool force_update)
528 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
530 boost::shared_ptr<Pannable> pannable = _route->pannable();
532 if (!pannable || !_route->panner()) {
533 _surface->write (_vpot->zero());
537 Control* control = 0;
538 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
540 if (i == control_by_parameter.end()) {
546 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
548 if (force_update || pos != _last_pan_azi_position_written) {
550 if (control == _fader) {
551 if (!_fader->in_use()) {
552 _surface->write (_fader->set_position (pos));
553 queue_parameter_display (PanAzimuthAutomation, pos);
555 } else if (control == _vpot) {
556 _surface->write (_vpot->set (pos, true, Pot::dot));
557 queue_parameter_display (PanAzimuthAutomation, pos);
560 _last_pan_azi_position_written = pos;
566 Strip::notify_panner_width_changed (bool force_update)
570 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
572 boost::shared_ptr<Pannable> pannable = _route->pannable();
574 if (!pannable || !_route->panner()) {
575 _surface->write (_vpot->zero());
579 Control* control = 0;
580 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
582 if (i == control_by_parameter.end()) {
588 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
590 if (force_update || pos != _last_pan_width_position_written) {
592 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
594 if (control == _fader) {
595 if (!control->in_use()) {
596 _surface->write (_fader->set_position (pos));
597 queue_parameter_display (PanWidthAutomation, pos);
601 } else if (control == _vpot) {
602 _surface->write (_vpot->set (pos, true, Pot::spread));
603 queue_parameter_display (PanWidthAutomation, pos);
606 _last_pan_width_position_written = pos;
612 Strip::select_event (Button&, ButtonState bs)
614 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
618 int ms = _surface->mcp().main_modifier_state();
620 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
621 _controls_locked = !_controls_locked;
622 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
623 block_vpot_mode_display_for (1000);
627 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
628 /* reset to default */
629 boost::shared_ptr<AutomationControl> ac = _fader->control ();
631 ac->set_value (ac->normal());
636 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
637 _surface->mcp().add_down_select_button (_surface->number(), _index);
638 _surface->mcp().select_range ();
641 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
642 _surface->mcp().remove_down_select_button (_surface->number(), _index);
647 Strip::vselect_event (Button&, ButtonState bs)
651 int ms = _surface->mcp().main_modifier_state();
653 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
655 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
659 /* reset to default/normal value */
660 ac->set_value (ac->normal());
665 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
673 Strip::fader_touch_event (Button&, ButtonState bs)
675 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
679 boost::shared_ptr<AutomationControl> ac = _fader->control ();
681 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
683 ac->set_value (ac->normal());
687 _fader->set_in_use (true);
688 _fader->start_touch (_surface->mcp().transport_frame());
691 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
697 _fader->set_in_use (false);
698 _fader->stop_touch (_surface->mcp().transport_frame(), true);
705 Strip::handle_button (Button& button, ButtonState bs)
707 boost::shared_ptr<AutomationControl> control;
710 button.set_in_use (true);
712 button.set_in_use (false);
715 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
717 switch (button.bid()) {
719 select_event (button, bs);
722 case Button::VSelect:
723 vselect_event (button, bs);
726 case Button::FaderTouch:
727 fader_touch_event (button, bs);
731 if ((control = button.control ())) {
733 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
734 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
737 int ms = _surface->mcp().main_modifier_state();
739 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
740 /* reset to default/normal value */
741 new_value = control->normal();
743 new_value = control->get_value() ? 0.0 : 1.0;
746 /* get all controls that either have their
747 * button down or are within a range of
748 * several down buttons
751 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
754 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
755 controls.size(), control->parameter().type(), new_value));
759 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
760 (*c)->set_value (new_value);
764 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
765 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
773 Strip::queue_parameter_display (AutomationType type, float val)
775 RedisplayRequest req;
780 redisplay_requests.write (&req, 1);
784 Strip::do_parameter_display (AutomationType type, float val)
786 bool screen_hold = false;
791 _surface->write (display (1, " -inf "));
794 float dB = accurate_coefficient_to_dB (val);
795 snprintf (buf, sizeof (buf), "%6.1f", dB);
796 _surface->write (display (1, buf));
801 case PanAzimuthAutomation:
803 boost::shared_ptr<Pannable> p = _route->pannable();
804 if (p && _route->panner()) {
805 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
806 _surface->write (display (1, str));
812 case PanWidthAutomation:
815 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
816 _surface->write (display (1, buf));
824 float dB = accurate_coefficient_to_dB (val);
825 snprintf (buf, sizeof (buf), "%6.1f", dB);
826 _surface->write (display (1, buf));
831 case PhaseAutomation:
833 if (_route->phase_control()->get_value() < 0.5) {
834 _surface->write (display (1, "Normal"));
836 _surface->write (display (1, "Invert"));
844 _surface->write (display (1, " -inf "));
847 float dB = accurate_coefficient_to_dB (val);
848 snprintf (buf, sizeof (buf), "%6.1f", dB);
849 _surface->write (display (1, buf));
859 block_vpot_mode_display_for (1000);
864 Strip::handle_fader_touch (Fader& fader, bool touch_on)
867 fader.start_touch (_surface->mcp().transport_frame());
869 fader.stop_touch (_surface->mcp().transport_frame(), false);
874 Strip::handle_fader (Fader& fader, float position)
876 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
877 boost::shared_ptr<AutomationControl> ac = fader.control();
882 fader.set_value (position);
884 /* From the Mackie Control MIDI implementation docs:
886 In order to ensure absolute synchronization with the host software,
887 Mackie Control uses a closed-loop servo system for the faders,
888 meaning the faders will always move to their last received position.
889 When a host receives a Fader Position Message, it must then
890 re-transmit that message to the Mackie Control or else the faders
891 will return to their last position.
894 _surface->write (fader.set_position (position));
898 Strip::handle_pot (Pot& pot, float delta)
900 /* Pots only emit events when they move, not when they
901 stop moving. So to get a stop event, we need to use a timeout.
904 boost::shared_ptr<AutomationControl> ac = pot.control();
908 double p = pot.get_value ();
910 p = max (ac->lower(), p);
911 p = min (ac->upper(), p);
916 Strip::periodic (ARDOUR::microseconds_t now)
918 bool reshow_vpot_mode = false;
919 bool reshow_name = false;
925 if (_block_screen_redisplay_until >= now) {
926 if (_surface->mcp().device_info().has_separate_meters()) {
929 /* no drawing here, for now */
932 } else if (_block_screen_redisplay_until) {
934 /* timeout reached, reset */
936 _block_screen_redisplay_until = 0;
937 reshow_vpot_mode = true;
941 if (_block_vpot_mode_redisplay_until >= now) {
943 } else if (_block_vpot_mode_redisplay_until) {
945 /* timeout reached, reset */
947 _block_vpot_mode_redisplay_until = 0;
948 reshow_vpot_mode = true;
955 if (reshow_vpot_mode) {
956 return_to_vpot_mode_display ();
958 /* no point doing this if we just switched back to vpot mode
960 update_automation ();
968 Strip::redisplay (ARDOUR::microseconds_t now)
970 RedisplayRequest req;
971 bool have_request = false;
973 while (redisplay_requests.read (&req, 1) == 1) {
978 if (_block_screen_redisplay_until >= now) {
983 do_parameter_display (req.type, req.val);
988 Strip::update_automation ()
990 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
992 if (gain_state == Touch || gain_state == Play) {
993 notify_gain_changed (false);
996 if (_route->panner()) {
997 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
998 if (panner_state == Touch || panner_state == Play) {
999 notify_panner_azi_changed (false);
1000 notify_panner_width_changed (false);
1003 if (_route->trim() && route()->trim()->active()) {
1004 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1005 if (trim_state == Touch || trim_state == Play) {
1006 notify_trim_changed (false);
1012 Strip::update_meter ()
1014 if (_meter && _transport_is_rolling && _metering_active) {
1015 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1016 _meter->send_update (*_surface, dB);
1023 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1024 _surface->write ((*it)->zero ());
1027 _surface->write (blank_display (0));
1028 _surface->write (blank_display (1));
1032 Strip::blank_display (uint32_t line_number)
1034 return display (line_number, string());
1038 Strip::display (uint32_t line_number, const std::string& line)
1040 assert (line_number <= 1);
1042 MidiByteArray retval;
1044 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1047 retval << _surface->sysex_hdr();
1051 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1052 retval << (_index * 7 + (line_number * 0x38));
1054 // ascii data to display. @param line is UTF-8
1055 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1056 string::size_type len = ascii.length();
1058 ascii = ascii.substr (0, 6);
1062 // pad with " " out to 6 chars
1063 for (int i = len; i < 6; ++i) {
1067 // column spacer, unless it's the right-hand column
1073 retval << MIDI::eox;
1079 Strip::lock_controls ()
1081 _controls_locked = true;
1085 Strip::unlock_controls ()
1087 _controls_locked = false;
1091 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1093 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1094 if ((*i) == _route) {
1095 _surface->write (_select->set_state (on));
1100 _surface->write (_select->set_state (off));
1104 Strip::vpot_mode_string ()
1106 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1111 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1113 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1115 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1116 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1117 } else if (control_by_parameter.find (SendAutomation)->second == _vpot) {
1118 // should be bus name
1119 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1123 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1125 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1127 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1129 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1131 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1139 Strip::potmode_changed (bool notify)
1146 int pm = _surface->mcp().pot_mode();
1148 case MackieControlProtocol::Pan:
1149 // This needs to set current pan mode (azimuth or width... or whatever)
1150 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1151 set_vpot_parameter (_pan_mode);
1153 case MackieControlProtocol::Trim:
1154 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1155 set_vpot_parameter (_trim_mode);
1157 case MackieControlProtocol::Send:
1158 // _current_send has the number of the send we will show
1159 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1160 set_vpot_parameter (SendAutomation);
1170 Strip::block_screen_display_for (uint32_t msecs)
1172 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1176 Strip::block_vpot_mode_display_for (uint32_t msecs)
1178 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1182 Strip::return_to_vpot_mode_display ()
1184 /* returns the second line of the two-line per-strip display
1185 back the mode where it shows what the VPot controls.
1189 _surface->write (display (1, vpot_mode_string()));
1191 _surface->write (blank_display (1));
1196 Strip::next_pot_mode ()
1198 vector<Evoral::Parameter>::iterator i;
1200 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1201 /* do not change vpot mode while in flipped mode */
1202 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1203 _surface->write (display (1, "Flip"));
1204 block_vpot_mode_display_for (1000);
1209 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1214 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1215 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1219 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1220 if ((*i) == ac->parameter()) {
1225 /* move to the next mode in the list, or back to the start (which will
1226 also happen if the current mode is not in the current pot mode list)
1229 if (i != possible_pot_parameters.end()) {
1233 if (i == possible_pot_parameters.end()) {
1234 i = possible_pot_parameters.begin();
1236 set_vpot_parameter (*i);
1237 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1238 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1242 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1243 if ((*i) == ac->parameter()) {
1247 if ((*i).type() == PhaseAutomation && _route->phase_invert().size() > 1) {
1248 // There are more than one channel of phase
1249 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1250 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1251 set_vpot_parameter (*i);
1254 _route->phase_control()->set_channel(0);
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_trim_parameters.end()) {
1265 if (i == possible_trim_parameters.end()) {
1266 i = possible_trim_parameters.begin();
1268 set_vpot_parameter (*i);
1269 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Send) {
1270 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1274 p = _route->nth_send (_current_send + 1);
1275 if (p && p->name() != "Monitor 1") {
1280 set_vpot_parameter (SendAutomation);
1285 Strip::set_vpot_parameter (Evoral::Parameter p)
1287 boost::shared_ptr<Pannable> pannable;
1289 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p.type()));
1291 reset_saved_values ();
1293 /* unset any mapping between the vpot and any existing parameters */
1295 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1297 if (i != control_by_parameter.end() && i->second == _vpot) {
1303 case PanAzimuthAutomation:
1304 _pan_mode = PanAzimuthAutomation;
1305 pannable = _route->pannable ();
1306 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1307 /* gain to vpot, pan azi to fader */
1308 _vpot->set_control (_route->group_gain_control());
1309 control_by_parameter[GainAutomation] = _vpot;
1311 _fader->set_control (pannable->pan_azimuth_control);
1312 control_by_parameter[PanAzimuthAutomation] = _fader;
1314 _fader->set_control (boost::shared_ptr<AutomationControl>());
1315 control_by_parameter[PanAzimuthAutomation] = 0;
1318 /* gain to fader, pan azi to vpot */
1319 _fader->set_control (_route->group_gain_control());
1320 control_by_parameter[GainAutomation] = _fader;
1322 _vpot->set_control (pannable->pan_azimuth_control);
1323 control_by_parameter[PanAzimuthAutomation] = _vpot;
1325 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1326 control_by_parameter[PanAzimuthAutomation] = 0;
1330 case PanWidthAutomation:
1331 _pan_mode = PanWidthAutomation;
1332 pannable = _route->pannable ();
1333 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1334 /* gain to vpot, pan width to fader */
1335 _vpot->set_control (_route->group_gain_control());
1336 control_by_parameter[GainAutomation] = _vpot;
1338 _fader->set_control (pannable->pan_width_control);
1339 control_by_parameter[PanWidthAutomation] = _fader;
1341 _fader->set_control (boost::shared_ptr<AutomationControl>());
1342 control_by_parameter[PanWidthAutomation] = 0;
1345 /* gain to fader, pan width to vpot */
1346 _fader->set_control (_route->group_gain_control());
1347 control_by_parameter[GainAutomation] = _fader;
1349 _vpot->set_control (pannable->pan_width_control);
1350 control_by_parameter[PanWidthAutomation] = _vpot;
1352 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1353 control_by_parameter[PanWidthAutomation] = 0;
1357 case PanElevationAutomation:
1359 case PanFrontBackAutomation:
1361 case PanLFEAutomation:
1363 case TrimAutomation:
1364 _trim_mode = TrimAutomation;
1365 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1366 /* gain to vpot, trim to fader */
1367 _vpot->set_control (_route->group_gain_control());
1368 control_by_parameter[GainAutomation] = _vpot;
1369 if (_route->trim() && route()->trim()->active()) {
1370 _fader->set_control (_route->trim_control());
1371 control_by_parameter[TrimAutomation] = _fader;
1373 _fader->set_control (boost::shared_ptr<AutomationControl>());
1374 control_by_parameter[TrimAutomation] = 0;
1377 /* gain to fader, trim to vpot */
1378 _fader->set_control (_route->group_gain_control());
1379 control_by_parameter[GainAutomation] = _fader;
1380 if (_route->trim() && route()->trim()->active()) {
1381 _vpot->set_control (_route->trim_control());
1382 control_by_parameter[TrimAutomation] = _vpot;
1384 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1385 control_by_parameter[TrimAutomation] = 0;
1389 case PhaseAutomation:
1390 _trim_mode = PhaseAutomation;
1391 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1392 /* gain to vpot, phase to fader */
1393 _vpot->set_control (_route->group_gain_control());
1394 control_by_parameter[GainAutomation] = _vpot;
1395 if (_route->phase_invert().size()) {
1396 _fader->set_control (_route->phase_control());
1397 control_by_parameter[PhaseAutomation] = _fader;
1399 _fader->set_control (boost::shared_ptr<AutomationControl>());
1400 control_by_parameter[PhaseAutomation] = 0;
1403 /* gain to fader, phase to vpot */
1404 _fader->set_control (_route->group_gain_control());
1405 control_by_parameter[GainAutomation] = _fader;
1406 if (_route->phase_invert().size()) {
1407 _vpot->set_control (_route->phase_control());
1408 control_by_parameter[PhaseAutomation] = _vpot;
1410 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1411 control_by_parameter[PhaseAutomation] = 0;
1415 case SendAutomation:
1416 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1417 // gain to vpot, send to fader
1418 _vpot->set_control (_route->group_gain_control());
1419 control_by_parameter[GainAutomation] = _vpot;
1420 // test for send to control
1421 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1422 if (p && p->name() != "Monitor 1") {
1423 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1424 boost::shared_ptr<Amp> a = s->amp();
1425 _fader->set_control (a->gain_control());
1426 // connect to signal
1427 send_connections.drop_connections ();
1428 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1429 control_by_parameter[SendAutomation] = _fader;
1431 _fader->set_control (boost::shared_ptr<AutomationControl>());
1432 control_by_parameter[SendAutomation] = 0;
1435 // gain to fader, send to vpot
1436 _fader->set_control (_route->group_gain_control());
1437 control_by_parameter[GainAutomation] = _fader;
1438 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1439 if (p && p->name() != "Monitor 1") {
1440 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1441 boost::shared_ptr<Amp> a = s->amp();
1442 _vpot->set_control (a->gain_control());
1443 // connect to signal
1444 send_connections.drop_connections ();
1445 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1446 control_by_parameter[SendAutomation] = _vpot;
1448 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1449 control_by_parameter[SendAutomation] = 0;
1454 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1459 _surface->write (display (1, vpot_mode_string()));
1463 Strip::is_midi_track () const
1465 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1469 Strip::reset_saved_values ()
1471 _last_pan_azi_position_written = -1.0;
1472 _last_pan_width_position_written = -1.0;
1473 _last_gain_position_written = -1.0;
1474 _last_trim_position_written = -1.0;
1479 Strip::notify_metering_state_changed()
1481 if (!_route || !_meter) {
1485 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1486 bool metering_active = _surface->mcp().metering_active ();
1488 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1492 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1494 if (!transport_is_rolling || !metering_active) {
1495 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1496 notify_panner_azi_changed (true);
1499 _transport_is_rolling = transport_is_rolling;
1500 _metering_active = metering_active;