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 Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
92 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
93 _surface->number(), index, Button::id_to_name (bb->bid()),
94 bb->id(), b->second.base_id));
100 /* surface is responsible for deleting all controls */
104 Strip::add (Control & control)
108 Group::add (control);
110 /* fader, vpot, meter were all set explicitly */
112 if ((button = dynamic_cast<Button*>(&control)) != 0) {
113 switch (button->bid()) {
114 case Button::RecEnable:
126 case Button::VSelect:
129 case Button::FaderTouch:
130 _fader_touch = button;
138 Strip::set_route (boost::shared_ptr<Route> r)
140 if (_controls_locked) {
144 route_connections.drop_connections ();
146 _solo->set_control (boost::shared_ptr<AutomationControl>());
147 _mute->set_control (boost::shared_ptr<AutomationControl>());
148 _select->set_control (boost::shared_ptr<AutomationControl>());
149 _recenable->set_control (boost::shared_ptr<AutomationControl>());
150 _fader->set_control (boost::shared_ptr<AutomationControl>());
151 _vpot->set_control (boost::shared_ptr<AutomationControl>());
159 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 strip %2 now mapping route %3\n",
160 _surface->number(), _index, _route->name()));
162 _solo->set_control (_route->solo_control());
163 _mute->set_control (_route->mute_control());
164 set_vpot_mode (PanAzimuth);
166 _route->solo_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_solo_changed, this), ui_context());
167 _route->mute_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_mute_changed, this), ui_context());
169 boost::shared_ptr<Pannable> pannable = _route->pannable();
172 pannable->pan_azimuth_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
173 pannable->pan_width_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
175 _route->gain_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
176 _route->PropertyChanged.connect (route_connections, invalidator(), ui_bind (&Strip::notify_property_changed, this, _1), ui_context());
178 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
181 _recenable->set_control (trk->rec_enable_control());
182 trk->rec_enable_control()->Changed .connect(route_connections, invalidator(), ui_bind (&Strip::notify_record_enable_changed, this), ui_context());
185 // TODO this works when a currently-banked route is made inactive, but not
186 // when a route is activated which should be currently banked.
188 _route->active_changed.connect (route_connections, invalidator(), ui_bind (&Strip::notify_active_changed, this), ui_context());
189 _route->DropReferences.connect (route_connections, invalidator(), ui_bind (&Strip::notify_route_deleted, this), ui_context());
195 /* setup legal VPot modes for this route */
197 build_input_list (_route->input()->n_ports());
198 build_output_list (_route->output()->n_ports());
200 current_pot_modes.clear();
203 boost::shared_ptr<Panner> panner = pannable->panner();
205 set<Evoral::Parameter> automatable = panner->what_can_be_automated ();
206 set<Evoral::Parameter>::iterator a;
208 if ((a = automatable.find (PanAzimuthAutomation)) != automatable.end()) {
209 current_pot_modes.push_back (PanAzimuth);
212 if ((a = automatable.find (PanWidthAutomation)) != automatable.end()) {
213 current_pot_modes.push_back (PanWidth);
218 current_pot_modes.push_back (Input);
219 current_pot_modes.push_back (Output);
221 if (_route->nth_send (0) != 0) {
222 current_pot_modes.push_back (Send1);
224 if (_route->nth_send (1) != 0) {
225 current_pot_modes.push_back (Send2);
227 if (_route->nth_send (2) != 0) {
228 current_pot_modes.push_back (Send3);
230 if (_route->nth_send (3) != 0) {
231 current_pot_modes.push_back (Send4);
233 if (_route->nth_send (4) != 0) {
234 current_pot_modes.push_back (Send5);
236 if (_route->nth_send (5) != 0) {
237 current_pot_modes.push_back (Send6);
239 if (_route->nth_send (6) != 0) {
240 current_pot_modes.push_back (Send7);
242 if (_route->nth_send (7) != 0) {
243 current_pot_modes.push_back (Send8);
250 notify_solo_changed ();
251 notify_mute_changed ();
252 notify_gain_changed ();
253 notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
254 notify_panner_changed ();
255 notify_record_enable_changed ();
259 Strip::notify_solo_changed ()
261 if (_route && _solo) {
262 _surface->write (_solo->set_state (_route->soloed() ? on : off));
267 Strip::notify_mute_changed ()
269 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Strip %1 mute changed\n", _index));
270 if (_route && _mute) {
271 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("\troute muted ? %1\n", _route->muted()));
272 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("mute message: %1\n", _mute->set_state (_route->muted() ? on : off)));
274 _surface->write (_mute->set_state (_route->muted() ? on : off));
279 Strip::notify_record_enable_changed ()
281 if (_route && _recenable) {
282 _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
287 Strip::notify_active_changed ()
289 _surface->mcp().refresh_current_bank();
293 Strip::notify_route_deleted ()
295 _surface->mcp().refresh_current_bank();
299 Strip::notify_gain_changed (bool force_update)
301 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("gain changed for strip %1, flip mode %2\n", _index, _surface->mcp().flip_mode()));
307 if (_surface->mcp().flip_mode()) {
313 if (!control->in_use()) {
315 boost::shared_ptr<AutomationControl> ac = _route->gain_control();
317 float gain_coefficient = ac->get_value();
318 float normalized_position = ac->internal_to_interface (gain_coefficient);
320 if (force_update || normalized_position != _last_gain_position_written) {
323 if (_surface->mcp().flip_mode()) {
324 _surface->write (_vpot->set_all (normalized_position, true, Pot::wrap));
325 do_parameter_display (GainAutomation, gain_coefficient);
327 _surface->write (_fader->set_position (normalized_position));
328 do_parameter_display (GainAutomation, gain_coefficient);
331 queue_display_reset (2000);
332 _last_gain_position_written = normalized_position;
335 DEBUG_TRACE (DEBUG::MackieControl, "value is stale, no message sent\n");
338 DEBUG_TRACE (DEBUG::MackieControl, "fader in use, no message sent\n");
341 DEBUG_TRACE (DEBUG::MackieControl, "no route or no fader\n");
346 Strip::notify_property_changed (const PropertyChange& what_changed)
348 if (!what_changed.contains (ARDOUR::Properties::name)) {
354 string fullname = _route->name();
356 if (fullname.length() <= 6) {
359 line1 = PBD::short_version (fullname, 6);
362 _surface->write (display (0, line1));
367 Strip::notify_panner_changed (bool force_update)
371 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("pan change for strip %1\n", _index));
373 boost::shared_ptr<Pannable> pannable = _route->pannable();
376 _surface->write (_vpot->zero());
382 if (_surface->mcp().flip_mode()) {
388 if (!control->in_use()) {
390 double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value());
392 if (force_update || pos != _last_pan_position_written) {
394 if (_surface->mcp().flip_mode()) {
396 _surface->write (_fader->set_position (pos));
397 do_parameter_display (PanAzimuthAutomation, pos);
399 _surface->write (_vpot->set_all (pos, true, Pot::dot));
400 do_parameter_display (PanAzimuthAutomation, pos);
403 queue_display_reset (2000);
404 _last_pan_position_written = pos;
411 Strip::select_event (Button& button, ButtonState bs)
413 DEBUG_TRACE (DEBUG::MackieControl, "select button\n");
417 int ms = _surface->mcp().modifier_state();
419 if (ms & MackieControlProtocol::MODIFIER_CMDALT) {
420 _controls_locked = !_controls_locked;
421 _surface->write (display (1,_controls_locked ? "Locked" : "Unlock"));
422 queue_display_reset (1000);
426 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
427 /* reset to default */
428 boost::shared_ptr<AutomationControl> ac = _vpot->control ();
430 ac->set_value (ac->normal());
435 DEBUG_TRACE (DEBUG::MackieControl, "add select button on press\n");
436 _surface->mcp().add_down_select_button (_surface->number(), _index);
437 _surface->mcp().select_range ();
440 DEBUG_TRACE (DEBUG::MackieControl, "remove select button on release\n");
441 _surface->mcp().remove_down_select_button (_surface->number(), _index);
446 Strip::vselect_event (Button& button, ButtonState bs)
451 int ms = _surface->mcp().modifier_state();
453 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
454 boost::shared_ptr<AutomationControl> ac = button.control ();
458 /* reset to default/normal value */
459 ac->set_value (ac->normal());
463 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
471 Strip::fader_touch_event (Button& button, ButtonState bs)
473 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
475 /* never use the modified control for fader stuff */
479 _fader->set_in_use (true);
480 _fader->start_touch (_surface->mcp().transport_frame());
481 boost::shared_ptr<AutomationControl> ac = _fader->control ();
483 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
484 queue_display_reset (2000);
489 _fader->set_in_use (false);
490 _fader->stop_touch (_surface->mcp().transport_frame(), true);
497 Strip::handle_button (Button& button, ButtonState bs)
499 boost::shared_ptr<AutomationControl> control;
502 button.set_in_use (true);
504 button.set_in_use (false);
507 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
509 switch (button.bid()) {
511 select_event (button, bs);
514 case Button::VSelect:
515 vselect_event (button, bs);
518 case Button::FaderTouch:
519 fader_touch_event (button, bs);
523 if ((control = button.control ())) {
525 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
526 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
529 int ms = _surface->mcp().modifier_state();
531 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
532 /* reset to default/normal value */
533 new_value = control->normal();
535 new_value = control->get_value() ? 0.0 : 1.0;
538 /* get all controls that either have their
539 * button down or are within a range of
540 * several down buttons
543 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
546 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
547 controls.size(), control->parameter().type(), new_value));
551 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
552 (*c)->set_value (new_value);
556 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
557 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
565 Strip::do_parameter_display (AutomationType type, float val)
570 _surface->write (display (1, " -inf "));
573 float dB = accurate_coefficient_to_dB (val);
574 snprintf (buf, sizeof (buf), "%6.1f", dB);
575 _surface->write (display (1, buf));
579 case PanAzimuthAutomation:
581 boost::shared_ptr<Pannable> p = _route->pannable();
582 if (p && p->panner()) {
583 string str = p->panner()->value_as_string (p->pan_azimuth_control);
584 _surface->write (display (1, str));
593 Strip::handle_fader (Fader& fader, float position)
595 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
597 fader.set_value (position);
598 fader.start_touch (_surface->mcp().transport_frame());
599 queue_display_reset (2000);
601 // must echo bytes back to slider now, because
602 // the notifier only works if the fader is not being
603 // touched. Which it is if we're getting input.
605 _surface->write (fader.set_position (position));
609 Strip::handle_pot (Pot& pot, float delta)
611 /* Pots only emit events when they move, not when they
612 stop moving. So to get a stop event, we need to use a timeout.
615 boost::shared_ptr<AutomationControl> ac = pot.control();
616 double p = pot.get_value ();
618 p = max (ac->lower(), p);
619 p = min (ac->upper(), p);
624 Strip::periodic (uint64_t usecs)
630 update_automation ();
633 if (_reset_display_at && _reset_display_at < usecs) {
639 Strip::update_automation ()
641 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
643 if (gain_state == Touch || gain_state == Play) {
644 notify_gain_changed (false);
647 if (_route->panner()) {
648 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
649 if (panner_state == Touch || panner_state == Play) {
650 notify_panner_changed (false);
656 Strip::update_meter ()
659 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
660 _surface->write (_meter->update_message (dB));
667 MidiByteArray retval;
669 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
670 retval << (*it)->zero ();
673 retval << blank_display (0);
674 retval << blank_display (1);
680 Strip::blank_display (uint32_t line_number)
682 return display (line_number, string());
686 Strip::display (uint32_t line_number, const std::string& line)
688 assert (line_number <= 1);
690 MidiByteArray retval;
692 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
695 retval << _surface->sysex_hdr();
699 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
700 retval << (_index * 7 + (line_number * 0x38));
702 // ascii data to display
704 // pad with " " out to 6 chars
705 for (int i = line.length(); i < 6; ++i) {
709 // column spacer, unless it's the right-hand column
717 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieMidiBuilder::strip_display midi: %1\n", retval));
723 Strip::lock_controls ()
725 _controls_locked = true;
729 Strip::unlock_controls ()
731 _controls_locked = false;
735 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
737 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
738 if ((*i) == _route) {
739 return _select->set_state (on);
743 return _select->set_state (off);
747 Strip::vpot_mode_string () const
749 switch (_vpot_mode) {
788 Strip::flip_mode_changed (bool notify)
794 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
795 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
797 _fader->set_control (vpot_controllable);
798 _vpot->set_control (fader_controllable);
800 _surface->write (display (1, vpot_mode_string ()));
808 Strip::queue_display_reset (uint32_t msecs)
811 struct timeval delta;
813 gettimeofday (&now, 0);
815 delta.tv_sec = msecs/1000;
816 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
818 timeradd (&now, &delta, &when);
820 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
824 Strip::clear_display_reset ()
826 _reset_display_at = 0;
830 Strip::reset_display ()
832 _surface->write (display (1, vpot_mode_string()));
833 clear_display_reset ();
836 struct RouteCompareByName {
837 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
838 return a->name().compare (b->name()) < 0;
843 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
845 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
853 Strip::build_input_list (const ChanCount& channels)
855 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
857 input_bundles.clear ();
859 /* give user bundles first chance at being in the menu */
861 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
862 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
863 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
867 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
868 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
869 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
873 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
874 RouteList copy = *routes;
875 copy.sort (RouteCompareByName ());
877 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
878 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
884 Strip::build_output_list (const ChanCount& channels)
886 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
888 output_bundles.clear ();
890 /* give user bundles first chance at being in the menu */
892 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
893 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
894 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
898 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
899 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
900 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
904 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
905 RouteList copy = *routes;
906 copy.sort (RouteCompareByName ());
908 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
909 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
914 Strip::next_pot_mode ()
916 vector<PotMode>::iterator i;
918 if (_surface->mcp().flip_mode()) {
919 /* do not change vpot mode while in flipped mode */
920 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
921 _surface->write (display (1, "Flip"));
922 queue_display_reset (2000);
926 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
927 if ((*i) == _vpot_mode) {
932 /* move to the next mode in the list, or back to the start (which will
933 also happen if the current mode is not in the current pot mode list)
936 if (i != current_pot_modes.end()) {
940 if (i == current_pot_modes.end()) {
941 i = current_pot_modes.begin();
948 Strip::set_vpot_mode (PotMode m)
950 boost::shared_ptr<Send> send;
951 boost::shared_ptr<Pannable> pannable;
953 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", m));
961 switch (_vpot_mode) {
965 pannable = _route->pannable ();
967 if (_surface->mcp().flip_mode()) {
968 /* gain to vpot, pan azi to fader */
969 _vpot->set_control (_route->gain_control());
971 _fader->set_control (pannable->pan_azimuth_control);
975 /* gain to fader, pan azi to vpot */
976 _fader->set_control (_route->gain_control());
978 _vpot->set_control (pannable->pan_azimuth_control);
984 pannable = _route->pannable ();
986 if (_surface->mcp().flip_mode()) {
987 /* gain to vpot, pan width to fader */
988 _vpot->set_control (_route->gain_control());
990 _fader->set_control (pannable->pan_width_control);
994 /* gain to fader, pan width to vpot */
995 _fader->set_control (_route->gain_control());
997 _vpot->set_control (pannable->pan_width_control);
1013 send = boost::dynamic_pointer_cast<Send> (_route->nth_send (0));
1015 if (_surface->mcp().flip_mode()) {
1016 /* route gain to vpot, send gain to fader */
1017 _fader->set_control (send->amp()->gain_control());
1018 _vpot->set_control (_route->gain_control());
1021 /* route gain to fader, send gain to vpot */
1022 _vpot->set_control (send->amp()->gain_control());
1023 _fader->set_control (_route->gain_control());
1043 _surface->write (display (1, vpot_mode_string()));