2 Copyright (C) 2012 Paul Davis
3 Copyright (C) 2017 Ben Loftis
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.
27 #include <glibmm/convert.h>
29 #include "pbd/stacktrace.h"
31 #include "midi++/port.h"
33 #include "ardour/audioengine.h"
34 #include "ardour/automation_control.h"
35 #include "ardour/debug.h"
36 #include "ardour/route.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/profile.h"
40 #include "ardour/rc_configuration.h"
41 #include "ardour/session.h"
42 #include "ardour/utils.h"
44 #include <gtkmm2ext/gui_thread.h>
46 #include "control_group.h"
47 #include "surface_port.h"
50 #include "us2400_control_protocol.h"
51 #include "jog_wheel.h"
63 #ifdef PLATFORM_WINDOWS
64 #define random() rand()
69 using ARDOUR::Stripable;
71 using ARDOUR::Profile;
72 using ARDOUR::AutomationControl;
73 using namespace ArdourSurface;
74 using namespace US2400;
76 #define ui_context() US2400Protocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
78 // The MCU sysex header.4th byte Will be overwritten
79 // when we get an incoming sysex that identifies
81 static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x14);
83 // The MCU extender sysex header.4th byte Will be overwritten
84 // when we get an incoming sysex that identifies
86 static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15);
88 static MidiByteArray empty_midi_byte_array;
90 Surface::Surface (US2400Protocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
99 , _last_master_gain_written (-0.0f)
100 , _joystick_active (false)
101 , connection_state (0)
104 DEBUG_TRACE (DEBUG::US2400, "Surface::Surface init\n");
107 _port = new SurfacePort (*this);
109 throw failed_constructor ();
112 /* only the first Surface object has global controls */
113 /* lets use master_position instead */
114 uint32_t mp = _mcp.device_info().master_position();
116 DEBUG_TRACE (DEBUG::US2400, "Surface matches MasterPosition. Might have global controls.\n");
117 if (_mcp.device_info().has_global_controls()) {
119 DEBUG_TRACE (DEBUG::US2400, "init_controls done\n");
122 if (_mcp.device_info().has_master_fader()) {
124 DEBUG_TRACE (DEBUG::US2400, "setup_master done\n");
128 uint32_t n = _mcp.device_info().strip_cnt();
132 DEBUG_TRACE (DEBUG::US2400, "init_strips done\n");
135 connect_to_signals ();
137 DEBUG_TRACE (DEBUG::US2400, "Surface::Surface done\n");
142 DEBUG_TRACE (DEBUG::US2400, "Surface::~Surface init\n");
145 g_source_destroy (input_source);
149 // delete groups (strips)
150 for (Groups::iterator it = groups.begin(); it != groups.end(); ++it) {
154 // delete controls (global buttons, master fader etc)
155 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
161 // the ports take time to release and we may be rebuilding right away
162 // in the case of changing devices.
164 DEBUG_TRACE (DEBUG::US2400, "Surface::~Surface done\n");
168 Surface::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
174 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->input_name());
175 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->output_name());
177 if (ni == name1 || ni == name2) {
179 connection_state |= InputConnected;
181 connection_state &= ~InputConnected;
183 } else if (no == name1 || no == name2) {
185 connection_state |= OutputConnected;
187 connection_state &= ~OutputConnected;
194 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
196 /* this will send a device query message, which should
197 result in a response that will kick off device type
198 discovery and activation of the surface(s).
200 The intended order of events is:
202 - each surface sends a device query message
203 - devices respond with either MCP or LCP response (sysex in both
205 - sysex message causes Surface::turn_it_on() which tells the
206 MCP object that the surface is ready, and sets up strip
207 displays and binds faders and buttons for that surface
209 In the case of LCP, where this is a handshake process that could
210 fail, the response process to the initial sysex after a device query
211 will mark the surface inactive, which won't shut anything down
212 but will stop any writes to the device.
214 Note: there are no known cases of the handshake process failing.
216 We actually can't initiate this in this callback, so we have
217 to queue it with the MCP event loop.
220 /* XXX this is a horrible hack. Without a short sleep here,
221 something prevents the device wakeup messages from being
222 sent and/or the responses from being received.
229 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
233 return true; /* connection status changed */
239 XMLNode* node = new XMLNode (X_("Surface"));
240 node->set_property (X_("name"), _name);
241 node->add_child_nocopy (_port->get_state());
246 Surface::set_state (const XMLNode& node, int version)
248 /* Look for a node named after the device we're part of */
250 XMLNodeList const& children = node.children();
253 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
255 if ((*c)->get_property (X_("name"), name) && name == _name) {
265 XMLNode* portnode = mynode->child (X_("Port"));
267 if (_port->set_state (*portnode, version)) {
276 Surface::sysex_hdr() const
279 case st_mcu: return mackie_sysex_hdr;
280 case st_ext: return mackie_sysex_hdr_xt;
281 default: return mackie_sysex_hdr_xt;
283 cout << "SurfacePort::sysex_hdr _port_type not known" << endl;
284 return mackie_sysex_hdr;
287 static GlobalControlDefinition mackie_global_controls[] = {
288 { "external", Pot::External, Pot::factory, "none" },
289 { "fader_touch", Led::FaderTouch, Led::factory, "master" },
290 { "timecode", Led::Timecode, Led::factory, "none" },
291 { "beats", Led::Beats, Led::factory, "none" },
292 { "solo", Led::RudeSolo, Led::factory, "none" },
293 { "relay_click", Led::RelayClick, Led::factory, "none" },
294 { "", 0, Led::factory, "" }
298 Surface::init_controls()
302 DEBUG_TRACE (DEBUG::US2400, "Surface::init_controls: creating groups\n");
303 groups["assignment"] = new Group ("assignment");
304 groups["automation"] = new Group ("automation");
305 groups["bank"] = new Group ("bank");
306 groups["cursor"] = new Group ("cursor");
307 groups["display"] = new Group ("display");
308 groups["function select"] = new Group ("function select");
309 groups["global view"] = new Group ("global view");
310 groups["master"] = new Group ("master");
311 groups["modifiers"] = new Group ("modifiers");
312 groups["none"] = new Group ("none");
313 groups["transport"] = new Group ("transport");
314 groups["user"] = new Group ("user");
315 groups["utilities"] = new Group ("utilities");
317 DEBUG_TRACE (DEBUG::US2400, "Surface::init_controls: creating jog wheel\n");
318 if (_mcp.device_info().has_jog_wheel()) {
319 _jog_wheel = new US2400::JogWheel (_mcp);
322 DEBUG_TRACE (DEBUG::US2400, "Surface::init_controls: creating global controls\n");
323 for (uint32_t n = 0; mackie_global_controls[n].name[0]; ++n) {
324 group = groups[mackie_global_controls[n].group_name];
325 Control* control = mackie_global_controls[n].factory (*this, mackie_global_controls[n].id, mackie_global_controls[n].name, *group);
326 controls_by_device_independent_id[mackie_global_controls[n].id] = control;
329 /* add global buttons */
330 DEBUG_TRACE (DEBUG::US2400, "Surface::init_controls: adding global buttons\n");
331 const map<Button::ID,GlobalButtonInfo>& global_buttons (_mcp.device_info().global_buttons());
333 for (map<Button::ID,GlobalButtonInfo>::const_iterator b = global_buttons.begin(); b != global_buttons.end(); ++b){
334 group = groups[b->second.group];
335 controls_by_device_independent_id[b->first] = Button::factory (*this, b->first, b->second.id, b->second.label, *group);
340 Surface::init_strips (uint32_t n)
342 const map<Button::ID,StripButtonInfo>& strip_buttons (_mcp.device_info().strip_buttons());
344 //surface 4 has no strips
345 if ((_stype != st_mcu) && (_stype != st_ext))
348 for (uint32_t i = 0; i < n; ++i) {
352 snprintf (name, sizeof (name), "strip_%d", (8* _number) + i);
354 Strip* strip = new Strip (*this, name, i, strip_buttons);
356 strip->set_global_index (_number*n + i);
358 groups[name] = strip;
359 strips.push_back (strip);
364 Surface::master_monitor_may_have_changed ()
366 if (_number == _mcp.device_info().master_position()) {
372 Surface::setup_master ()
374 boost::shared_ptr<Stripable> m;
376 if ((m = _mcp.get_session().monitor_out()) == 0) {
377 m = _mcp.get_session().master_out();
382 _master_fader->reset_control ();
384 master_connection.disconnect ();
388 if (!_master_fader) {
389 Groups::iterator group_it;
391 group_it = groups.find("master");
393 if (group_it == groups.end()) {
394 groups["master"] = master_group = new Group ("master");
396 master_group = group_it->second;
399 _master_fader = dynamic_cast<Fader*> (Fader::factory (*this, _mcp.device_info().strip_cnt(), "master", *master_group));
401 DeviceInfo device_info = _mcp.device_info();
402 GlobalButtonInfo master_button = device_info.get_global_button(Button::MasterFaderTouch);
403 Button* bb = dynamic_cast<Button*> (Button::factory (
405 Button::MasterFaderTouch,
411 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface %1 Master Fader new button BID %2 id %3\n",
412 number(), Button::MasterFaderTouch, bb->id()));
414 master_connection.disconnect ();
417 _master_fader->set_control (m->gain_control());
418 m->gain_control()->Changed.connect (master_connection, MISSING_INVALIDATOR, boost::bind (&Surface::master_gain_changed, this), ui_context());
419 _last_master_gain_written = FLT_MAX; /* some essentially impossible value */
420 _port->write (_master_fader->set_position (0.0));
421 master_gain_changed ();
425 Surface::master_gain_changed ()
427 if (!_master_fader) {
431 boost::shared_ptr<AutomationControl> ac = _master_fader->control();
436 float normalized_position = ac->internal_to_interface (ac->get_value());
437 if (normalized_position == _last_master_gain_written) {
441 DEBUG_TRACE (DEBUG::US2400, "Surface::master_gain_changed: updating surface master fader\n");
443 _port->write (_master_fader->set_position (normalized_position));
444 _last_master_gain_written = normalized_position;
448 Surface::scaled_delta (float delta, float current_speed)
450 /* XXX needs work before use */
451 const float sign = delta < 0.0 ? -1.0 : 1.0;
453 return ((sign * std::pow (delta + 1.0, 2.0)) + current_speed) / 100.0;
457 Surface::blank_jog_ring ()
462 Surface::scrub_scaling_factor () const
468 Surface::connect_to_signals ()
473 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 connecting to signals on port %2\n",
474 number(), _port->input_port().name()));
476 MIDI::Parser* p = _port->input_port().parser();
479 p->sysex.connect_same_thread (*this, boost::bind (&Surface::handle_midi_sysex, this, _1, _2, _3));
480 /* V-Pot messages are Controller */
481 p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2));
482 /* Button messages are NoteOn */
483 p->note_on.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
484 /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
485 p->note_off.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
486 /* Fader messages are Pitchbend */
488 for (i = 0; i < _mcp.device_info().strip_cnt(); i++) {
489 p->channel_pitchbend[i].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, i));
492 p->channel_pitchbend[_mcp.device_info().strip_cnt()].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, _mcp.device_info().strip_cnt()));
499 Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
501 /* Pitchbend messages are fader position messages. Nothing in the data we get
502 * from the MIDI::Parser conveys the fader ID, which was given by the
503 * channel ID in the status byte.
505 * Instead, we have used bind() to supply the fader-within-strip ID
506 * when we connected to the per-channel pitchbend events.
509 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface::handle_midi_pitchbend_message on port %3, fader = %1 value = %2 (%4)\n",
510 fader_id, pb, _number, pb/16384.0));
514 Fader* fader = faders[fader_id];
517 Strip* strip = dynamic_cast<Strip*> (&fader->group());
518 float pos = pb / 16384.0;
520 strip->handle_fader (*fader, pos);
522 DEBUG_TRACE (DEBUG::US2400, "Handling master fader\n");
524 fader->set_value (pos); // alter master gain
525 _port->write (fader->set_position (pos)); // write back value (required for servo)
528 DEBUG_TRACE (DEBUG::US2400, "fader not found\n");
533 Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
535 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface::handle_midi_note_on_message %1 = %2\n", (int) ev->note_number, (int) ev->velocity));
539 /* fader touch sense is given by "buttons" 0xe..0xe7 and 0xe8 for the
543 if (ev->note_number >= 0xE0 && ev->note_number <= 0xE8) {
544 Fader* fader = faders[ev->note_number];
546 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface: fader touch message, fader = %1\n", fader));
550 Strip* strip = dynamic_cast<Strip*> (&fader->group());
552 if (ev->velocity > 64) {
553 strip->handle_fader_touch (*fader, true);
555 strip->handle_fader_touch (*fader, false);
561 Button* button = buttons[ev->note_number];
565 if (ev->velocity > 64) {
569 Strip* strip = dynamic_cast<Strip*> (&button->group());
571 if (mcp().main_modifier_state() == US2400Protocol::MODIFIER_OPTION) {
573 /* special case: CLR Solo looks like a strip's solo button, but with MODIFIER_OPTION it becomes global CLR SOLO */
574 DEBUG_TRACE (DEBUG::US2400, string_compose ("HERE option global button %1\n", button->id()));
575 _mcp.handle_button_event (*this, *button, ev->velocity > 64 ? press : release);
578 DEBUG_TRACE (DEBUG::US2400, string_compose ("strip %1 button %2 pressed ? %3\n",
579 strip->index(), button->name(), (ev->velocity > 64)));
580 strip->handle_button (*button, ev->velocity > 64 ? press : release);
583 DEBUG_TRACE (DEBUG::US2400, string_compose ("global button %1\n", button->id()));
584 _mcp.handle_button_event (*this, *button, ev->velocity > 64 ? press : release);
587 if (ev->velocity <= 64) {
592 DEBUG_TRACE (DEBUG::US2400, string_compose ("no button found for %1\n", (int) ev->note_number));
595 /* button release should reset timer AFTER handler(s) have run */
599 Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
601 DEBUG_TRACE (DEBUG::US2400, string_compose ("SurfacePort::handle_midi_controller %1 = %2\n", (int) ev->controller_number, (int) ev->value));
605 /* The joystick is not touch sensitive.
606 * ignore the joystick until the user clicks the "null" button.
607 * The joystick sends spurious controller messages,
608 * and since they are absolute values (joy position) this can send undesired changes.
610 if (_stype == st_joy && ev->controller_number == 0x01) {
611 _joystick_active = true;
613 /* Unfortunately the device does not appear to respond to the NULL button's LED,
614 * to indicate that the joystick is active.
616 #if 0 // this approach doesn't seem to work
617 MidiByteArray joy_active (3, 0xB0, 0x01, 0x01);
618 _port->write (joy_active);
622 #ifdef MIXBUS32C //in 32C, we can use the joystick for the last 2 mixbus send level & pans
624 if (_stype == st_joy && _joystick_active) {
625 if (ev->controller_number == 0x03) {
626 float value = (float)ev->value / 127.0;
627 float db_value = 20.0 * value;
628 float inv_db = 20.0 - db_value;
629 boost::shared_ptr<Stripable> r = mcp().subview_stripable();
630 if (r && r->is_input_strip()) {
631 boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (10);
633 pc->set_value (-db_value , PBD::Controllable::NoGroup);
635 pc = r->send_level_controllable (11);
637 pc->set_value (-inv_db, PBD::Controllable::NoGroup);
641 if (ev->controller_number == 0x02) {
642 float value = (float)ev->value / 127.0;
643 boost::shared_ptr<Stripable> r = mcp().subview_stripable();
644 if (r && r->is_input_strip()) {
645 boost::shared_ptr<AutomationControl> pc = r->send_pan_azi_controllable (10);
647 float v = pc->interface_to_internal(value);
648 pc->set_value (v, PBD::Controllable::NoGroup);
650 pc = r->send_pan_azi_controllable (11);
652 float v = pc->interface_to_internal(value);
653 pc->set_value (v, PBD::Controllable::NoGroup);
661 Pot* pot = pots[ev->controller_number];
663 // bit 6 gives the sign
664 float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
665 // bits 0..5 give the velocity. we interpret this as "ticks
666 // moved before this message was sent"
667 float ticks = (ev->value & 0x3f);
669 /* euphonix and perhaps other devices send zero
670 when they mean 1, we think.
676 if (mcp().main_modifier_state() == US2400Protocol::MODIFIER_SHIFT) {
677 delta = sign * (ticks / (float) 0xff);
679 delta = sign * (ticks / (float) 0x3f);
683 if (ev->controller_number == Jog::ID && _jog_wheel) {
685 DEBUG_TRACE (DEBUG::US2400, string_compose ("Jog wheel moved %1\n", ticks));
686 _jog_wheel->jog_event (delta);
689 // add external (pedal?) control here
694 Strip* strip = dynamic_cast<Strip*> (&pot->group());
696 strip->handle_pot (*pot, delta);
701 Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
703 MidiByteArray bytes (count, raw_bytes);
705 /* always save the device type ID so that our outgoing sysex messages
709 if (_stype == st_mcu) {
710 mackie_sysex_hdr[4] = bytes[4];
712 mackie_sysex_hdr_xt[4] = bytes[4];
718 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface #%1, handle_midi_sysex: %2\n", _number, bytes));
719 DEBUG_TRACE (DEBUG::US2400, string_compose ("Mackie Control Device ready, current status = %1\n", _active));
726 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface #%1, handle_midi_sysex: %2\n", _number, bytes));
728 /* Behringer X-Touch Compact: Device Ready
730 DEBUG_TRACE (DEBUG::US2400, string_compose ("Behringer X-Touch Compact ready, current status = %1\n", _active));
734 case 0x03: /* LCP Connection Confirmation */
735 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface #%1, handle_midi_sysex: %2\n", _number, bytes));
736 DEBUG_TRACE (DEBUG::US2400, "Logic Control Device confirms connection, ardour replies\n");
737 // if (bytes[4] == 0x10 || bytes[4] == 0x11) {
738 // write_sysex (host_connection_confirmation (bytes)); turn_it_on ();
743 // case 0x04: /* LCP: Confirmation Denied */
744 // DEBUG_TRACE (DEBUG::US2400, string_compose ("surface #%1, handle_midi_sysex: %2\n", _number, bytes));
745 // DEBUG_TRACE (DEBUG::US2400, "Logic Control Device denies connection\n");
750 DEBUG_TRACE (DEBUG::US2400, string_compose ("surface #%1, handle_midi_sysex: %2\n", _number, bytes));
751 // DEBUG_TRACE (DEBUG::US2400, string_compose ("unknown device ID byte %1", (int) bytes[5]));
752 error << "MCP: unknown sysex: " << bytes << endmsg;
757 calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
760 back_insert_iterator<MidiByteArray> back (l);
761 copy (begin, end, back);
763 MidiByteArray retval;
765 // this is how to calculate the response to the challenge.
766 // from the Logic docs.
767 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
768 retval << (0x7f & ((l[2] >> l[3]) ^ (l[0] + l[3])));
769 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
770 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
776 Surface::host_connection_query (MidiByteArray & bytes)
778 MidiByteArray response;
780 if (bytes[4] != 0x10 && bytes[4] != 0x11) {
781 /* not a Logic Control device - no response required */
785 // handle host connection query
786 DEBUG_TRACE (DEBUG::US2400, string_compose ("host connection query: %1\n", bytes));
788 if (bytes.size() != 18) {
789 cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
793 // build and send host connection reply
795 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
796 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
801 Surface::host_connection_confirmation (const MidiByteArray & bytes)
803 DEBUG_TRACE (DEBUG::US2400, string_compose ("host_connection_confirmation: %1\n", bytes));
805 // decode host connection confirmation
806 if (bytes.size() != 14) {
808 os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
809 throw MackieControlException (os.str());
812 // send version request
813 return MidiByteArray (2, 0x13, 0x00);
817 Surface::turn_it_on ()
825 _mcp.device_ready (); //this gets redundantly called with each new surface connection; but this is desirable to get the banks set up correctly
827 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
834 Surface::write_sysex (const MidiByteArray & mba)
841 buf << sysex_hdr() << mba << MIDI::eox;
846 Surface::write_sysex (MIDI::byte msg)
849 buf << sysex_hdr() << msg << MIDI::eox;
854 Surface::n_strips (bool with_locked_strips) const
856 if (with_locked_strips) {
857 return strips.size();
862 for (Strips::const_iterator it = strips.begin(); it != strips.end(); ++it) {
863 if (!(*it)->locked()) {
871 Surface::nth_strip (uint32_t n) const
873 if (n > n_strips()) {
882 if (_mcp.device_info().has_master_fader () && _master_fader) {
883 _port->write (_master_fader->zero ());
887 for (Strips::iterator it = strips.begin(); it != strips.end(); ++it) {
895 Surface::zero_controls ()
897 if (!_mcp.device_info().has_global_controls()) {
901 // turn off global buttons and leds
903 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
904 Control & control = **it;
905 if (!control.group().is_strip()) {
906 _port->write (control.zero());
910 // and the led ring for the master strip
913 _last_master_gain_written = 0.0f;
917 Surface::periodic (uint64_t now_usecs)
920 master_gain_changed();
921 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
922 (*s)->periodic (now_usecs);
928 Surface::redisplay (ARDOUR::microseconds_t now, bool force)
930 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
931 (*s)->redisplay (now, force);
936 Surface::write (const MidiByteArray& data)
941 DEBUG_TRACE (DEBUG::US2400, "surface not active, write ignored\n");
946 Surface::update_strip_selection ()
948 Strips::iterator s = strips.begin();
949 for ( ; s != strips.end(); ++s) {
950 (*s)->update_selection_state();
955 Surface::map_stripables (const vector<boost::shared_ptr<Stripable> >& stripables)
957 vector<boost::shared_ptr<Stripable> >::const_iterator r;
958 Strips::iterator s = strips.begin();
960 DEBUG_TRACE (DEBUG::US2400, string_compose ("Mapping %1 stripables to %2 strips\n", stripables.size(), strips.size()));
962 for (r = stripables.begin(); r != stripables.end() && s != strips.end(); ++s) {
964 /* don't try to assign stripables to a locked strip. it won't
965 use it anyway, but if we do, then we get out of sync
966 with the proposed mapping.
969 if (!(*s)->locked()) {
970 DEBUG_TRACE (DEBUG::US2400, string_compose ("Mapping stripable \"%1\" to strip %2\n", (*r)->name(), (*s)->global_index()));
971 (*s)->set_stripable (*r);
976 for (; s != strips.end(); ++s) {
977 DEBUG_TRACE (DEBUG::US2400, string_compose ("strip %1 being set to null stripable\n", (*s)->global_index()));
978 (*s)->reset_stripable ();
983 Surface::subview_mode_changed ()
985 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
986 (*s)->subview_mode_changed ();
989 //channel selection likely changed. disable the joystick so it doesn't send spurious messages
990 if (_stype == st_joy) {
991 _joystick_active = false;
996 Surface::say_hello ()
998 /* wakeup for Mackie Control */
999 MidiByteArray wakeup (7, MIDI::sysex, 0x00, 0x00, 0x66, 0x14, 0x00, MIDI::eox);
1000 _port->write (wakeup);
1001 wakeup[4] = 0x15; /* wakup Mackie XT */
1002 _port->write (wakeup);
1003 wakeup[4] = 0x10; /* wakeup Logic Control */
1004 _port->write (wakeup);
1005 wakeup[4] = 0x11; /* wakeup Logic Control XT */
1006 _port->write (wakeup);
1010 Surface::next_jog_mode ()
1015 Surface::set_jog_mode (JogWheel::Mode)
1020 Surface::stripable_is_locked_to_strip (boost::shared_ptr<Stripable> stripable) const
1022 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1023 if ((*s)->stripable() == stripable && (*s)->locked()) {
1031 Surface::stripable_is_mapped (boost::shared_ptr<Stripable> stripable) const
1033 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1034 if ((*s)->stripable() == stripable) {
1043 Surface::notify_metering_state_changed()
1045 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1046 (*s)->notify_metering_state_changed ();
1054 /* reset msg for Mackie Control */
1065 Surface::toggle_backlight ()
1067 return; //avoid sending anything that might be misconstrued
1071 Surface::recalibrate_faders ()
1073 return; //avoid sending anything that might be misconstrued
1077 Surface::set_touch_sensitivity (int sensitivity)
1079 /* NOTE: assumed called from GUI code, hence sleep() */
1081 /* sensitivity already clamped by caller */
1086 msg << sysex_hdr ();
1088 msg << 0xff; /* overwritten for each fader below */
1089 msg << (sensitivity & 0x7f);
1092 for (int fader = 0; fader < 9; ++fader) {
1100 Surface::hui_heartbeat ()
1106 MidiByteArray msg (3, MIDI::on, 0x0, 0x0);
1111 Surface::connected ()
1113 DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 now connected, trying to ping device...\n", _name));