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_SHIFT) {
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)->flip_mode_changed ();
1027 Surface::subview_mode_changed ()
1029 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1030 (*s)->subview_mode_changed ();
1035 Surface::update_view_mode_display (bool with_helpful_text)
1044 switch (_mcp.view_mode()) {
1045 case MackieControlProtocol::Mixer:
1046 show_two_char_display ("Mx");
1048 text = _("Mixer View");
1050 case MackieControlProtocol::AudioTracks:
1051 show_two_char_display ("AT");
1052 id = Button::AudioTracks;
1053 text = _("Audio Tracks");
1055 case MackieControlProtocol::MidiTracks:
1056 show_two_char_display ("MT");
1057 id = Button::MidiTracks;
1058 text = _("MIDI Tracks");
1060 case MackieControlProtocol::Plugins:
1061 show_two_char_display ("PL");
1062 id = Button::Plugin;
1063 text = _("Plugins");
1065 case MackieControlProtocol::Busses:
1066 show_two_char_display ("BS");
1067 id = Button::Busses;
1068 if (Profile->get_mixbus()) {
1069 text = _("Mixbusses");
1074 case MackieControlProtocol::Auxes:
1075 show_two_char_display ("Au");
1079 case MackieControlProtocol::Hidden:
1080 show_two_char_display ("HI");
1081 id = Button::Outputs;
1082 text = _("Hidden Tracks");
1084 case MackieControlProtocol::Selected:
1085 show_two_char_display ("SE");
1087 text = _("Selected Tracks");
1093 vector<int> view_mode_buttons;
1094 view_mode_buttons.push_back (Button::View);
1095 view_mode_buttons.push_back (Button::Busses);
1096 view_mode_buttons.push_back (Button::Plugin);
1097 view_mode_buttons.push_back (Button::AudioTracks);
1098 view_mode_buttons.push_back (Button::MidiTracks);
1099 view_mode_buttons.push_back (Button::Aux);
1100 view_mode_buttons.push_back (Button::Outputs);
1101 view_mode_buttons.push_back (Button::User);
1105 for (vector<int>::iterator i = view_mode_buttons.begin(); i != view_mode_buttons.end(); ++i) {
1106 map<int,Control*>::iterator x = controls_by_device_independent_id.find (id);
1108 if (x != controls_by_device_independent_id.end()) {
1109 Button* button = dynamic_cast<Button*> (x->second);
1114 _port->write (button->set_state (onoff));
1120 if (with_helpful_text && !text.empty()) {
1121 display_message_for (text, 1000);
1126 Surface::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& routes)
1128 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1129 (*s)->gui_selection_changed (routes);
1134 Surface::say_hello ()
1136 /* wakeup for Mackie Control */
1137 MidiByteArray wakeup (7, MIDI::sysex, 0x00, 0x00, 0x66, 0x14, 0x00, MIDI::eox);
1138 _port->write (wakeup);
1139 wakeup[4] = 0x15; /* wakup Mackie XT */
1140 _port->write (wakeup);
1141 wakeup[4] = 0x10; /* wakeup Logic Control */
1142 _port->write (wakeup);
1143 wakeup[4] = 0x11; /* wakeup Logic Control XT */
1144 _port->write (wakeup);
1148 Surface::next_jog_mode ()
1153 Surface::set_jog_mode (JogWheel::Mode)
1158 Surface::route_is_locked_to_strip (boost::shared_ptr<Route> r) const
1160 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1161 if ((*s)->route() == r && (*s)->locked()) {
1169 Surface::route_is_mapped (boost::shared_ptr<Route> r) const
1171 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1172 if ((*s)->route() == r) {
1181 Surface::notify_metering_state_changed()
1183 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1184 (*s)->notify_metering_state_changed ();
1192 /* reset msg for Mackie Control */
1203 Surface::toggle_backlight ()
1206 int onoff = random() %2;
1208 msg << sysex_hdr ();
1210 msg << (onoff ? 0x1 : 0x0);
1217 Surface::recalibrate_faders ()
1221 msg << sysex_hdr ();
1230 Surface::set_touch_sensitivity (int sensitivity)
1232 /* NOTE: assumed called from GUI code, hence sleep() */
1234 /* sensitivity already clamped by caller */
1239 msg << sysex_hdr ();
1241 msg << 0xff; /* overwritten for each fader below */
1242 msg << (sensitivity & 0x7f);
1245 for (int fader = 0; fader < 9; ++fader) {
1253 Surface::hui_heartbeat ()
1259 MidiByteArray msg (3, MIDI::on, 0x0, 0x0);
1264 Surface::connected ()
1266 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 now connected, trying to ping device...\n", _name));
1270 if (_mcp.device_info().no_handshake()) {
1276 Surface::display_line (string const& msg, int line_num)
1278 MidiByteArray midi_msg;
1279 midi_msg << sysex_hdr ();
1281 midi_msg << (line_num ? 0x38 : 0x0); /* offsets into char array
1283 * correspond to line
1288 midi_msg.insert (midi_msg.end(), 55, ' ');
1292 /* ascii data to display. @param msg is UTF-8 which is not legal. */
1293 string ascii = Glib::convert_with_fallback (msg, "UTF-8", "ISO-8859-1", "_");
1294 string::size_type len = ascii.length();
1297 midi_msg << ascii.substr (0, 55);
1301 for (string::size_type i = len; i < 55; ++i) {
1307 midi_msg << MIDI::eox;
1312 /** display @param msg on the 55x2 screen for @param msecs milliseconds
1314 * @param msg is assumed to be UTF-8 encoded, and will be converted
1315 * to ASCII with an underscore as fallback character before being
1316 * sent to the device.
1319 Surface::display_message_for (string const& msg, uint64_t msecs)
1321 string::size_type newline;
1323 if ((newline = msg.find ('\n')) == string::npos) {
1325 _port->write (display_line (msg, 0));
1326 _port->write (display_line (string(), 1));
1328 } else if (newline == 0) {
1330 _port->write (display_line (string(), 0));
1331 _port->write (display_line (msg.substr (1), 1));
1335 string first_line = msg.substr (0, newline-1);
1336 string second_line = msg.substr (newline+1);
1338 _port->write (display_line (first_line, 0));
1339 _port->write (display_line (second_line.substr (0, second_line.find_first_of ('\n')), 1));
1342 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1343 (*s)->block_screen_display_for (msecs);