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 "midi++/port.h"
28 #include "pbd/compose.h"
29 #include "pbd/convert.h"
31 #include "ardour/amp.h"
32 #include "ardour/bundle.h"
33 #include "ardour/debug.h"
34 #include "ardour/midi_ui.h"
35 #include "ardour/meter.h"
36 #include "ardour/pannable.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/route.h"
41 #include "ardour/session.h"
42 #include "ardour/send.h"
43 #include "ardour/track.h"
44 #include "ardour/user_bundle.h"
46 #include "mackie_control_protocol.h"
47 #include "surface_port.h"
56 using namespace Mackie;
58 using namespace ARDOUR;
61 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
62 #define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
64 extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
65 #define invalidator() __invalidator (*(MackieControlProtocol::instance()), __FILE__, __LINE__)
67 Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
76 , _vpot_mode (PanAzimuth)
77 , _preflip_vpot_mode (PanAzimuth)
81 , _controls_locked (false)
82 , _reset_display_at (0)
83 , _last_gain_position_written (-1.0)
84 , _last_pan_position_written (-1.0)
86 _fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
87 _vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
88 _meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
90 for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
91 (void) Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this);
97 /* surface is responsible for deleting all controls */
101 Strip::add (Control & control)
105 Group::add (control);
107 /* fader, vpot, meter were all set explicitly */
109 if ((button = dynamic_cast<Button*>(&control)) != 0) {
110 switch (button->bid()) {
111 case Button::RecEnable:
123 case Button::VSelect:
126 case Button::FaderTouch:
127 _fader_touch = button;
135 Strip::set_route (boost::shared_ptr<Route> r)
137 if (_controls_locked) {
141 route_connections.drop_connections ();
143 _solo->set_control (boost::shared_ptr<AutomationControl>());
144 _mute->set_control (boost::shared_ptr<AutomationControl>());
145 _select->set_control (boost::shared_ptr<AutomationControl>());
146 _recenable->set_control (boost::shared_ptr<AutomationControl>());
147 _fader->set_control (boost::shared_ptr<AutomationControl>());
148 _vpot->set_control (boost::shared_ptr<AutomationControl>());
156 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
157 _surface->number(), _index, _route->name()));
159 _solo->set_control (_route->solo_control());
160 _mute->set_control (_route->mute_control());
161 set_vpot_mode (PanAzimuth);
163 _route->solo_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_solo_changed, this), ui_context());
164 _route->mute_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_mute_changed, this), ui_context());
166 boost::shared_ptr<Pannable> pannable = _route->pannable();
169 pannable->pan_azimuth_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
170 pannable->pan_width_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
172 _route->gain_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
173 _route->PropertyChanged.connect (route_connections, invalidator(), ui_bind (&Strip::notify_property_changed, this, _1), ui_context());
175 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
178 _recenable->set_control (trk->rec_enable_control());
179 trk->rec_enable_control()->Changed .connect(route_connections, invalidator(), ui_bind (&Strip::notify_record_enable_changed, this), ui_context());
182 // TODO this works when a currently-banked route is made inactive, but not
183 // when a route is activated which should be currently banked.
185 _route->active_changed.connect (route_connections, invalidator(), ui_bind (&Strip::notify_active_changed, this), ui_context());
186 _route->DropReferences.connect (route_connections, invalidator(), ui_bind (&Strip::notify_route_deleted, this), ui_context());
192 /* setup legal VPot modes for this route */
194 build_input_list (_route->input()->n_ports());
195 build_output_list (_route->output()->n_ports());
197 current_pot_modes.clear();
200 boost::shared_ptr<Panner> panner = pannable->panner();
202 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
203 set<Evoral::Parameter>::iterator a;
205 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
206 current_pot_modes.push_back (PanAzimuth);
209 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
210 current_pot_modes.push_back (PanWidth);
215 current_pot_modes.push_back (Input);
216 current_pot_modes.push_back (Output);
218 if (_route->nth_send (0) != 0) {
219 current_pot_modes.push_back (Send1);
221 if (_route->nth_send (1) != 0) {
222 current_pot_modes.push_back (Send2);
224 if (_route->nth_send (2) != 0) {
225 current_pot_modes.push_back (Send3);
227 if (_route->nth_send (3) != 0) {
228 current_pot_modes.push_back (Send4);
230 if (_route->nth_send (4) != 0) {
231 current_pot_modes.push_back (Send5);
233 if (_route->nth_send (5) != 0) {
234 current_pot_modes.push_back (Send6);
236 if (_route->nth_send (6) != 0) {
237 current_pot_modes.push_back (Send7);
239 if (_route->nth_send (7) != 0) {
240 current_pot_modes.push_back (Send8);
247 notify_solo_changed ();
248 notify_mute_changed ();
249 notify_gain_changed ();
250 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
251 notify_panner_changed ();
252 notify_record_enable_changed ();
256 Strip::notify_solo_changed ()
258 if (_route && _solo) {
259 _surface->write (_solo->set_state (_route->soloed() ? on : off));
264 Strip::notify_mute_changed ()
266 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
267 if (_route && _mute) {
268 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
269 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
271 _surface->write (_mute->set_state (_route->muted() ? on : off));
276 Strip::notify_record_enable_changed ()
278 if (_route && _recenable) {
279 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
284 Strip::notify_active_changed ()
286 _surface->mcp().refresh_current_bank();
290 Strip::notify_route_deleted ()
292 _surface->mcp().refresh_current_bank();
296 Strip::notify_gain_changed (bool force_update)
298 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("gain changed for strip %1, flip mode %2\n", _index, _surface->mcp().flip_mode()));
304 if (_surface->mcp().flip_mode()) {
310 if (!control->in_use()) {
312 float pos = _route->gain_control()->internal_to_interface (_route->gain_control()->get_value());
314 if (force_update || pos != _last_gain_position_written) {
316 if (_surface->mcp().flip_mode()) {
317 _surface->write (_vpot->set_all (pos, true, Pot::wrap));
318 do_parameter_display (GainAutomation, pos);
320 _surface->write (_fader->set_position (pos));
321 do_parameter_display (GainAutomation, pos);
324 queue_display_reset (2000);
325 _last_gain_position_written = pos;
328 DEBUG_TRACE (DEBUG::MackieControl, "value is stale, no message sent\n");
331 DEBUG_TRACE (DEBUG::MackieControl, "fader in use, no message sent\n");
334 DEBUG_TRACE (DEBUG::MackieControl, "no route or no fader\n");
339 Strip::notify_property_changed (const PropertyChange& what_changed)
341 if (!what_changed.contains (ARDOUR::Properties::name)) {
347 string fullname = _route->name();
349 if (fullname.length() <= 6) {
352 line1 = PBD::short_version (fullname, 6);
355 _surface->write (display (0, line1));
360 Strip::notify_panner_changed (bool force_update)
364 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
366 boost::shared_ptr<Pannable> pannable = _route->pannable();
369 _surface->write (_vpot->zero());
375 if (_surface->mcp().flip_mode()) {
381 if (!control->in_use()) {
383 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
385 if (force_update || pos != _last_pan_position_written) {
387 if (_surface->mcp().flip_mode()) {
389 _surface->write (_fader->set_position (pos));
390 do_parameter_display (PanAzimuthAutomation, pos);
392 _surface->write (_vpot->set_all (pos, true, Pot::dot));
393 do_parameter_display (PanAzimuthAutomation, pos);
396 queue_display_reset (2000);
397 _last_pan_position_written = pos;
404 Strip::select_event (Button& button, ButtonState bs)
406 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
410 int ms = _surface->mcp().modifier_state();
412 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
413 _controls_locked = !_controls_locked;
414 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
415 queue_display_reset (1000);
419 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
420 /* reset to default */
421 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
423 ac->set_value (ac->normal());
428 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
429 _surface->mcp().add_down_select_button (_surface->number(), _index);
430 _surface->mcp().select_range ();
433 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
434 _surface->mcp().remove_down_select_button (_surface->number(), _index);
439 Strip::vselect_event (Button& button, ButtonState bs)
443 boost::shared_ptr<AutomationControl> ac = button.control ();
447 int ms = _surface->mcp().modifier_state();
449 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
450 /* reset to default/normal value */
451 ac->set_value (ac->normal());
461 Strip::fader_touch_event (Button& button, ButtonState bs)
463 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
465 /* never use the modified control for fader stuff */
469 _fader->set_in_use (true);
470 _fader->start_touch (_surface->mcp().transport_frame());
471 boost::shared_ptr<AutomationControl> ac = _fader->control ();
473 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
474 queue_display_reset (2000);
479 _fader->set_in_use (false);
480 _fader->stop_touch (_surface->mcp().transport_frame(), true);
487 Strip::handle_button (Button& button, ButtonState bs)
489 boost::shared_ptr<AutomationControl> control;
492 button.set_in_use (true);
494 button.set_in_use (false);
497 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
499 switch (button.bid()) {
501 select_event (button, bs);
504 case Button::VSelect:
505 vselect_event (button, bs);
508 case Button::FaderTouch:
509 fader_touch_event (button, bs);
513 if ((control = button.control ())) {
515 DEBUG_TRACE (DEBUG::MackieControl, "add button on release\n");
516 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
519 int ms = _surface->mcp().modifier_state();
521 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
522 /* reset to default/normal value */
523 new_value = control->normal();
525 new_value = control->get_value() ? 0.0 : 1.0;
528 /* get all controls that either have their
529 * button down or are within a range of
530 * several down buttons
533 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
536 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
537 controls.size(), control->parameter().type(), new_value));
541 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
542 (*c)->set_value (new_value);
546 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
547 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
555 Strip::do_parameter_display (AutomationType type, float val)
561 dB = fast_coefficient_to_dB (val);
563 _surface->write (display (1, " -inf "));
567 snprintf (buf, sizeof (buf), "%6.1f", dB);
568 _surface->write (display (1, buf));
572 case PanAzimuthAutomation:
574 boost::shared_ptr<Pannable> p = _route->pannable();
575 if (p && p->panner()) {
576 string str = p->panner()->value_as_string (p->pan_azimuth_control);
577 _surface->write (display (1, str));
586 Strip::handle_fader (Fader& fader, float position)
588 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
590 fader.set_value (position);
591 fader.start_touch (_surface->mcp().transport_frame());
592 queue_display_reset (2000);
594 // must echo bytes back to slider now, because
595 // the notifier only works if the fader is not being
596 // touched. Which it is if we're getting input.
598 _surface->write (fader.set_position (position));
602 Strip::handle_pot (Pot& pot, float delta)
604 /* Pots only emit events when they move, not when they
605 stop moving. So to get a stop event, we need to use a timeout.
608 pot.start_touch (_surface->mcp().transport_frame());
610 double p = pot.get_value ();
618 Strip::periodic (uint64_t usecs)
624 update_automation ();
627 if (_reset_display_at && _reset_display_at < usecs) {
633 Strip::update_automation ()
635 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
637 if (gain_state == Touch || gain_state == Play) {
638 notify_gain_changed (false);
641 if (_route->panner()) {
642 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
643 if (panner_state == Touch || panner_state == Play) {
644 notify_panner_changed (false);
650 Strip::update_meter ()
653 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
654 _surface->write (_meter->update_message (dB));
661 MidiByteArray retval;
663 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
664 retval << (*it)->zero ();
667 retval << blank_display (0);
668 retval << blank_display (1);
674 Strip::blank_display (uint32_t line_number)
676 return display (line_number, string());
680 Strip::display (uint32_t line_number, const std::string& line)
682 assert (line_number <= 1);
684 MidiByteArray retval;
686 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
689 retval << _surface->sysex_hdr();
693 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
694 retval << (_index * 7 + (line_number * 0x38));
696 // ascii data to display
698 // pad with " " out to 6 chars
699 for (int i = line.length(); i < 6; ++i) {
703 // column spacer, unless it's the right-hand column
711 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieMidiBuilder::strip_display midi: %1\n", retval));
717 Strip::lock_controls ()
719 _controls_locked = true;
723 Strip::unlock_controls ()
725 _controls_locked = false;
729 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
731 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
732 if ((*i) == _route) {
733 return _select->set_state (on);
737 return _select->set_state (off);
741 Strip::vpot_mode_string () const
743 switch (_vpot_mode) {
782 Strip::flip_mode_changed (bool notify)
788 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
789 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
791 _fader->set_control (vpot_controllable);
792 _vpot->set_control (fader_controllable);
794 _surface->write (display (1, vpot_mode_string ()));
802 Strip::queue_display_reset (uint32_t msecs)
805 struct timeval delta;
807 gettimeofday (&now, 0);
809 delta.tv_sec = msecs/1000;
810 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
812 timeradd (&now, &delta, &when);
814 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
818 Strip::clear_display_reset ()
820 _reset_display_at = 0;
824 Strip::reset_display ()
826 _surface->write (display (1, vpot_mode_string()));
827 clear_display_reset ();
830 struct RouteCompareByName {
831 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
832 return a->name().compare (b->name()) < 0;
837 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
839 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
847 Strip::build_input_list (const ChanCount& channels)
849 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
851 input_bundles.clear ();
853 /* give user bundles first chance at being in the menu */
855 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
856 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
857 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
861 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
862 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
863 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
867 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
868 RouteList copy = *routes;
869 copy.sort (RouteCompareByName ());
871 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
872 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
878 Strip::build_output_list (const ChanCount& channels)
880 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
882 output_bundles.clear ();
884 /* give user bundles first chance at being in the menu */
886 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
887 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
888 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
892 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
893 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
894 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
898 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
899 RouteList copy = *routes;
900 copy.sort (RouteCompareByName ());
902 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
903 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
908 Strip::next_pot_mode ()
910 vector<PotMode>::iterator i;
912 if (_surface->mcp().flip_mode()) {
913 /* do not change vpot mode while in flipped mode */
914 _surface->write (display (1, "Flip"));
915 queue_display_reset (2000);
919 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
920 if ((*i) == _vpot_mode) {
925 /* move to the next mode in the list, or back to the start (which will
926 also happen if the current mode is not in the current pot mode list)
929 if (i != current_pot_modes.end()) {
933 if (i == current_pot_modes.end()) {
934 i = current_pot_modes.begin();
941 Strip::set_vpot_mode (PotMode m)
943 boost::shared_ptr<Send> send;
944 boost::shared_ptr<Pannable> pannable;
952 switch (_vpot_mode) {
956 pannable = _route->pannable ();
958 if (_surface->mcp().flip_mode()) {
959 /* gain to vpot, pan azi to fader */
960 _vpot->set_control (_route->gain_control());
962 _fader->set_control (pannable->pan_azimuth_control);
966 /* gain to fader, pan azi to vpot */
967 _fader->set_control (_route->gain_control());
969 _vpot->set_control (pannable->pan_azimuth_control);
971 _vpot_mode = PanAzimuth;
976 pannable = _route->pannable ();
978 if (_surface->mcp().flip_mode()) {
979 /* gain to vpot, pan width to fader */
980 _vpot->set_control (_route->gain_control());
982 _fader->set_control (pannable->pan_width_control);
986 /* gain to fader, pan width to vpot */
987 _fader->set_control (_route->gain_control());
989 _vpot->set_control (pannable->pan_width_control);
1005 send = boost::dynamic_pointer_cast<Send> (_route->nth_send (0));
1007 if (_surface->mcp().flip_mode()) {
1008 /* route gain to vpot, send gain to fader */
1009 _fader->set_control (send->amp()->gain_control());
1010 _vpot->set_control (_route->gain_control());
1013 /* route gain to fader, send gain to vpot */
1014 _vpot->set_control (send->amp()->gain_control());
1015 _fader->set_control (_route->gain_control());
1035 _surface->write (display (1, vpot_mode_string()));