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 , vpot_parameter (PanAzimuthAutomation)
103 , _last_gain_position_written (-1.0)
104 , _last_pan_azi_position_written (-1.0)
105 , _last_pan_width_position_written (-1.0)
106 , _last_trim_position_written (-1.0)
108 , redisplay_requests (256)
110 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
111 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
113 if (s.mcp().device_info().has_meters()) {
114 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
117 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
118 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
119 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
120 _surface->number(), index, Button::id_to_name (bb->bid()),
121 bb->id(), b->second.base_id));
127 /* surface is responsible for deleting all controls */
131 Strip::add (Control & control)
135 Group::add (control);
137 /* fader, vpot, meter were all set explicitly */
139 if ((button = dynamic_cast<Button*>(&control)) != 0) {
140 switch (button->bid()) {
141 case Button::RecEnable:
153 case Button::VSelect:
156 case Button::FaderTouch:
157 _fader_touch = button;
166 Strip::set_route (boost::shared_ptr<Route> r, bool /*with_messages*/)
168 if (_controls_locked) {
172 mb_pan_controllable.reset();
174 route_connections.drop_connections ();
176 _solo->set_control (boost::shared_ptr<AutomationControl>());
177 _mute->set_control (boost::shared_ptr<AutomationControl>());
178 _select->set_control (boost::shared_ptr<AutomationControl>());
179 _recenable->set_control (boost::shared_ptr<AutomationControl>());
180 _fader->set_control (boost::shared_ptr<AutomationControl>());
181 _vpot->set_control (boost::shared_ptr<AutomationControl>());
185 control_by_parameter.clear ();
187 control_by_parameter[PanAzimuthAutomation] = (Control*) 0;
188 control_by_parameter[PanWidthAutomation] = (Control*) 0;
189 control_by_parameter[PanElevationAutomation] = (Control*) 0;
190 control_by_parameter[PanFrontBackAutomation] = (Control*) 0;
191 control_by_parameter[PanLFEAutomation] = (Control*) 0;
192 control_by_parameter[GainAutomation] = (Control*) 0;
193 control_by_parameter[TrimAutomation] = (Control*) 0;
194 control_by_parameter[PhaseAutomation] = (Control*) 0;
195 control_by_parameter[SendAutomation] = (Control*) 0;
196 control_by_parameter[EQParam1] = (Control*) 0;
197 control_by_parameter[EQParam2] = (Control*) 0;
198 control_by_parameter[EQParam3] = (Control*) 0;
199 control_by_parameter[EQParam4] = (Control*) 0;
200 control_by_parameter[EQParam5] = (Control*) 0;
201 control_by_parameter[EQParam6] = (Control*) 0;
202 control_by_parameter[EQParam7] = (Control*) 0;
203 control_by_parameter[EQParam8] = (Control*) 0;
205 reset_saved_values ();
212 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
213 _surface->number(), _index, _route->name()));
215 _solo->set_control (_route->solo_control());
216 _mute->set_control (_route->mute_control());
218 _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
219 _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
221 _route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
223 if (_route->trim() && route()->trim()->active()) {
224 _route->trim_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trim_changed, this, false), ui_context());
227 if (_route->phase_invert().size()) {
228 _route->phase_invert_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_phase_changed, this, false), ui_context());
229 _route->phase_control()->set_channel(0);
232 boost::shared_ptr<Pannable> pannable = _route->pannable();
234 if(Profile->get_mixbus()) {
235 const uint32_t port_channel_post_pan = 2; // gtk2_ardour/mixbus_ports.h
236 boost::shared_ptr<ARDOUR::PluginInsert> plug = _route->ch_post();
237 mb_pan_controllable = boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_pan)));
239 mb_pan_controllable->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
241 if (pannable && _route->panner()) {
242 pannable->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
243 pannable->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
247 _route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
248 _route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
250 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
253 _recenable->set_control (trk->rec_enable_control());
254 trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_record_enable_changed, this), ui_context());
259 // TODO this works when a currently-banked route is made inactive, but not
260 // when a route is activated which should be currently banked.
262 _route->active_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_active_changed, this), ui_context());
263 _route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_route_deleted, this), ui_context());
265 /* setup legal VPot modes for this route */
267 possible_pot_parameters.clear();
269 if (Profile->get_mixbus()) {
270 possible_pot_parameters.push_back (PanAzimuthAutomation);
273 boost::shared_ptr<Panner> panner = _route->panner();
275 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
276 set<Evoral::Parameter>::iterator a;
278 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
279 possible_pot_parameters.push_back (PanAzimuthAutomation);
282 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
283 possible_pot_parameters.push_back (PanWidthAutomation);
289 if (_route->trim() && route()->trim()->active()) {
290 possible_pot_parameters.push_back (TrimAutomation);
293 possible_trim_parameters.clear();
295 if (_route->trim() && route()->trim()->active()) {
296 possible_trim_parameters.push_back (TrimAutomation);
297 _trim_mode = TrimAutomation;
300 if (_route->phase_invert().size()) {
301 possible_trim_parameters.push_back (PhaseAutomation);
302 _route->phase_control()->set_channel(0);
303 if (_trim_mode != TrimAutomation) {
304 _trim_mode = PhaseAutomation;
309 _pan_mode = PanAzimuthAutomation;
310 potmode_changed (false);
323 notify_solo_changed ();
324 notify_mute_changed ();
325 notify_gain_changed ();
326 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
327 notify_panner_azi_changed ();
328 notify_panner_width_changed ();
329 notify_record_enable_changed ();
330 notify_trim_changed ();
331 notify_phase_changed ();
332 notify_processor_changed ();
336 Strip::notify_solo_changed ()
338 if (_route && _solo) {
339 _surface->write (_solo->set_state ((_route->soloed() || _route->listening_via_monitor()) ? on : off));
344 Strip::notify_mute_changed ()
346 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
347 if (_route && _mute) {
348 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
349 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
351 _surface->write (_mute->set_state (_route->muted() ? on : off));
356 Strip::notify_record_enable_changed ()
358 if (_route && _recenable) {
359 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
364 Strip::notify_active_changed ()
366 _surface->mcp().refresh_current_bank();
370 Strip::notify_route_deleted ()
372 _surface->mcp().refresh_current_bank();
376 Strip::notify_gain_changed (bool force_update)
382 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
388 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
390 float gain_coefficient = ac->get_value();
391 float normalized_position = ac->internal_to_interface (gain_coefficient);
394 if (force_update || normalized_position != _last_gain_position_written) {
396 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
397 if (!control->in_use()) {
398 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
400 queue_parameter_display (GainAutomation, gain_coefficient);
402 if (!control->in_use()) {
403 _surface->write (_fader->set_position (normalized_position));
405 queue_parameter_display (GainAutomation, gain_coefficient);
408 _last_gain_position_written = normalized_position;
414 Strip::notify_trim_changed (bool force_update)
418 if (!_route->trim() || !route()->trim()->active()) {
419 _surface->write (_vpot->zero());
422 Control* control = 0;
423 ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation);
425 if (i == control_by_parameter.end()) {
431 boost::shared_ptr<AutomationControl> ac = _route->trim_control();
433 float gain_coefficient = ac->get_value();
434 float normalized_position = ac->internal_to_interface (gain_coefficient);
436 if (force_update || normalized_position != _last_trim_position_written) {
437 if (control == _fader) {
438 if (!_fader->in_use()) {
439 _surface->write (_fader->set_position (normalized_position));
440 queue_parameter_display (TrimAutomation, gain_coefficient);
442 } else if (control == _vpot) {
443 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
444 queue_parameter_display (TrimAutomation, gain_coefficient);
446 _last_trim_position_written = normalized_position;
452 Strip::notify_phase_changed (bool force_update)
455 if (!_route->phase_invert().size()) {
456 _surface->write (_vpot->zero());
460 Control* control = 0;
461 ControlParameterMap::iterator i = control_by_parameter.find (PhaseAutomation);
463 if (i == control_by_parameter.end()) {
469 float normalized_position = _route->phase_control()->get_value();
471 if (control == _fader) {
472 if (!_fader->in_use()) {
473 _surface->write (_fader->set_position (normalized_position));
474 queue_parameter_display (PhaseAutomation, normalized_position);
476 } else if (control == _vpot) {
477 _surface->write (_vpot->set (normalized_position, true, Pot::wrap));
478 queue_parameter_display (PhaseAutomation, normalized_position);
484 Strip::notify_processor_changed (bool force_update)
487 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
489 _surface->write (_vpot->zero());
493 Control* control = 0;
494 ControlParameterMap::iterator i = control_by_parameter.find (SendAutomation);
496 if (i == control_by_parameter.end()) {
502 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
503 boost::shared_ptr<Amp> a = s->amp();
504 boost::shared_ptr<AutomationControl> ac = a->gain_control();
506 float gain_coefficient = ac->get_value();
507 float normalized_position = ac->internal_to_interface (gain_coefficient);
509 if (control == _fader) {
510 if (!_fader->in_use()) {
511 _surface->write (_fader->set_position (normalized_position));
512 queue_parameter_display (SendAutomation, gain_coefficient);
514 } else if (control == _vpot) {
515 _surface->write (_vpot->set (normalized_position, true, Pot::dot));
516 queue_parameter_display (SendAutomation, gain_coefficient);
522 Strip::notify_property_changed (const PropertyChange& what_changed)
524 if (!what_changed.contains (ARDOUR::Properties::name)) {
532 Strip::show_route_name ()
534 MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
536 if (svm == MackieControlProtocol::None) {
541 string fullname = _route->name();
543 if (fullname.length() <= 6) {
546 line1 = PBD::short_version (fullname, 6);
549 _surface->write (display (0, line1));
551 } else if (svm == MackieControlProtocol::EQ) {
552 if (_vpot == control_by_parameter[EQParam1]) {
553 _surface->write (display (0, "HiFreq"));
554 } else if (_vpot == control_by_parameter[EQParam2]) {
555 _surface->write (display (0, "HiGain"));
556 } else if (_vpot == control_by_parameter[EQParam3]) {
557 _surface->write (display (0, "MidFreq"));
558 } else if (_vpot == control_by_parameter[EQParam4]) {
559 _surface->write (display (0, "MidGain"));
560 } else if (_vpot == control_by_parameter[EQParam5]) {
561 _surface->write (display (0, "LoFreq"));
562 } else if (_vpot == control_by_parameter[EQParam6]) {
563 _surface->write (display (0, "LoGain"));
564 } else if (_vpot == control_by_parameter[EQParam7]) {
565 _surface->write (display (0, "HPFreq"));
566 } else if (_vpot == control_by_parameter[EQParam8]) {
567 _surface->write (display (0, "In/Out"));
569 } else if (svm == MackieControlProtocol::Dynamics) {
576 Strip::notify_eq_change (AutomationType p, uint32_t port_number, bool force_update)
578 if (!_subview_route) {
579 /* no longer in EQ subview mode */
583 if (_vpot != control_by_parameter[p]) {
584 /* vpot is no longer controlling this EQ parameter */
588 boost::shared_ptr<PluginInsert> eq = _subview_route->ch_eq();
591 boost::shared_ptr<AutomationControl> control = boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_number)));
594 float val = control->get_value();
595 queue_parameter_display (p, val);
596 _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
602 Strip::notify_panner_azi_changed (bool force_update)
606 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
608 boost::shared_ptr<Pannable> pannable = _route->pannable();
610 if (!pannable || !_route->panner()) {
611 _surface->write (_vpot->zero());
615 Control* control = 0;
616 ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation);
618 if (i == control_by_parameter.end()) {
624 double pos = mb_pan_controllable->internal_to_interface (mb_pan_controllable->get_value());
626 if (force_update || pos != _last_pan_azi_position_written) {
628 if (control == _fader) {
629 if (!_fader->in_use()) {
630 _surface->write (_fader->set_position (pos));
631 queue_parameter_display (PanAzimuthAutomation, pos);
633 } else if (control == _vpot) {
634 _surface->write (_vpot->set (pos, true, Pot::dot));
635 queue_parameter_display (PanAzimuthAutomation, pos);
638 _last_pan_azi_position_written = pos;
644 Strip::notify_panner_width_changed (bool force_update)
648 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan width change for strip %1\n", _index));
650 boost::shared_ptr<Pannable> pannable = _route->pannable();
652 if (!pannable || !_route->panner()) {
653 _surface->write (_vpot->zero());
657 Control* control = 0;
658 ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation);
660 if (i == control_by_parameter.end()) {
666 double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value());
668 if (force_update || pos != _last_pan_width_position_written) {
670 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
672 if (control == _fader) {
673 if (!control->in_use()) {
674 _surface->write (_fader->set_position (pos));
675 queue_parameter_display (PanWidthAutomation, pos);
679 } else if (control == _vpot) {
680 _surface->write (_vpot->set (pos, true, Pot::spread));
681 queue_parameter_display (PanWidthAutomation, pos);
684 _last_pan_width_position_written = pos;
690 Strip::select_event (Button&, ButtonState bs)
692 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
696 int ms = _surface->mcp().main_modifier_state();
698 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
699 _controls_locked = !_controls_locked;
700 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
701 block_vpot_mode_display_for (1000);
705 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
706 /* reset to default */
707 boost::shared_ptr<AutomationControl> ac = _fader->control ();
709 ac->set_value (ac->normal());
714 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
715 _surface->mcp().add_down_select_button (_surface->number(), _index);
716 _surface->mcp().select_range ();
719 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
720 _surface->mcp().remove_down_select_button (_surface->number(), _index);
725 Strip::vselect_event (Button&, ButtonState bs)
729 int ms = _surface->mcp().main_modifier_state();
731 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
733 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
737 /* reset to default/normal value */
738 ac->set_value (ac->normal());
743 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
751 Strip::fader_touch_event (Button&, ButtonState bs)
753 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
757 boost::shared_ptr<AutomationControl> ac = _fader->control ();
759 if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
761 ac->set_value (ac->normal());
765 _fader->set_in_use (true);
766 _fader->start_touch (_surface->mcp().transport_frame());
769 queue_parameter_display ((AutomationType) ac->parameter().type(), ac->get_value());
775 _fader->set_in_use (false);
776 _fader->stop_touch (_surface->mcp().transport_frame(), true);
783 Strip::handle_button (Button& button, ButtonState bs)
785 boost::shared_ptr<AutomationControl> control;
788 button.set_in_use (true);
790 button.set_in_use (false);
793 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
795 switch (button.bid()) {
797 select_event (button, bs);
800 case Button::VSelect:
801 vselect_event (button, bs);
804 case Button::FaderTouch:
805 fader_touch_event (button, bs);
809 if ((control = button.control ())) {
811 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
812 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
815 int ms = _surface->mcp().main_modifier_state();
817 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
818 /* reset to default/normal value */
819 new_value = control->normal();
821 new_value = control->get_value() ? 0.0 : 1.0;
824 /* get all controls that either have their
825 * button down or are within a range of
826 * several down buttons
829 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
832 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
833 controls.size(), control->parameter().type(), new_value));
837 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
838 (*c)->set_value (new_value);
842 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
843 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
851 Strip::queue_parameter_display (AutomationType type, float val)
853 RedisplayRequest req;
858 redisplay_requests.write (&req, 1);
862 Strip::do_parameter_display (AutomationType type, float val)
864 bool screen_hold = false;
870 _surface->write (display (1, " -inf "));
872 float dB = accurate_coefficient_to_dB (val);
873 snprintf (buf, sizeof (buf), "%6.1f", dB);
874 _surface->write (display (1, buf));
879 case PanAzimuthAutomation:
880 if (Profile->get_mixbus()) {
881 snprintf (buf, sizeof (buf), "%2.1f", val);
882 _surface->write (display (1, buf));
886 boost::shared_ptr<Pannable> p = _route->pannable();
887 if (p && _route->panner()) {
888 string str =_route->panner()->value_as_string (p->pan_azimuth_control);
889 _surface->write (display (1, str));
896 case PanWidthAutomation:
898 snprintf (buf, sizeof (buf), "%5ld%%", lrintf ((val * 200.0)-100));
899 _surface->write (display (1, buf));
906 float dB = accurate_coefficient_to_dB (val);
907 snprintf (buf, sizeof (buf), "%6.1f", dB);
908 _surface->write (display (1, buf));
913 case PhaseAutomation:
915 if (_route->phase_control()->get_value() < 0.5) {
916 _surface->write (display (1, "Normal"));
918 _surface->write (display (1, "Invert"));
926 _surface->write (display (1, " -inf "));
928 float dB = accurate_coefficient_to_dB (val);
929 snprintf (buf, sizeof (buf), "%6.1f", dB);
930 _surface->write (display (1, buf));
942 snprintf (buf, sizeof (buf), "%6.1f", val);
943 _surface->write (display (1, buf));
950 block_vpot_mode_display_for (1000);
955 Strip::handle_fader_touch (Fader& fader, bool touch_on)
958 fader.start_touch (_surface->mcp().transport_frame());
960 fader.stop_touch (_surface->mcp().transport_frame(), false);
965 Strip::handle_fader (Fader& fader, float position)
967 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
968 boost::shared_ptr<AutomationControl> ac = fader.control();
973 fader.set_value (position);
975 /* From the Mackie Control MIDI implementation docs:
977 In order to ensure absolute synchronization with the host software,
978 Mackie Control uses a closed-loop servo system for the faders,
979 meaning the faders will always move to their last received position.
980 When a host receives a Fader Position Message, it must then
981 re-transmit that message to the Mackie Control or else the faders
982 will return to their last position.
985 _surface->write (fader.set_position (position));
989 Strip::handle_pot (Pot& pot, float delta)
991 /* Pots only emit events when they move, not when they
992 stop moving. So to get a stop event, we need to use a timeout.
995 boost::shared_ptr<AutomationControl> ac = pot.control();
999 double p = pot.get_value ();
1001 // fader and pot should be the same and fader is hard coded 0 -> 1
1008 Strip::periodic (ARDOUR::microseconds_t now)
1010 bool reshow_vpot_mode = false;
1011 bool reshow_name = false;
1017 if (_block_screen_redisplay_until >= now) {
1018 if (_surface->mcp().device_info().has_separate_meters()) {
1021 /* no drawing here, for now */
1024 } else if (_block_screen_redisplay_until) {
1026 /* timeout reached, reset */
1028 _block_screen_redisplay_until = 0;
1029 reshow_vpot_mode = true;
1033 if (_block_vpot_mode_redisplay_until >= now) {
1035 } else if (_block_vpot_mode_redisplay_until) {
1037 /* timeout reached, reset */
1039 _block_vpot_mode_redisplay_until = 0;
1040 reshow_vpot_mode = true;
1047 if (reshow_vpot_mode) {
1048 return_to_vpot_mode_display ();
1050 /* no point doing this if we just switched back to vpot mode
1052 update_automation ();
1060 Strip::redisplay (ARDOUR::microseconds_t now)
1062 RedisplayRequest req;
1063 bool have_request = false;
1065 while (redisplay_requests.read (&req, 1) == 1) {
1067 have_request = true;
1070 if (_block_screen_redisplay_until >= now) {
1075 do_parameter_display (req.type, req.val);
1080 Strip::update_automation ()
1082 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
1084 if (gain_state == Touch || gain_state == Play) {
1085 notify_gain_changed (false);
1088 if ( Profile->get_mixbus() ) {
1089 ARDOUR::AutoState panner_state = mb_pan_controllable->automation_state();
1090 if (panner_state == Touch || panner_state == Play) {
1091 notify_panner_azi_changed (false);
1094 if (_route->panner()) {
1095 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
1096 if (panner_state == Touch || panner_state == Play) {
1097 notify_panner_azi_changed (false);
1098 notify_panner_width_changed (false);
1102 if (_route->trim() && route()->trim()->active()) {
1103 ARDOUR::AutoState trim_state = _route->trim_control()->automation_state();
1104 if (trim_state == Touch || trim_state == Play) {
1105 notify_trim_changed (false);
1111 Strip::update_meter ()
1113 if (_meter && _transport_is_rolling && _metering_active) {
1114 float dB = const_cast<PeakMeter&> (_route->peak_meter()).meter_level (0, MeterMCP);
1115 _meter->send_update (*_surface, dB);
1122 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
1123 _surface->write ((*it)->zero ());
1126 _surface->write (blank_display (0));
1127 _surface->write (blank_display (1));
1131 Strip::blank_display (uint32_t line_number)
1133 return display (line_number, string());
1137 Strip::display (uint32_t line_number, const std::string& line)
1139 assert (line_number <= 1);
1141 MidiByteArray retval;
1143 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
1146 retval << _surface->sysex_hdr();
1150 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
1151 retval << (_index * 7 + (line_number * 0x38));
1153 // ascii data to display. @param line is UTF-8
1154 string ascii = Glib::convert_with_fallback (line, "UTF-8", "ISO-8859-1", "_");
1155 string::size_type len = ascii.length();
1157 ascii = ascii.substr (0, 6);
1161 // pad with " " out to 6 chars
1162 for (int i = len; i < 6; ++i) {
1166 // column spacer, unless it's the right-hand column
1172 retval << MIDI::eox;
1178 Strip::lock_controls ()
1180 _controls_locked = true;
1184 Strip::unlock_controls ()
1186 _controls_locked = false;
1190 Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
1192 for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
1193 if ((*i) == _route) {
1194 _surface->write (_select->set_state (on));
1199 _surface->write (_select->set_state (off));
1203 Strip::vpot_mode_string ()
1205 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1210 if (control_by_parameter.find (GainAutomation)->second == _vpot) {
1212 } else if (control_by_parameter.find (TrimAutomation)->second == _vpot) {
1214 } else if (control_by_parameter.find (PhaseAutomation)->second == _vpot) {
1215 return string_compose ("Phase%1", _route->phase_control()->channel() + 1);
1216 } else if (control_by_parameter.find (SendAutomation)->second == _vpot) {
1217 // should be bus name
1218 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1222 } else if (control_by_parameter.find (PanAzimuthAutomation)->second == _vpot) {
1224 } else if (control_by_parameter.find (PanWidthAutomation)->second == _vpot) {
1226 } else if (control_by_parameter.find (PanElevationAutomation)->second == _vpot) {
1228 } else if (control_by_parameter.find (PanFrontBackAutomation)->second == _vpot) {
1230 } else if (control_by_parameter.find (PanLFEAutomation)->second == _vpot) {
1234 if (_subview_route) {
1242 Strip::potmode_changed (bool notify)
1249 int pm = _surface->mcp().pot_mode();
1251 case MackieControlProtocol::Pan:
1252 // This needs to set current pan mode (azimuth or width... or whatever)
1253 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Assign pot to Pan mode %1\n", enum_2_string (_pan_mode)));
1254 set_vpot_parameter (_pan_mode);
1256 case MackieControlProtocol::Trim:
1257 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n");
1258 set_vpot_parameter (_trim_mode);
1260 case MackieControlProtocol::Send:
1261 // _current_send has the number of the send we will show
1262 DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n");
1263 set_vpot_parameter (SendAutomation);
1273 Strip::block_screen_display_for (uint32_t msecs)
1275 _block_screen_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1279 Strip::block_vpot_mode_display_for (uint32_t msecs)
1281 _block_vpot_mode_redisplay_until = ARDOUR::get_microseconds() + (msecs * 1000);
1285 Strip::return_to_vpot_mode_display ()
1287 /* returns the second line of the two-line per-strip display
1288 back the mode where it shows what the VPot controls.
1290 if (_subview_route) {
1291 /* do nothing - second line shows value of current subview parameter */
1293 } else if (_route) {
1294 _surface->write (display (1, vpot_mode_string()));
1296 _surface->write (blank_display (1));
1301 Strip::next_pot_mode ()
1303 vector<Evoral::Parameter>::iterator i;
1305 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1306 /* do not change vpot mode while in flipped mode */
1307 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
1308 _surface->write (display (1, "Flip"));
1309 block_vpot_mode_display_for (1000);
1314 boost::shared_ptr<AutomationControl> ac = _vpot->control();
1319 if (_surface->mcp().pot_mode() == MackieControlProtocol::Pan) {
1320 if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
1324 for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
1325 if ((*i) == ac->parameter()) {
1330 /* move to the next mode in the list, or back to the start (which will
1331 also happen if the current mode is not in the current pot mode list)
1334 if (i != possible_pot_parameters.end()) {
1338 if (i == possible_pot_parameters.end()) {
1339 i = possible_pot_parameters.begin();
1341 set_vpot_parameter (*i);
1342 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Trim) {
1343 if (possible_trim_parameters.empty() || (possible_trim_parameters.size() == 1 && possible_trim_parameters.front() == ac->parameter())) {
1347 for (i = possible_trim_parameters.begin(); i != possible_trim_parameters.end(); ++i) {
1348 if ((*i) == ac->parameter()) {
1352 if ((*i).type() == PhaseAutomation && _route->phase_invert().size() > 1) {
1353 // There are more than one channel of phase
1354 if ((_route->phase_control()->channel() + 1) < _route->phase_invert().size()) {
1355 _route->phase_control()->set_channel(_route->phase_control()->channel() + 1);
1356 set_vpot_parameter (*i);
1359 _route->phase_control()->set_channel(0);
1362 /* move to the next mode in the list, or back to the start (which will
1363 also happen if the current mode is not in the current pot mode list)
1366 if (i != possible_trim_parameters.end()) {
1370 if (i == possible_trim_parameters.end()) {
1371 i = possible_trim_parameters.begin();
1373 set_vpot_parameter (*i);
1374 } else if (_surface->mcp().pot_mode() == MackieControlProtocol::Send) {
1375 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1379 p = _route->nth_send (_current_send + 1);
1380 if (p && p->name() != "Monitor 1") {
1385 set_vpot_parameter (SendAutomation);
1390 Strip::use_subview (MackieControlProtocol::SubViewMode sm, boost::shared_ptr<Route> target_route)
1397 case MackieControlProtocol::None:
1398 if (vpot_parameter != NullAutomation) {
1399 set_vpot_parameter (vpot_parameter);
1403 case MackieControlProtocol::EQ:
1406 set_vpot_parameter (ARDOUR::EQParam1, target_route);
1409 set_vpot_parameter (ARDOUR::EQParam2, target_route);
1412 set_vpot_parameter (ARDOUR::EQParam3, target_route);
1415 set_vpot_parameter (ARDOUR::EQParam4, target_route);
1418 set_vpot_parameter (ARDOUR::EQParam5, target_route);
1421 set_vpot_parameter (ARDOUR::EQParam6, target_route);
1424 set_vpot_parameter (ARDOUR::EQParam7, target_route);
1427 set_vpot_parameter (ARDOUR::EQParam8, target_route);
1432 case MackieControlProtocol::Dynamics:
1438 Strip::set_vpot_parameter (Evoral::Parameter p, boost::shared_ptr<Route> target_route)
1440 boost::shared_ptr<Pannable> pannable;
1442 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p.type()));
1444 reset_saved_values ();
1446 /* target route is either null, or points to a route other than the one
1447 we are controlling/viewing, to be used while in a particular subview
1448 state (e.g. EQ or Dynamics)
1451 if (target_route != _subview_route) {
1452 subview_connections.drop_connections ();
1455 _subview_route = target_route;
1457 /* unset any mapping between the vpot and any existing parameters */
1459 for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) {
1461 if (i != control_by_parameter.end() && i->second == _vpot) {
1467 case PanAzimuthAutomation:
1468 _pan_mode = PanAzimuthAutomation;
1469 pannable = _route->pannable ();
1470 vpot_parameter = PanAzimuthAutomation;
1471 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1472 /* gain to vpot, pan azi to fader */
1473 _vpot->set_control (_route->group_gain_control());
1474 control_by_parameter[GainAutomation] = _vpot;
1476 _fader->set_control (mb_pan_controllable);
1477 control_by_parameter[PanAzimuthAutomation] = _fader;
1479 _fader->set_control (boost::shared_ptr<AutomationControl>());
1480 control_by_parameter[PanAzimuthAutomation] = 0;
1483 /* gain to fader, pan azi to vpot */
1484 _fader->set_control (_route->group_gain_control());
1485 control_by_parameter[GainAutomation] = _fader;
1487 _vpot->set_control (mb_pan_controllable);
1488 control_by_parameter[PanAzimuthAutomation] = _vpot;
1490 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1491 control_by_parameter[PanAzimuthAutomation] = 0;
1495 case PanWidthAutomation:
1496 _pan_mode = PanWidthAutomation;
1497 pannable = _route->pannable ();
1498 vpot_parameter = PanWidthAutomation;
1499 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1500 /* gain to vpot, pan width to fader */
1501 _vpot->set_control (_route->group_gain_control());
1502 control_by_parameter[GainAutomation] = _vpot;
1504 _fader->set_control (pannable->pan_width_control);
1505 control_by_parameter[PanWidthAutomation] = _fader;
1507 _fader->set_control (boost::shared_ptr<AutomationControl>());
1508 control_by_parameter[PanWidthAutomation] = 0;
1511 /* gain to fader, pan width to vpot */
1512 _fader->set_control (_route->group_gain_control());
1513 control_by_parameter[GainAutomation] = _fader;
1515 _vpot->set_control (pannable->pan_width_control);
1516 control_by_parameter[PanWidthAutomation] = _vpot;
1518 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1519 control_by_parameter[PanWidthAutomation] = 0;
1523 case PanElevationAutomation:
1525 case PanFrontBackAutomation:
1527 case PanLFEAutomation:
1529 case TrimAutomation:
1530 _trim_mode = TrimAutomation;
1531 vpot_parameter = TrimAutomation;
1532 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1533 /* gain to vpot, trim to fader */
1534 _vpot->set_control (_route->group_gain_control());
1535 control_by_parameter[GainAutomation] = _vpot;
1536 if (_route->trim() && route()->trim()->active()) {
1537 _fader->set_control (_route->trim_control());
1538 control_by_parameter[TrimAutomation] = _fader;
1540 _fader->set_control (boost::shared_ptr<AutomationControl>());
1541 control_by_parameter[TrimAutomation] = 0;
1544 /* gain to fader, trim to vpot */
1545 _fader->set_control (_route->group_gain_control());
1546 control_by_parameter[GainAutomation] = _fader;
1547 if (_route->trim() && route()->trim()->active()) {
1548 _vpot->set_control (_route->trim_control());
1549 control_by_parameter[TrimAutomation] = _vpot;
1551 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1552 control_by_parameter[TrimAutomation] = 0;
1556 case PhaseAutomation:
1557 _trim_mode = PhaseAutomation;
1558 vpot_parameter = PhaseAutomation;
1559 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1560 /* gain to vpot, phase to fader */
1561 _vpot->set_control (_route->group_gain_control());
1562 control_by_parameter[GainAutomation] = _vpot;
1563 if (_route->phase_invert().size()) {
1564 _fader->set_control (_route->phase_control());
1565 control_by_parameter[PhaseAutomation] = _fader;
1567 _fader->set_control (boost::shared_ptr<AutomationControl>());
1568 control_by_parameter[PhaseAutomation] = 0;
1571 /* gain to fader, phase to vpot */
1572 _fader->set_control (_route->group_gain_control());
1573 control_by_parameter[GainAutomation] = _fader;
1574 if (_route->phase_invert().size()) {
1575 _vpot->set_control (_route->phase_control());
1576 control_by_parameter[PhaseAutomation] = _vpot;
1578 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1579 control_by_parameter[PhaseAutomation] = 0;
1583 case SendAutomation:
1584 if (!Profile->get_mixbus()) {
1585 if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) {
1586 // gain to vpot, send to fader
1587 _vpot->set_control (_route->group_gain_control());
1588 control_by_parameter[GainAutomation] = _vpot;
1589 // test for send to control
1590 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1591 if (p && p->name() != "Monitor 1") {
1592 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1593 boost::shared_ptr<Amp> a = s->amp();
1594 _fader->set_control (a->gain_control());
1595 // connect to signal
1596 send_connections.drop_connections ();
1597 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1598 control_by_parameter[SendAutomation] = _fader;
1600 _fader->set_control (boost::shared_ptr<AutomationControl>());
1601 control_by_parameter[SendAutomation] = 0;
1604 // gain to fader, send to vpot
1605 _fader->set_control (_route->group_gain_control());
1606 control_by_parameter[GainAutomation] = _fader;
1607 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1608 if (p && p->name() != "Monitor 1") {
1609 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1610 boost::shared_ptr<Amp> a = s->amp();
1611 _vpot->set_control (a->gain_control());
1612 // connect to signal
1613 send_connections.drop_connections ();
1614 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1615 control_by_parameter[SendAutomation] = _vpot;
1617 // gain to fader, send to vpot
1618 _fader->set_control (_route->group_gain_control());
1619 control_by_parameter[GainAutomation] = _fader;
1620 boost::shared_ptr<Processor> p = _route->nth_send (_current_send);
1621 if (p && p->name() != "Monitor 1") {
1622 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1623 boost::shared_ptr<Amp> a = s->amp();
1624 _vpot->set_control (a->gain_control());
1625 // connect to signal
1626 send_connections.drop_connections ();
1627 a->gain_control()->Changed.connect(send_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_processor_changed, this, false), ui_context());
1628 control_by_parameter[SendAutomation] = _vpot;
1630 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1631 control_by_parameter[SendAutomation] = 0;
1637 const uint32_t eq_hi_freq = 3; /* gtk2_ardour/mixbus_ports.h */
1638 hookup_eq (EQParam1, eq_hi_freq);
1642 const uint32_t eq_hi_gain = 4; /* gtk2_ardour/mixbus_ports.h */
1643 hookup_eq (EQParam2, eq_hi_gain);
1647 const uint32_t eq_mid_freq = 5; /* gtk2_ardour/mixbus_ports.h */
1648 hookup_eq (EQParam3, eq_mid_freq);
1652 const uint32_t eq_mid_gain = 6; /* gtk2_ardour/mixbus_ports.h */
1653 hookup_eq (EQParam4, eq_mid_gain);
1657 const uint32_t eq_lo_freq = 7; /* gtk2_ardour/mixbus_ports.h */
1658 hookup_eq (EQParam5, eq_lo_freq);
1662 const uint32_t eq_lo_gain = 8; /* gtk2_ardour/mixbus_ports.h */
1663 hookup_eq (EQParam6, eq_lo_gain);
1667 const uint32_t eq_hp_freq = 2; /* gtk2_ardour/mixbus_ports.h */
1668 hookup_eq (EQParam7, eq_hp_freq);
1672 const uint32_t eq_in = 1; /* gtk2_ardour/mixbus_ports.h */
1673 hookup_eq (EQParam8, eq_in);
1677 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("vpot mode %1 not known.\n", p));
1682 _surface->write (display (1, vpot_mode_string()));
1686 Strip::is_midi_track () const
1688 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1692 Strip::reset_saved_values ()
1694 _last_pan_azi_position_written = -1.0;
1695 _last_pan_width_position_written = -1.0;
1696 _last_gain_position_written = -1.0;
1697 _last_trim_position_written = -1.0;
1702 Strip::notify_metering_state_changed()
1704 if (!_route || !_meter) {
1708 bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
1709 bool metering_active = _surface->mcp().metering_active ();
1711 if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
1715 _meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
1717 if (!transport_is_rolling || !metering_active) {
1718 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
1719 notify_panner_azi_changed (true);
1722 _transport_is_rolling = transport_is_rolling;
1723 _metering_active = metering_active;
1727 Strip::hookup_eq (AutomationType param, uint32_t port_number)
1729 if (!_subview_route) {
1730 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1734 boost::shared_ptr<PluginInsert> eq = _subview_route->ch_eq();
1737 _vpot->set_control (boost::shared_ptr<AutomationControl>());
1740 boost::shared_ptr<AutomationControl> control = boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (eq->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_number)));
1743 control->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, param, port_number, false), ui_context());
1744 _vpot->set_control (control);
1745 control_by_parameter[param] = _vpot;