2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <glibmm/convert.h>
28 #include "pbd/stacktrace.h"
30 #include "midi++/port.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/automation_control.h"
34 #include "ardour/debug.h"
35 #include "ardour/route.h"
36 #include "ardour/panner.h"
37 #include "ardour/panner_shell.h"
38 #include "ardour/profile.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/session.h"
41 #include "ardour/utils.h"
43 #include <gtkmm2ext/gui_thread.h>
45 #include "control_group.h"
46 #include "surface_port.h"
49 #include "mackie_control_protocol.h"
50 #include "jog_wheel.h"
62 #ifdef PLATFORM_WINDOWS
63 #define random() rand()
70 using ARDOUR::Profile;
71 using ARDOUR::AutomationControl;
72 using namespace ArdourSurface;
73 using namespace Mackie;
75 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
77 // The MCU sysex header.4th byte Will be overwritten
78 // when we get an incoming sysex that identifies
80 static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x14);
82 // The MCU extender sysex header.4th byte Will be overwritten
83 // when we get an incoming sysex that identifies
85 static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15);
87 static MidiByteArray empty_midi_byte_array;
89 Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
98 , _last_master_gain_written (-0.0f)
99 , connection_state (0)
102 DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface init\n");
105 _port = new SurfacePort (*this);
107 throw failed_constructor ();
110 /* only the first Surface object has global controls */
111 /* lets use master_position instead */
112 uint32_t mp = _mcp.device_info().master_position();
114 DEBUG_TRACE (DEBUG::MackieControl, "Surface matches MasterPosition. Might have global controls.\n");
115 if (_mcp.device_info().has_global_controls()) {
117 DEBUG_TRACE (DEBUG::MackieControl, "init_controls done\n");
120 if (_mcp.device_info().has_master_fader()) {
122 DEBUG_TRACE (DEBUG::MackieControl, "setup_master done\n");
126 uint32_t n = _mcp.device_info().strip_cnt();
130 DEBUG_TRACE (DEBUG::MackieControl, "init_strips done\n");
133 if (_mcp.device_info().uses_ipmidi()) {
134 /* ipMIDI port already exists, we can just assume that we're
137 * If the user still hasn't connected the ipMIDI surface and/or
138 * turned it on, then they have to press "Discover Mackie
139 * Devices" in the GUI at the right time.
142 connection_state |= (InputConnected|OutputConnected);
146 connect_to_signals ();
148 DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface done\n");
153 DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface init\n");
156 g_source_destroy (input_source);
160 // delete groups (strips)
161 for (Groups::iterator it = groups.begin(); it != groups.end(); ++it) {
165 // delete controls (global buttons, master fader etc)
166 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
172 // the ports take time to release and we may be rebuilding right away
173 // in the case of changing devices.
175 DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface done\n");
179 Surface::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
185 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->input_name());
186 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->output_name());
188 if (ni == name1 || ni == name2) {
190 connection_state |= InputConnected;
192 connection_state &= ~InputConnected;
194 } else if (no == name1 || no == name2) {
196 connection_state |= OutputConnected;
198 connection_state &= ~OutputConnected;
205 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
207 /* this will send a device query message, which should
208 result in a response that will kick off device type
209 discovery and activation of the surface(s).
211 The intended order of events is:
213 - each surface sends a device query message
214 - devices respond with either MCP or LCP response (sysex in both
216 - sysex message causes Surface::turn_it_on() which tells the
217 MCP object that the surface is ready, and sets up strip
218 displays and binds faders and buttons for that surface
220 In the case of LCP, where this is a handshake process that could
221 fail, the response process to the initial sysex after a device query
222 will mark the surface inactive, which won't shut anything down
223 but will stop any writes to the device.
225 Note: there are no known cases of the handshake process failing.
227 We actually can't initiate this in this callback, so we have
228 to queue it with the MCP event loop.
231 /* XXX this is a horrible hack. Without a short sleep here,
232 something prevents the device wakeup messages from being
233 sent and/or the responses from being received.
240 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
244 return true; /* connection status changed */
250 XMLNode* node = new XMLNode (X_("Surface"));
251 node->add_property (X_("name"), _name);
252 node->add_child_nocopy (_port->get_state());
257 Surface::set_state (const XMLNode& node, int version)
259 /* Look for a node named after the device we're part of */
261 XMLNodeList const& children = node.children();
264 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
265 XMLProperty const* prop = (*c)->property (X_("name"));
267 if (prop->value() == _name) {
278 XMLNode* portnode = mynode->child (X_("Port"));
280 if (_port->set_state (*portnode, version)) {
289 Surface::sysex_hdr() const
292 case mcu: return mackie_sysex_hdr;
293 case ext: return mackie_sysex_hdr_xt;
295 cout << "SurfacePort::sysex_hdr _port_type not known" << endl;
296 return mackie_sysex_hdr;
299 static GlobalControlDefinition mackie_global_controls[] = {
300 { "external", Pot::External, Pot::factory, "none" },
301 { "fader_touch", Led::FaderTouch, Led::factory, "master" },
302 { "timecode", Led::Timecode, Led::factory, "none" },
303 { "beats", Led::Beats, Led::factory, "none" },
304 { "solo", Led::RudeSolo, Led::factory, "none" },
305 { "relay_click", Led::RelayClick, Led::factory, "none" },
306 { "", 0, Led::factory, "" }
310 Surface::init_controls()
314 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating groups\n");
315 groups["assignment"] = new Group ("assignment");
316 groups["automation"] = new Group ("automation");
317 groups["bank"] = new Group ("bank");
318 groups["cursor"] = new Group ("cursor");
319 groups["display"] = new Group ("display");
320 groups["function select"] = new Group ("function select");
321 groups["global view"] = new Group ("global view");
322 groups["master"] = new Group ("master");
323 groups["modifiers"] = new Group ("modifiers");
324 groups["none"] = new Group ("none");
325 groups["transport"] = new Group ("transport");
326 groups["user"] = new Group ("user");
327 groups["utilities"] = new Group ("utilities");
329 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating jog wheel\n");
330 if (_mcp.device_info().has_jog_wheel()) {
331 _jog_wheel = new Mackie::JogWheel (_mcp);
334 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating global controls\n");
335 for (uint32_t n = 0; mackie_global_controls[n].name[0]; ++n) {
336 group = groups[mackie_global_controls[n].group_name];
337 Control* control = mackie_global_controls[n].factory (*this, mackie_global_controls[n].id, mackie_global_controls[n].name, *group);
338 controls_by_device_independent_id[mackie_global_controls[n].id] = control;
341 /* add global buttons */
342 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: adding global buttons\n");
343 const map<Button::ID,GlobalButtonInfo>& global_buttons (_mcp.device_info().global_buttons());
345 for (map<Button::ID,GlobalButtonInfo>::const_iterator b = global_buttons.begin(); b != global_buttons.end(); ++b){
346 group = groups[b->second.group];
347 controls_by_device_independent_id[b->first] = Button::factory (*this, b->first, b->second.id, b->second.label, *group);
352 Surface::init_strips (uint32_t n)
354 const map<Button::ID,StripButtonInfo>& strip_buttons (_mcp.device_info().strip_buttons());
356 for (uint32_t i = 0; i < n; ++i) {
360 snprintf (name, sizeof (name), "strip_%d", (8* _number) + i);
362 Strip* strip = new Strip (*this, name, i, strip_buttons);
364 groups[name] = strip;
365 strips.push_back (strip);
370 Surface::master_monitor_may_have_changed ()
372 if (_number == _mcp.device_info().master_position()) {
378 Surface::setup_master ()
380 boost::shared_ptr<Route> m;
382 if ((m = _mcp.get_session().monitor_out()) == 0) {
383 m = _mcp.get_session().master_out();
387 _master_fader->set_control (boost::shared_ptr<AutomationControl>());
388 master_connection.disconnect ();
392 if (!_master_fader) {
393 _master_fader = dynamic_cast<Fader*> (Fader::factory (*this, _mcp.device_info().strip_cnt(), "master", *groups["master"]));
395 Groups::iterator group_it;
396 group_it = groups.find("master");
398 DeviceInfo device_info = _mcp.device_info();
399 GlobalButtonInfo master_button = device_info.get_global_button(Button::MasterFaderTouch);
400 Button* bb = dynamic_cast<Button*> (Button::factory (
402 Button::MasterFaderTouch,
408 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 Master Fader new button BID %2 id %3\n",
409 number(), Button::MasterFaderTouch, bb->id()));
411 master_connection.disconnect ();
414 _master_fader->set_control (m->gain_control());
415 m->gain_control()->Changed.connect (master_connection, MISSING_INVALIDATOR, boost::bind (&Surface::master_gain_changed, this), ui_context());
416 _last_master_gain_written = FLT_MAX; /* some essentially impossible value */
417 master_gain_changed ();
421 Surface::master_gain_changed ()
423 if (!_master_fader) {
427 boost::shared_ptr<AutomationControl> ac = _master_fader->control();
432 float normalized_position = ac->internal_to_interface (ac->get_value());
433 if (normalized_position == _last_master_gain_written) {
437 DEBUG_TRACE (DEBUG::MackieControl, "Surface::master_gain_changed: updating surface master fader\n");
439 _port->write (_master_fader->set_position (normalized_position));
440 _last_master_gain_written = normalized_position;
444 Surface::scaled_delta (float delta, float current_speed)
446 /* XXX needs work before use */
447 const float sign = delta < 0.0 ? -1.0 : 1.0;
449 return ((sign * std::pow (delta + 1.0, 2.0)) + current_speed) / 100.0;
453 Surface::display_bank_start (uint32_t current_bank)
455 if (current_bank == 0) {
456 // send Ar. to 2-char display on the master
457 show_two_char_display ("Ar", "..");
459 // write the current first remote_id to the 2-char display
460 show_two_char_display (current_bank);
465 Surface::blank_jog_ring ()
467 Control* control = controls_by_device_independent_id[Jog::ID];
470 Pot* pot = dynamic_cast<Pot*> (control);
472 _port->write (pot->set (0.0, false, Pot::spread));
478 Surface::scrub_scaling_factor () const
484 Surface::connect_to_signals ()
489 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 connecting to signals on port %2\n",
490 number(), _port->input_port().name()));
492 MIDI::Parser* p = _port->input_port().parser();
495 p->sysex.connect_same_thread (*this, boost::bind (&Surface::handle_midi_sysex, this, _1, _2, _3));
496 /* V-Pot messages are Controller */
497 p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2));
498 /* Button messages are NoteOn */
499 p->note_on.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
500 /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
501 p->note_off.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
502 /* Fader messages are Pitchbend */
504 for (i = 0; i < _mcp.device_info().strip_cnt(); i++) {
505 p->channel_pitchbend[i].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, i));
508 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()));
515 Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
517 /* Pitchbend messages are fader position messages. Nothing in the data we get
518 * from the MIDI::Parser conveys the fader ID, which was given by the
519 * channel ID in the status byte.
521 * Instead, we have used bind() to supply the fader-within-strip ID
522 * when we connected to the per-channel pitchbend events.
525 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_pitchbend_message on port %3, fader = %1 value = %2 (%4)\n",
526 fader_id, pb, _number, pb/16384.0));
528 if (_mcp.device_info().no_handshake()) {
532 Fader* fader = faders[fader_id];
535 Strip* strip = dynamic_cast<Strip*> (&fader->group());
536 float pos = pb / 16384.0;
538 strip->handle_fader (*fader, pos);
540 DEBUG_TRACE (DEBUG::MackieControl, "Handling master fader\n");
542 fader->set_value (pos); // alter master gain
543 _port->write (fader->set_position (pos)); // write back value (required for servo)
546 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
551 Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
553 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_note_on_message %1 = %2\n", (int) ev->note_number, (int) ev->velocity));
555 if (_mcp.device_info().no_handshake()) {
559 if (_mcp.device_info().device_type() == DeviceInfo::HUI && ev->note_number == 0 && ev->velocity == 127) {
563 /* fader touch sense is given by "buttons" 0xe..0xe7 and 0xe8 for the
567 if (ev->note_number >= 0xE0 && ev->note_number <= 0xE8) {
568 Fader* fader = faders[ev->note_number];
570 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface: fader touch message, fader = %1\n", fader));
574 Strip* strip = dynamic_cast<Strip*> (&fader->group());
576 if (ev->velocity > 64) {
577 strip->handle_fader_touch (*fader, true);
579 strip->handle_fader_touch (*fader, false);
585 Button* button = buttons[ev->note_number];
589 if (ev->velocity > 64) {
593 Strip* strip = dynamic_cast<Strip*> (&button->group());
596 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 button %2 pressed ? %3\n",
597 strip->index(), button->name(), (ev->velocity > 64)));
598 strip->handle_button (*button, ev->velocity > 64 ? press : release);
601 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("global button %1\n", button->id()));
602 _mcp.handle_button_event (*this, *button, ev->velocity > 64 ? press : release);
605 if (ev->velocity <= 64) {
610 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("no button found for %1\n", (int) ev->note_number));
613 /* button release should reset timer AFTER handler(s) have run */
617 Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
619 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::handle_midi_controller %1 = %2\n", (int) ev->controller_number, (int) ev->value));
621 if (_mcp.device_info().no_handshake()) {
625 Pot* pot = pots[ev->controller_number];
627 // bit 6 gives the sign
628 float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
629 // bits 0..5 give the velocity. we interpret this as "ticks
630 // moved before this message was sent"
631 float ticks = (ev->value & 0x3f);
633 /* euphonix and perhaps other devices send zero
634 when they mean 1, we think.
640 if (mcp().main_modifier_state() == MackieControlProtocol::MODIFIER_CONTROL) {
641 delta = sign * (ticks / (float) 0xff);
643 delta = sign * (ticks / (float) 0x3f);
647 if (ev->controller_number == Jog::ID && _jog_wheel) {
649 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", ticks));
650 _jog_wheel->jog_event (delta);
653 // add external (pedal?) control here
658 Strip* strip = dynamic_cast<Strip*> (&pot->group());
660 strip->handle_pot (*pot, delta);
665 Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
667 MidiByteArray bytes (count, raw_bytes);
669 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
671 if (_mcp.device_info().no_handshake()) {
675 /* always save the device type ID so that our outgoing sysex messages
680 mackie_sysex_hdr[4] = bytes[4];
682 mackie_sysex_hdr_xt[4] = bytes[4];
688 LCP: Connection Challenge
690 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
691 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device connection challenge\n");
692 write_sysex (host_connection_query (bytes));
694 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mackie Control Device ready, current status = %1\n", _active));
699 case 0x03: /* LCP Connection Confirmation */
700 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device confirms connection, ardour replies\n");
701 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
702 write_sysex (host_connection_confirmation (bytes));
707 case 0x04: /* LCP: Confirmation Denied */
708 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device denies connection\n");
712 error << "MCP: unknown sysex: " << bytes << endmsg;
717 calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
720 back_insert_iterator<MidiByteArray> back (l);
721 copy (begin, end, back);
723 MidiByteArray retval;
725 // this is how to calculate the response to the challenge.
726 // from the Logic docs.
727 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
728 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
729 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
730 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
736 Surface::host_connection_query (MidiByteArray & bytes)
738 MidiByteArray response;
740 if (bytes[4] != 0x10 && bytes[4] != 0x11) {
741 /* not a Logic Control device - no response required */
745 // handle host connection query
746 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
748 if (bytes.size() != 18) {
749 cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
753 // build and send host connection reply
755 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
756 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
761 Surface::host_connection_confirmation (const MidiByteArray & bytes)
763 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
765 // decode host connection confirmation
766 if (bytes.size() != 14) {
768 os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
769 throw MackieControlException (os.str());
772 // send version request
773 return MidiByteArray (2, 0x13, 0x00);
777 Surface::turn_it_on ()
785 _mcp.device_ready ();
787 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
791 update_view_mode_display (false);
793 // if (_mcp.device_info ().has_global_controls ()) {
794 // _mcp.update_global_button (Button::Read, _mcp.metering_active ());
799 Surface::write_sysex (const MidiByteArray & mba)
806 buf << sysex_hdr() << mba << MIDI::eox;
811 Surface::write_sysex (MIDI::byte msg)
814 buf << sysex_hdr() << msg << MIDI::eox;
819 Surface::n_strips (bool with_locked_strips) const
821 if (with_locked_strips) {
822 return strips.size();
827 for (Strips::const_iterator it = strips.begin(); it != strips.end(); ++it) {
828 if (!(*it)->locked()) {
836 Surface::nth_strip (uint32_t n) const
838 if (n > n_strips()) {
847 if (_mcp.device_info().has_timecode_display ()) {
848 display_timecode (string (10, '0'), string (10, ' '));
851 if (_mcp.device_info().has_two_character_display()) {
852 show_two_char_display (string (2, '0'), string (2, ' '));
855 if (_mcp.device_info().has_master_fader () && _master_fader) {
856 _port->write (_master_fader->zero ());
860 for (Strips::iterator it = strips.begin(); it != strips.end(); ++it) {
868 Surface::zero_controls ()
870 if (!_mcp.device_info().has_global_controls()) {
874 // turn off global buttons and leds
876 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
877 Control & control = **it;
878 if (!control.group().is_strip()) {
879 _port->write (control.zero());
883 // and the led ring for the master strip
886 _last_master_gain_written = 0.0f;
890 Surface::periodic (uint64_t now_usecs)
892 master_gain_changed();
893 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
894 (*s)->periodic (now_usecs);
899 Surface::redisplay (ARDOUR::microseconds_t now, bool force)
901 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
902 (*s)->redisplay (now, force);
907 Surface::write (const MidiByteArray& data)
912 DEBUG_TRACE (DEBUG::MackieControl, "surface not active, write ignored\n");
917 Surface::map_routes (const vector<boost::shared_ptr<Route> >& routes)
919 vector<boost::shared_ptr<Route> >::const_iterator r;
920 Strips::iterator s = strips.begin();
922 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mapping %1 routes\n", routes.size()));
924 for (r = routes.begin(); r != routes.end() && s != strips.end(); ++s) {
926 /* don't try to assign routes to a locked strip. it won't
927 use it anyway, but if we do, then we get out of sync
928 with the proposed mapping.
931 if (!(*s)->locked()) {
932 (*s)->set_route (*r);
937 for (; s != strips.end(); ++s) {
938 (*s)->set_route (boost::shared_ptr<Route>());
943 translate_seven_segment (char achar)
945 achar = toupper (achar);
947 if (achar >= 0x40 && achar <= 0x60) {
949 } else if (achar >= 0x21 && achar <= 0x3f) {
957 Surface::show_two_char_display (const std::string & msg, const std::string & dots)
959 if (_stype != mcu || !_mcp.device_info().has_two_character_display() || msg.length() != 2 || dots.length() != 2) {
963 MidiByteArray right (3, 0xb0, 0x4b, 0x00);
964 MidiByteArray left (3, 0xb0, 0x4a, 0x00);
966 right[2] = translate_seven_segment (msg[0]) + (dots[0] == '.' ? 0x40 : 0x00);
967 left[2] = translate_seven_segment (msg[1]) + (dots[1] == '.' ? 0x40 : 0x00);
969 _port->write (right);
974 Surface::show_two_char_display (unsigned int value, const std::string & /*dots*/)
977 os << setfill('0') << setw(2) << value % 100;
978 show_two_char_display (os.str());
982 Surface::display_timecode (const std::string & timecode, const std::string & last_timecode)
984 if (!_active || !_mcp.device_info().has_timecode_display()) {
987 // if there's no change, send nothing, not even sysex header
988 if (timecode == last_timecode) return;
990 // length sanity checking
991 string local_timecode = timecode;
993 // truncate to 10 characters
994 if (local_timecode.length() > 10) {
995 local_timecode = local_timecode.substr (0, 10);
998 // pad to 10 characters
999 while (local_timecode.length() < 10) {
1000 local_timecode += " ";
1003 // translate characters.
1004 // Only the characters that actually changed are sent.
1005 int position = 0x3f;
1007 for (i = local_timecode.length () - 1; i >= 0; i--) {
1009 if (local_timecode[i] == last_timecode[i]) {
1012 MidiByteArray retval (2, 0xb0, position);
1013 retval << translate_seven_segment (local_timecode[i]);
1014 _port->write (retval);
1019 Surface::update_flip_mode_display ()
1021 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1022 (*s)->potmode_changed (true);
1027 Surface::update_potmode ()
1029 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1030 (*s)->potmode_changed (false);
1035 Surface::subview_mode_changed ()
1037 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1038 (*s)->subview_mode_changed ();
1043 Surface::update_view_mode_display (bool with_helpful_text)
1052 switch (_mcp.view_mode()) {
1053 case MackieControlProtocol::Mixer:
1054 show_two_char_display ("Mx");
1056 text = _("Mixer View");
1058 case MackieControlProtocol::AudioTracks:
1059 show_two_char_display ("AT");
1060 id = Button::AudioTracks;
1061 text = _("Audio Tracks");
1063 case MackieControlProtocol::MidiTracks:
1064 show_two_char_display ("MT");
1065 id = Button::MidiTracks;
1066 text = _("MIDI Tracks");
1068 case MackieControlProtocol::Plugins:
1069 show_two_char_display ("PL");
1070 id = Button::Plugin;
1071 text = _("Plugins");
1073 case MackieControlProtocol::Busses:
1074 show_two_char_display ("BS");
1075 id = Button::Busses;
1076 if (Profile->get_mixbus()) {
1077 text = _("Mixbusses");
1082 case MackieControlProtocol::Auxes:
1083 show_two_char_display ("Au");
1087 case MackieControlProtocol::Hidden:
1088 show_two_char_display ("HI");
1089 id = Button::Outputs;
1090 text = _("Hidden Tracks");
1092 case MackieControlProtocol::Selected:
1093 show_two_char_display ("SE");
1095 text = _("Selected Tracks");
1101 vector<int> view_mode_buttons;
1102 view_mode_buttons.push_back (Button::View);
1103 view_mode_buttons.push_back (Button::Busses);
1104 view_mode_buttons.push_back (Button::Plugin);
1105 view_mode_buttons.push_back (Button::AudioTracks);
1106 view_mode_buttons.push_back (Button::MidiTracks);
1107 view_mode_buttons.push_back (Button::Aux);
1108 view_mode_buttons.push_back (Button::Outputs);
1109 view_mode_buttons.push_back (Button::User);
1113 for (vector<int>::iterator i = view_mode_buttons.begin(); i != view_mode_buttons.end(); ++i) {
1114 map<int,Control*>::iterator x = controls_by_device_independent_id.find (id);
1116 if (x != controls_by_device_independent_id.end()) {
1117 Button* button = dynamic_cast<Button*> (x->second);
1122 _port->write (button->set_state (onoff));
1128 if (with_helpful_text && !text.empty()) {
1129 display_message_for (text, 1000);
1134 Surface::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& routes)
1136 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1137 (*s)->gui_selection_changed (routes);
1142 Surface::say_hello ()
1144 /* wakeup for Mackie Control */
1145 MidiByteArray wakeup (7, MIDI::sysex, 0x00, 0x00, 0x66, 0x14, 0x00, MIDI::eox);
1146 _port->write (wakeup);
1147 wakeup[4] = 0x15; /* wakup Mackie XT */
1148 _port->write (wakeup);
1149 wakeup[4] = 0x10; /* wakeup Logic Control */
1150 _port->write (wakeup);
1151 wakeup[4] = 0x11; /* wakeup Logic Control XT */
1152 _port->write (wakeup);
1156 Surface::next_jog_mode ()
1161 Surface::set_jog_mode (JogWheel::Mode)
1166 Surface::route_is_locked_to_strip (boost::shared_ptr<Route> r) const
1168 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1169 if ((*s)->route() == r && (*s)->locked()) {
1177 Surface::route_is_mapped (boost::shared_ptr<Route> r) const
1179 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1180 if ((*s)->route() == r) {
1189 Surface::notify_metering_state_changed()
1191 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1192 (*s)->notify_metering_state_changed ();
1200 /* reset msg for Mackie Control */
1211 Surface::toggle_backlight ()
1214 int onoff = random() %2;
1216 msg << sysex_hdr ();
1218 msg << (onoff ? 0x1 : 0x0);
1225 Surface::recalibrate_faders ()
1229 msg << sysex_hdr ();
1238 Surface::set_touch_sensitivity (int sensitivity)
1240 /* NOTE: assumed called from GUI code, hence sleep() */
1242 /* sensitivity already clamped by caller */
1247 msg << sysex_hdr ();
1249 msg << 0xff; /* overwritten for each fader below */
1250 msg << (sensitivity & 0x7f);
1253 for (int fader = 0; fader < 9; ++fader) {
1261 Surface::hui_heartbeat ()
1267 MidiByteArray msg (3, MIDI::on, 0x0, 0x0);
1272 Surface::connected ()
1274 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 now connected, trying to ping device...\n", _name));
1278 if (_mcp.device_info().no_handshake()) {
1284 Surface::display_line (string const& msg, int line_num)
1286 MidiByteArray midi_msg;
1287 midi_msg << sysex_hdr ();
1289 midi_msg << (line_num ? 0x38 : 0x0); /* offsets into char array
1291 * correspond to line
1296 midi_msg.insert (midi_msg.end(), 55, ' ');
1300 /* ascii data to display. @param msg is UTF-8 which is not legal. */
1301 string ascii = Glib::convert_with_fallback (msg, "UTF-8", "ISO-8859-1", "_");
1302 string::size_type len = ascii.length();
1305 midi_msg << ascii.substr (0, 55);
1309 for (string::size_type i = len; i < 55; ++i) {
1315 midi_msg << MIDI::eox;
1320 /** display @param msg on the 55x2 screen for @param msecs milliseconds
1322 * @param msg is assumed to be UTF-8 encoded, and will be converted
1323 * to ASCII with an underscore as fallback character before being
1324 * sent to the device.
1327 Surface::display_message_for (string const& msg, uint64_t msecs)
1329 string::size_type newline;
1331 if ((newline = msg.find ('\n')) == string::npos) {
1333 _port->write (display_line (msg, 0));
1334 _port->write (display_line (string(), 1));
1336 } else if (newline == 0) {
1338 _port->write (display_line (string(), 0));
1339 _port->write (display_line (msg.substr (1), 1));
1343 string first_line = msg.substr (0, newline-1);
1344 string second_line = msg.substr (newline+1);
1346 _port->write (display_line (first_line, 0));
1347 _port->write (display_line (second_line.substr (0, second_line.find_first_of ('\n')), 1));
1350 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1351 (*s)->block_screen_display_for (msecs);