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)
104 , redisplay_requests (256)
106 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
107 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
109 if (s.mcp().device_info().has_meters()) {
110 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
113 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
114 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
115 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
116 _surface->number(), index, Button::id_to_name (bb->bid()),
117 bb->id(), b->second.base_id));
123 /* surface is responsible for deleting all controls */
127 Strip::add (Control & control)
131 Group::add (control);
133 /* fader, vpot, meter were all set explicitly */
135 if ((button = dynamic_cast<Button*>(&control)) != 0) {
136 switch (button->bid()) {
137 case Button::RecEnable:
149 case Button::VSelect:
152 case Button::FaderTouch:
153 _fader_touch = button;
162 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
164 if (_controls_locked) {
168 route_connections.drop_connections ();
170 _solo->set_control (boost::shared_ptr<AutomationControl>());
171 _mute->set_control (boost::shared_ptr<AutomationControl>());
172 _select->set_control (boost::shared_ptr<AutomationControl>());
173 _recenable->set_control (boost::shared_ptr<AutomationControl>());
174 _fader->set_control (boost::shared_ptr<AutomationControl>());
175 _vpot->set_control (boost::shared_ptr<AutomationControl>());
179 control_by_parameter.clear ();
181 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
182 control_by_parameter[PanWidthAutomation] = (Control*) 0;
183 control_by_parameter[PanElevationAutomation] = (Control*) 0;
184 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
185 control_by_parameter[PanLFEAutomation] = (Control*) 0;
186 control_by_parameter[GainAutomation] = (Control*) 0;
187 control_by_parameter[TrimAutomation] = (Control*) 0;
188 control_by_parameter[PhaseAutomation] = (Control*) 0;
190 reset_saved_values ();
197 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
198 _surface->number(), _index, _route->name()));
200 _solo->set_control (_route->solo_control());
201 _mute->set_control (_route->mute_control());
203 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
204 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
206 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
208 if (_route->trim() && route()->trim()->active()) {
209 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
212 if (_route->phase_invert().size()) {
213 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
214 _route->phase_control()->set_channel(0);
217 boost::shared_ptr<Pannable> pannable = _route->pannable();
219 if (pannable && _route->panner()) {
220 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
221 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
223 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
224 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
226 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
229 _recenable->set_control (trk->rec_enable_control());
230 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
235 // TODO this works when a currently-banked route is made inactive, but not
236 // when a route is activated which should be currently banked.
238 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
239 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
241 /* setup legal VPot modes for this route */
243 possible_pot_parameters.clear();
246 boost::shared_ptr<Panner> panner = _route->panner();
248 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
249 set<Evoral::Parameter>::iterator a;
251 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
252 possible_pot_parameters.push_back (PanAzimuthAutomation);
255 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
256 possible_pot_parameters.push_back (PanWidthAutomation);
261 if (_route->trim() && route()->trim()->active()) {
262 possible_pot_parameters.push_back (TrimAutomation);
265 possible_trim_parameters.clear();
267 if (_route->trim() && route()->trim()->active()) {
268 possible_trim_parameters.push_back (TrimAutomation);
269 _trim_mode = TrimAutomation;
272 if (_route->phase_invert().size()) {
273 possible_trim_parameters.push_back (PhaseAutomation);
274 if (_trim_mode != TrimAutomation) {
275 _trim_mode = PhaseAutomation;
280 _pan_mode = PanAzimuthAutomation;
281 potmode_changed (false);
294 notify_solo_changed ();
295 notify_mute_changed ();
296 notify_gain_changed ();
297 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
298 notify_panner_azi_changed ();
299 notify_panner_width_changed ();
300 notify_record_enable_changed ();
301 notify_trim_changed ();
302 notify_phase_changed ();
306 Strip::notify_solo_changed ()
308 if (_route && _solo) {
309 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
314 Strip::notify_mute_changed ()
316 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
317 if (_route && _mute) {
318 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
319 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
321 _surface->write (_mute->set_state (_route->muted() ? on : off));
326 Strip::notify_record_enable_changed ()
328 if (_route && _recenable) {
329 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
334 Strip::notify_active_changed ()
336 _surface->mcp().refresh_current_bank();
340 Strip::notify_route_deleted ()
342 _surface->mcp().refresh_current_bank();
346 Strip::notify_gain_changed (bool force_update)
352 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
358 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
360 float gain_coefficient = ac->get_value();
361 float normalized_position = ac->internal_to_interface (gain_coefficient);
364 if (force_update || normalized_position != _last_gain_position_written) {
366 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
367 if (!control->in_use()) {
368 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
370 queue_parameter_display (GainAutomation, gain_coefficient);
372 if (!control->in_use()) {
373 _surface->write (_fader->set_position (normalized_position));
375 queue_parameter_display (GainAutomation, gain_coefficient);
378 _last_gain_position_written = normalized_position;
384 Strip::notify_trim_changed (bool force_update)
388 if (!_route->trim() || !route()->trim()->active()) {
389 _surface->write (_vpot->zero());
392 Control* control = 0;
393 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
395 if (i == control_by_parameter.end()) {
401 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
403 float gain_coefficient = ac->get_value();
404 float normalized_position = ac->internal_to_interface (gain_coefficient);
406 if (force_update || normalized_position != _last_trim_position_written) {
407 if (control == _fader) {
408 if (!_fader->in_use()) {
409 _surface->write (_fader->set_position (normalized_position));
410 queue_parameter_display (TrimAutomation, gain_coefficient);
412 } else if (control == _vpot) {
413 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
414 queue_parameter_display (TrimAutomation, gain_coefficient);
416 _last_trim_position_written = normalized_position;
422 Strip::notify_phase_changed (bool force_update)
425 if (!_route->phase_invert().size()) {
426 _surface->write (_vpot->zero());
430 Control* control = 0;
431 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
433 if (i == control_by_parameter.end()) {
439 float normalized_position = _route->phase_control()->get_value();
441 if (control == _fader) {
442 if (!_fader->in_use()) {
443 _surface->write (_fader->set_position (normalized_position));
444 queue_parameter_display (PhaseAutomation, normalized_position);
446 } else if (control == _vpot) {
447 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
448 queue_parameter_display (PhaseAutomation, normalized_position);
454 Strip::notify_property_changed (const PropertyChange& what_changed)
456 if (!what_changed.contains (ARDOUR::Properties::name)) {
464 Strip::show_route_name ()
470 string fullname = _route->name();
472 if (fullname.length() <= 6) {
475 line1 = PBD::short_version (fullname, 6);
478 _surface->write (display (0, line1));
482 Strip::notify_panner_azi_changed (bool force_update)
486 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
488 boost::shared_ptr<Pannable> pannable = _route->pannable();
490 if (!pannable || !_route->panner()) {
491 _surface->write (_vpot->zero());
495 Control* control = 0;
496 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
498 if (i == control_by_parameter.end()) {
504 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
506 if (force_update || pos != _last_pan_azi_position_written) {
508 if (control == _fader) {
509 if (!_fader->in_use()) {
510 _surface->write (_fader->set_position (pos));
511 queue_parameter_display (PanAzimuthAutomation, pos);
513 } else if (control == _vpot) {
514 _surface->write (_vpot->set (pos, true, Pot::dot));
515 queue_parameter_display (PanAzimuthAutomation, pos);
518 _last_pan_azi_position_written = pos;
524 Strip::notify_panner_width_changed (bool force_update)
528 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width 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 (PanWidthAutomation);
540 if (i == control_by_parameter.end()) {
546 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
548 if (force_update || pos != _last_pan_azi_position_written) {
550 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
552 if (control == _fader) {
553 if (!control->in_use()) {
554 _surface->write (_fader->set_position (pos));
555 queue_parameter_display (PanWidthAutomation, pos);
559 } else if (control == _vpot) {
560 _surface->write (_vpot->set (pos, true, Pot::spread));
561 queue_parameter_display (PanWidthAutomation, pos);
564 _last_pan_azi_position_written = pos;
570 Strip::select_event (Button&, ButtonState bs)
572 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
576 int ms = _surface->mcp().main_modifier_state();
578 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
579 _controls_locked = !_controls_locked;
580 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
581 block_vpot_mode_display_for (1000);
585 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
586 /* reset to default */
587 boost::shared_ptr<AutomationControl> ac = _fader->control ();
589 ac->set_value (ac->normal());
594 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
595 _surface->mcp().add_down_select_button (_surface->number(), _index);
596 _surface->mcp().select_range ();
599 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
600 _surface->mcp().remove_down_select_button (_surface->number(), _index);
605 Strip::vselect_event (Button&, ButtonState bs)
609 int ms = _surface->mcp().main_modifier_state();
611 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
613 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
617 /* reset to default/normal value */
618 ac->set_value (ac->normal());
623 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
631 Strip::fader_touch_event (Button&, ButtonState bs)
633 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
637 boost::shared_ptr<AutomationControl> ac = _fader->control ();
639 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
641 ac->set_value (ac->normal());
645 _fader->set_in_use (true);
646 _fader->start_touch (_surface->mcp().transport_frame());
649 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
655 _fader->set_in_use (false);
656 _fader->stop_touch (_surface->mcp().transport_frame(), true);
663 Strip::handle_button (Button& button, ButtonState bs)
665 boost::shared_ptr<AutomationControl> control;
668 button.set_in_use (true);
670 button.set_in_use (false);
673 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
675 switch (button.bid()) {
677 select_event (button, bs);
680 case Button::VSelect:
681 vselect_event (button, bs);
684 case Button::FaderTouch:
685 fader_touch_event (button, bs);
689 if ((control = button.control ())) {
691 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
692 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
695 int ms = _surface->mcp().main_modifier_state();
697 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
698 /* reset to default/normal value */
699 new_value = control->normal();
701 new_value = control->get_value() ? 0.0 : 1.0;
704 /* get all controls that either have their
705 * button down or are within a range of
706 * several down buttons
709 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
712 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
713 controls.size(), control->parameter().type(), new_value));
717 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
718 (*c)->set_value (new_value);
722 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
723 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
731 Strip::queue_parameter_display (AutomationType type, float val)
733 RedisplayRequest req;
738 redisplay_requests.write (&req, 1);
742 Strip::do_parameter_display (AutomationType type, float val)
744 bool screen_hold = false;
749 _surface->write (display (1, " -inf "));
752 float dB = accurate_coefficient_to_dB (val);
753 snprintf (buf, sizeof (buf), "%6.1f", dB);
754 _surface->write (display (1, buf));
759 case PanAzimuthAutomation:
761 boost::shared_ptr<Pannable> p = _route->pannable();
762 if (p && _route->panner()) {
763 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
764 _surface->write (display (1, str));
770 case PanWidthAutomation:
773 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
774 _surface->write (display (1, buf));
782 float dB = accurate_coefficient_to_dB (val);
783 snprintf (buf, sizeof (buf), "%6.1f", dB);
784 _surface->write (display (1, buf));
789 case PhaseAutomation:
791 if (_route->phase_control()->get_value() < 0.5) {
792 _surface->write (display (1, "Normal"));
794 _surface->write (display (1, "Invert"));
805 block_vpot_mode_display_for (1000);
810 Strip::handle_fader_touch (Fader& fader, bool touch_on)
813 fader.start_touch (_surface->mcp().transport_frame());
815 fader.stop_touch (_surface->mcp().transport_frame(), false);
820 Strip::handle_fader (Fader& fader, float position)
822 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
823 boost::shared_ptr<AutomationControl> ac = fader.control();
828 fader.set_value (position);
830 /* From the Mackie Control MIDI implementation docs:
832 In order to ensure absolute synchronization with the host software,
833 Mackie Control uses a closed-loop servo system for the faders,
834 meaning the faders will always move to their last received position.
835 When a host receives a Fader Position Message, it must then
836 re-transmit that message to the Mackie Control or else the faders
837 will return to their last position.
840 _surface->write (fader.set_position (position));
844 Strip::handle_pot (Pot& pot, float delta)
846 /* Pots only emit events when they move, not when they
847 stop moving. So to get a stop event, we need to use a timeout.
850 boost::shared_ptr<AutomationControl> ac = pot.control();
854 double p = pot.get_value ();
856 p = max (ac->lower(), p);
857 p = min (ac->upper(), p);
862 Strip::periodic (ARDOUR::microseconds_t now)
864 bool reshow_vpot_mode = false;
865 bool reshow_name = false;
871 if (_block_screen_redisplay_until >= now) {
872 if (_surface->mcp().device_info().has_separate_meters()) {
875 /* no drawing here, for now */
878 } else if (_block_screen_redisplay_until) {
880 /* timeout reached, reset */
882 _block_screen_redisplay_until = 0;
883 reshow_vpot_mode = true;
887 if (_block_vpot_mode_redisplay_until >= now) {
889 } else if (_block_vpot_mode_redisplay_until) {
891 /* timeout reached, reset */
893 _block_vpot_mode_redisplay_until = 0;
894 reshow_vpot_mode = true;
901 if (reshow_vpot_mode) {
902 return_to_vpot_mode_display ();
904 /* no point doing this if we just switched back to vpot mode
906 update_automation ();
914 Strip::redisplay (ARDOUR::microseconds_t now)
916 RedisplayRequest req;
917 bool have_request = false;
919 while (redisplay_requests.read (&req, 1) == 1) {
924 if (_block_screen_redisplay_until >= now) {
929 do_parameter_display (req.type, req.val);
934 Strip::update_automation ()
936 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
938 if (gain_state == Touch || gain_state == Play) {
939 notify_gain_changed (false);
942 if (_route->panner()) {
943 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
944 if (panner_state == Touch || panner_state == Play) {
945 notify_panner_azi_changed (false);
946 notify_panner_width_changed (false);
949 if (_route->trim() && route()->trim()->active()) {
950 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
951 if (trim_state == Touch || trim_state == Play) {
952 notify_trim_changed (false);
958 Strip::update_meter ()
960 if (_meter && _transport_is_rolling && _metering_active) {
961 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
962 _meter->send_update (*_surface, dB);
969 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
970 _surface->write ((*it)->zero ());
973 _surface->write (blank_display (0));
974 _surface->write (blank_display (1));
978 Strip::blank_display (uint32_t line_number)
980 return display (line_number, string());
984 Strip::display (uint32_t line_number, const std::string& line)
986 assert (line_number <= 1);
988 MidiByteArray retval;
990 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
993 retval << _surface->sysex_hdr();
997 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
998 retval << (_index * 7 + (line_number * 0x38));
1000 // ascii data to display. @param line is UTF-8
1001 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1002 string::size_type len = ascii.length();
1004 ascii = ascii.substr (0, 6);
1008 // pad with " " out to 6 chars
1009 for (int i = len; i < 6; ++i) {
1013 // column spacer, unless it's the right-hand column
1019 retval << MIDI::eox;
1025 Strip::lock_controls ()
1027 _controls_locked = true;
1031 Strip::unlock_controls ()
1033 _controls_locked = false;
1037 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1039 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1040 if ((*i) == _route) {
1041 _surface->write (_select->set_state (on));
1046 _surface->write (_select->set_state (off));
1050 Strip::vpot_mode_string () const
1052 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1058 switch (ac->parameter().type()) {
1059 case GainAutomation:
1061 case TrimAutomation:
1063 case PhaseAutomation:
1064 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1065 case PanAzimuthAutomation:
1067 case PanWidthAutomation:
1069 case PanElevationAutomation:
1071 case PanFrontBackAutomation:
1073 case PanLFEAutomation:
1081 Strip::potmode_changed (bool notify)
1088 int pm = _surface->mcp().pot_mode();
1090 case MackieControlProtocol::Pan:
1091 // This needs to set current pan mode (azimuth or width... or whatever)
1092 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1093 set_vpot_parameter (_pan_mode);
1095 case MackieControlProtocol::Trim:
1096 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1097 set_vpot_parameter (_trim_mode);
1099 case MackieControlProtocol::Send:
1100 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1101 set_vpot_parameter (SendAutomation);
1111 Strip::block_screen_display_for (uint32_t msecs)
1113 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1117 Strip::block_vpot_mode_display_for (uint32_t msecs)
1119 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1123 Strip::return_to_vpot_mode_display ()
1125 /* returns the second line of the two-line per-strip display
1126 back the mode where it shows what the VPot controls.
1130 _surface->write (display (1, vpot_mode_string()));
1132 _surface->write (blank_display (1));
1137 Strip::next_pot_mode ()
1139 vector<Evoral::Parameter>::iterator i;
1141 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1142 /* do not change vpot mode while in flipped mode */
1143 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1144 _surface->write (display (1, "Flip"));
1145 block_vpot_mode_display_for (1000);
1150 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1155 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1156 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1160 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1161 if ((*i) == ac->parameter()) {
1166 /* move to the next mode in the list, or back to the start (which will
1167 also happen if the current mode is not in the current pot mode list)
1170 if (i != possible_pot_parameters.end()) {
1174 if (i == possible_pot_parameters.end()) {
1175 i = possible_pot_parameters.begin();
1177 set_vpot_parameter (*i);
1178 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1179 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1183 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1184 if ((*i) == ac->parameter()) {
1188 if ((*i).type() == PhaseAutomation && _route->phase_invert().size() > 1) {
1189 // There are more than one channel of phase
1190 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1191 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1192 set_vpot_parameter (*i);
1195 _route->phase_control()->set_channel(0);
1198 /* move to the next mode in the list, or back to the start (which will
1199 also happen if the current mode is not in the current pot mode list)
1202 if (i != possible_trim_parameters.end()) {
1206 if (i == possible_trim_parameters.end()) {
1207 i = possible_trim_parameters.begin();
1209 set_vpot_parameter (*i);
1215 Strip::set_vpot_parameter (Evoral::Parameter p)
1217 boost::shared_ptr<Pannable> pannable;
1219 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p.type()));
1221 reset_saved_values ();
1223 /* unset any mapping between the vpot and any existing parameters */
1225 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1227 if (i != control_by_parameter.end() && i->second == _vpot) {
1233 case PanAzimuthAutomation:
1234 _pan_mode = PanAzimuthAutomation;
1235 pannable = _route->pannable ();
1236 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1237 /* gain to vpot, pan azi to fader */
1238 _vpot->set_control (_route->gain_control());
1239 control_by_parameter[GainAutomation] = _vpot;
1241 _fader->set_control (pannable->pan_azimuth_control);
1242 control_by_parameter[PanAzimuthAutomation] = _fader;
1244 _fader->set_control (boost::shared_ptr<AutomationControl>());
1245 control_by_parameter[PanAzimuthAutomation] = 0;
1248 /* gain to fader, pan azi to vpot */
1249 _fader->set_control (_route->gain_control());
1250 control_by_parameter[GainAutomation] = _fader;
1252 _vpot->set_control (pannable->pan_azimuth_control);
1253 control_by_parameter[PanAzimuthAutomation] = _vpot;
1255 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1256 control_by_parameter[PanAzimuthAutomation] = 0;
1260 case PanWidthAutomation:
1261 _pan_mode = PanWidthAutomation;
1262 pannable = _route->pannable ();
1263 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1264 /* gain to vpot, pan width to fader */
1265 _vpot->set_control (_route->gain_control());
1266 control_by_parameter[GainAutomation] = _vpot;
1268 _fader->set_control (pannable->pan_width_control);
1269 control_by_parameter[PanWidthAutomation] = _fader;
1271 _fader->set_control (boost::shared_ptr<AutomationControl>());
1272 control_by_parameter[PanWidthAutomation] = 0;
1275 /* gain to fader, pan width to vpot */
1276 _fader->set_control (_route->gain_control());
1277 control_by_parameter[GainAutomation] = _fader;
1279 _vpot->set_control (pannable->pan_width_control);
1280 control_by_parameter[PanWidthAutomation] = _vpot;
1282 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1283 control_by_parameter[PanWidthAutomation] = 0;
1287 case PanElevationAutomation:
1289 case PanFrontBackAutomation:
1291 case PanLFEAutomation:
1293 case TrimAutomation:
1294 _trim_mode = TrimAutomation;
1295 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1296 /* gain to vpot, trim to fader */
1297 _vpot->set_control (_route->gain_control());
1298 control_by_parameter[GainAutomation] = _vpot;
1299 if (_route->trim() && route()->trim()->active()) {
1300 _fader->set_control (_route->trim_control());
1301 control_by_parameter[TrimAutomation] = _fader;
1303 _fader->set_control (boost::shared_ptr<AutomationControl>());
1304 control_by_parameter[TrimAutomation] = 0;
1307 /* gain to fader, trim to vpot */
1308 _fader->set_control (_route->gain_control());
1309 control_by_parameter[GainAutomation] = _fader;
1310 if (_route->trim() && route()->trim()->active()) {
1311 _vpot->set_control (_route->trim_control());
1312 control_by_parameter[TrimAutomation] = _vpot;
1314 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1315 control_by_parameter[TrimAutomation] = 0;
1319 case PhaseAutomation:
1320 _trim_mode = PhaseAutomation;
1321 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1322 /* gain to vpot, phase to fader */
1323 _vpot->set_control (_route->gain_control());
1324 control_by_parameter[GainAutomation] = _vpot;
1325 if (_route->phase_invert().size()) {
1326 _fader->set_control (_route->phase_control());
1327 control_by_parameter[PhaseAutomation] = _fader;
1329 _fader->set_control (boost::shared_ptr<AutomationControl>());
1330 control_by_parameter[PhaseAutomation] = 0;
1333 /* gain to fader, phase to vpot */
1334 _fader->set_control (_route->gain_control());
1335 control_by_parameter[GainAutomation] = _fader;
1336 if (_route->phase_invert().size()) {
1337 _vpot->set_control (_route->phase_control());
1338 control_by_parameter[PhaseAutomation] = _vpot;
1340 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1341 control_by_parameter[PhaseAutomation] = 0;
1345 case SendAutomation:
1346 // deal with sends ... needs sends yet :)
1347 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1348 // gain to vpot, trim to fader
1349 _vpot->set_control (_route->gain_control());
1350 control_by_parameter[GainAutomation] = _vpot;
1351 _fader->set_control (boost::shared_ptr<AutomationControl>());
1353 // gain to fader, trim to vpot
1354 _fader->set_control (_route->gain_control());
1355 control_by_parameter[GainAutomation] = _fader;
1356 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1360 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1365 _surface->write (display (1, vpot_mode_string()));
1369 Strip::is_midi_track () const
1371 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1375 Strip::reset_saved_values ()
1377 _last_pan_azi_position_written = -1.0;
1378 _last_pan_width_position_written = -1.0;
1379 _last_gain_position_written = -1.0;
1380 _last_trim_position_written = -1.0;
1385 Strip::notify_metering_state_changed()
1387 if (!_route || !_meter) {
1391 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1392 bool metering_active = _surface->mcp().metering_active ();
1394 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1398 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1400 if (!transport_is_rolling || !metering_active) {
1401 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1402 notify_panner_azi_changed (true);
1405 _transport_is_rolling = transport_is_rolling;
1406 _metering_active = metering_active;