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)
444 int ms = _surface->mcp().modifier_state();
446 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
447 boost::shared_ptr<AutomationControl> ac = button.control ();
451 /* reset to default/normal value */
452 ac->set_value (ac->normal());
456 DEBUG_TRACE (DEBUG::MackieControl, "switching to next pot mode\n");
464 Strip::fader_touch_event (Button& button, ButtonState bs)
466 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));
468 /* never use the modified control for fader stuff */
472 _fader->set_in_use (true);
473 _fader->start_touch (_surface->mcp().transport_frame());
474 boost::shared_ptr<AutomationControl> ac = _fader->control ();
476 do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value()));
477 queue_display_reset (2000);
482 _fader->set_in_use (false);
483 _fader->stop_touch (_surface->mcp().transport_frame(), true);
490 Strip::handle_button (Button& button, ButtonState bs)
492 boost::shared_ptr<AutomationControl> control;
495 button.set_in_use (true);
497 button.set_in_use (false);
500 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
502 switch (button.bid()) {
504 select_event (button, bs);
507 case Button::VSelect:
508 vselect_event (button, bs);
511 case Button::FaderTouch:
512 fader_touch_event (button, bs);
516 if ((control = button.control ())) {
518 DEBUG_TRACE (DEBUG::MackieControl, "add button on press\n");
519 _surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
522 int ms = _surface->mcp().modifier_state();
524 if (ms & MackieControlProtocol::MODIFIER_SHIFT) {
525 /* reset to default/normal value */
526 new_value = control->normal();
528 new_value = control->get_value() ? 0.0 : 1.0;
531 /* get all controls that either have their
532 * button down or are within a range of
533 * several down buttons
536 MackieControlProtocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type());
539 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
540 controls.size(), control->parameter().type(), new_value));
544 for (MackieControlProtocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
545 (*c)->set_value (new_value);
549 DEBUG_TRACE (DEBUG::MackieControl, "remove button on release\n");
550 _surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
558 Strip::do_parameter_display (AutomationType type, float val)
564 dB = fast_coefficient_to_dB (val);
566 _surface->write (display (1, " -inf "));
570 snprintf (buf, sizeof (buf), "%6.1f", dB);
571 _surface->write (display (1, buf));
575 case PanAzimuthAutomation:
577 boost::shared_ptr<Pannable> p = _route->pannable();
578 if (p && p->panner()) {
579 string str = p->panner()->value_as_string (p->pan_azimuth_control);
580 _surface->write (display (1, str));
589 Strip::handle_fader (Fader& fader, float position)
591 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
593 fader.set_value (position);
594 fader.start_touch (_surface->mcp().transport_frame());
595 queue_display_reset (2000);
597 // must echo bytes back to slider now, because
598 // the notifier only works if the fader is not being
599 // touched. Which it is if we're getting input.
601 _surface->write (fader.set_position (position));
605 Strip::handle_pot (Pot& pot, float delta)
607 /* Pots only emit events when they move, not when they
608 stop moving. So to get a stop event, we need to use a timeout.
611 pot.start_touch (_surface->mcp().transport_frame());
613 double p = pot.get_value ();
621 Strip::periodic (uint64_t usecs)
627 update_automation ();
630 if (_reset_display_at && _reset_display_at < usecs) {
636 Strip::update_automation ()
638 ARDOUR::AutoState gain_state = _route->gain_control()->automation_state();
640 if (gain_state == Touch || gain_state == Play) {
641 notify_gain_changed (false);
644 if (_route->panner()) {
645 ARDOUR::AutoState panner_state = _route->panner()->automation_state();
646 if (panner_state == Touch || panner_state == Play) {
647 notify_panner_changed (false);
653 Strip::update_meter ()
656 float dB = const_cast<PeakMeter&> (_route->peak_meter()).peak_power (0);
657 _surface->write (_meter->update_message (dB));
664 MidiByteArray retval;
666 for (Group::Controls::const_iterator it = _controls.begin(); it != _controls.end(); ++it) {
667 retval << (*it)->zero ();
670 retval << blank_display (0);
671 retval << blank_display (1);
677 Strip::blank_display (uint32_t line_number)
679 return display (line_number, string());
683 Strip::display (uint32_t line_number, const std::string& line)
685 assert (line_number <= 1);
687 MidiByteArray retval;
689 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip_display index: %1, line %2 = %3\n", _index, line_number, line));
692 retval << _surface->sysex_hdr();
696 // offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
697 retval << (_index * 7 + (line_number * 0x38));
699 // ascii data to display
701 // pad with " " out to 6 chars
702 for (int i = line.length(); i < 6; ++i) {
706 // column spacer, unless it's the right-hand column
714 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieMidiBuilder::strip_display midi: %1\n", retval));
720 Strip::lock_controls ()
722 _controls_locked = true;
726 Strip::unlock_controls ()
728 _controls_locked = false;
732 Strip::gui_selection_changed (ARDOUR::RouteNotificationListPtr rl)
734 for (ARDOUR::RouteNotificationList::iterator i = rl->begin(); i != rl->end(); ++i) {
735 if ((*i) == _route) {
736 return _select->set_state (on);
740 return _select->set_state (off);
744 Strip::vpot_mode_string () const
746 switch (_vpot_mode) {
785 Strip::flip_mode_changed (bool notify)
791 boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
792 boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
794 _fader->set_control (vpot_controllable);
795 _vpot->set_control (fader_controllable);
797 _surface->write (display (1, vpot_mode_string ()));
805 Strip::queue_display_reset (uint32_t msecs)
808 struct timeval delta;
810 gettimeofday (&now, 0);
812 delta.tv_sec = msecs/1000;
813 delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
815 timeradd (&now, &delta, &when);
817 _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
821 Strip::clear_display_reset ()
823 _reset_display_at = 0;
827 Strip::reset_display ()
829 _surface->write (display (1, vpot_mode_string()));
830 clear_display_reset ();
833 struct RouteCompareByName {
834 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
835 return a->name().compare (b->name()) < 0;
840 Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
842 if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
850 Strip::build_input_list (const ChanCount& channels)
852 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
854 input_bundles.clear ();
856 /* give user bundles first chance at being in the menu */
858 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
859 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
860 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
864 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
865 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
866 maybe_add_to_bundle_map (input_bundles, *i, true, channels);
870 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
871 RouteList copy = *routes;
872 copy.sort (RouteCompareByName ());
874 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
875 maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
881 Strip::build_output_list (const ChanCount& channels)
883 boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
885 output_bundles.clear ();
887 /* give user bundles first chance at being in the menu */
889 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
890 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
891 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
895 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
896 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
897 maybe_add_to_bundle_map (output_bundles, *i, false, channels);
901 boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
902 RouteList copy = *routes;
903 copy.sort (RouteCompareByName ());
905 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
906 maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
911 Strip::next_pot_mode ()
913 vector<PotMode>::iterator i;
915 if (_surface->mcp().flip_mode()) {
916 /* do not change vpot mode while in flipped mode */
917 DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
918 _surface->write (display (1, "Flip"));
919 queue_display_reset (2000);
923 for (i = current_pot_modes.begin(); i != current_pot_modes.end(); ++i) {
924 if ((*i) == _vpot_mode) {
929 /* move to the next mode in the list, or back to the start (which will
930 also happen if the current mode is not in the current pot mode list)
933 if (i != current_pot_modes.end()) {
937 if (i == current_pot_modes.end()) {
938 i = current_pot_modes.begin();
945 Strip::set_vpot_mode (PotMode m)
947 boost::shared_ptr<Send> send;
948 boost::shared_ptr<Pannable> pannable;
950 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", m));
958 switch (_vpot_mode) {
962 pannable = _route->pannable ();
964 if (_surface->mcp().flip_mode()) {
965 /* gain to vpot, pan azi to fader */
966 _vpot->set_control (_route->gain_control());
968 _fader->set_control (pannable->pan_azimuth_control);
972 /* gain to fader, pan azi to vpot */
973 _fader->set_control (_route->gain_control());
975 _vpot->set_control (pannable->pan_azimuth_control);
981 pannable = _route->pannable ();
983 if (_surface->mcp().flip_mode()) {
984 /* gain to vpot, pan width to fader */
985 _vpot->set_control (_route->gain_control());
987 _fader->set_control (pannable->pan_width_control);
991 /* gain to fader, pan width to vpot */
992 _fader->set_control (_route->gain_control());
994 _vpot->set_control (pannable->pan_width_control);
1010 send = boost::dynamic_pointer_cast<Send> (_route->nth_send (0));
1012 if (_surface->mcp().flip_mode()) {
1013 /* route gain to vpot, send gain to fader */
1014 _fader->set_control (send->amp()->gain_control());
1015 _vpot->set_control (_route->gain_control());
1018 /* route gain to fader, send gain to vpot */
1019 _vpot->set_control (send->amp()->gain_control());
1020 _fader->set_control (_route->gain_control());
1040 _surface->write (display (1, vpot_mode_string()));