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 ()
376 Surface::setup_master ()
378 boost::shared_ptr<Route> m;
380 if ((m = _mcp.get_session().monitor_out()) == 0) {
381 m = _mcp.get_session().master_out();
385 _master_fader->set_control (boost::shared_ptr<AutomationControl>());
386 master_connection.disconnect ();
390 if (!_master_fader) {
391 _master_fader = dynamic_cast<Fader*> (Fader::factory (*this, _mcp.device_info().strip_cnt(), "master", *groups["master"]));
393 Groups::iterator group_it;
394 group_it = groups.find("master");
396 DeviceInfo device_info = _mcp.device_info();
397 GlobalButtonInfo master_button = device_info.get_global_button(Button::MasterFaderTouch);
398 Button* bb = dynamic_cast<Button*> (Button::factory (
400 Button::MasterFaderTouch,
406 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 Master Fader new button BID %2 id %3\n",
407 number(), Button::MasterFaderTouch, bb->id()));
409 master_connection.disconnect ();
412 _master_fader->set_control (m->gain_control());
413 m->gain_control()->Changed.connect (master_connection, MISSING_INVALIDATOR, boost::bind (&Surface::master_gain_changed, this), ui_context());
414 _last_master_gain_written = FLT_MAX; /* some essentially impossible value */
415 master_gain_changed ();
419 Surface::master_gain_changed ()
421 if (!_master_fader) {
425 boost::shared_ptr<AutomationControl> ac = _master_fader->control();
430 float normalized_position = ac->internal_to_interface (ac->get_value());
431 if (normalized_position == _last_master_gain_written) {
435 DEBUG_TRACE (DEBUG::MackieControl, "Surface::master_gain_changed: updating surface master fader\n");
437 _port->write (_master_fader->set_position (normalized_position));
438 _last_master_gain_written = normalized_position;
442 Surface::scaled_delta (float delta, float current_speed)
444 /* XXX needs work before use */
445 const float sign = delta < 0.0 ? -1.0 : 1.0;
447 return ((sign * std::pow (delta + 1.0, 2.0)) + current_speed) / 100.0;
451 Surface::display_bank_start (uint32_t current_bank)
453 if (current_bank == 0) {
454 // send Ar. to 2-char display on the master
455 show_two_char_display ("Ar", "..");
457 // write the current first remote_id to the 2-char display
458 show_two_char_display (current_bank);
463 Surface::blank_jog_ring ()
465 Control* control = controls_by_device_independent_id[Jog::ID];
468 Pot* pot = dynamic_cast<Pot*> (control);
470 _port->write (pot->set (0.0, false, Pot::spread));
476 Surface::scrub_scaling_factor () const
482 Surface::connect_to_signals ()
487 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 connecting to signals on port %2\n",
488 number(), _port->input_port().name()));
490 MIDI::Parser* p = _port->input_port().parser();
493 p->sysex.connect_same_thread (*this, boost::bind (&Surface::handle_midi_sysex, this, _1, _2, _3));
494 /* V-Pot messages are Controller */
495 p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2));
496 /* Button messages are NoteOn */
497 p->note_on.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
498 /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
499 p->note_off.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
500 /* Fader messages are Pitchbend */
502 for (i = 0; i < _mcp.device_info().strip_cnt(); i++) {
503 p->channel_pitchbend[i].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, i));
506 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()));
513 Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
515 /* Pitchbend messages are fader position messages. Nothing in the data we get
516 * from the MIDI::Parser conveys the fader ID, which was given by the
517 * channel ID in the status byte.
519 * Instead, we have used bind() to supply the fader-within-strip ID
520 * when we connected to the per-channel pitchbend events.
523 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_pitchbend_message on port %3, fader = %1 value = %2 (%4)\n",
524 fader_id, pb, _number, pb/16384.0));
526 if (_mcp.device_info().no_handshake()) {
530 if (_mcp.main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
531 /* user is doing a reset to unity gain but device sends a PB
532 * message in the middle of the touch on/off messages. Ignore
538 Fader* fader = faders[fader_id];
541 Strip* strip = dynamic_cast<Strip*> (&fader->group());
542 float pos = pb / 16384.0;
544 strip->handle_fader (*fader, pos);
546 DEBUG_TRACE (DEBUG::MackieControl, "Handling master fader\n");
548 fader->set_value (pos); // alter master gain
549 _port->write (fader->set_position (pos)); // write back value (required for servo)
552 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
557 Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
559 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_note_on_message %1 = %2\n", (int) ev->note_number, (int) ev->velocity));
561 if (_mcp.device_info().no_handshake()) {
565 if (_mcp.device_info().device_type() == DeviceInfo::HUI && ev->note_number == 0 && ev->velocity == 127) {
569 /* fader touch sense is given by "buttons" 0xe..0xe7 and 0xe8 for the
573 if (ev->note_number >= 0xE0 && ev->note_number <= 0xE8) {
574 Fader* fader = faders[ev->note_number];
576 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface: fader touch message, fader = %1\n", fader));
580 Strip* strip = dynamic_cast<Strip*> (&fader->group());
582 if (ev->velocity > 64) {
583 strip->handle_fader_touch (*fader, true);
585 strip->handle_fader_touch (*fader, false);
591 Button* button = buttons[ev->note_number];
595 if (ev->velocity > 64) {
599 Strip* strip = dynamic_cast<Strip*> (&button->group());
602 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 button %2 pressed ? %3\n",
603 strip->index(), button->name(), (ev->velocity > 64)));
604 strip->handle_button (*button, ev->velocity > 64 ? press : release);
607 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("global button %1\n", button->id()));
608 _mcp.handle_button_event (*this, *button, ev->velocity > 64 ? press : release);
611 if (ev->velocity <= 64) {
616 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("no button found for %1\n", (int) ev->note_number));
619 /* button release should reset timer AFTER handler(s) have run */
623 Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
625 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::handle_midi_controller %1 = %2\n", (int) ev->controller_number, (int) ev->value));
627 if (_mcp.device_info().no_handshake()) {
631 Pot* pot = pots[ev->controller_number];
633 // bit 6 gives the sign
634 float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
635 // bits 0..5 give the velocity. we interpret this as "ticks
636 // moved before this message was sent"
637 float ticks = (ev->value & 0x3f);
639 /* euphonix and perhaps other devices send zero
640 when they mean 1, we think.
646 if (mcp().main_modifier_state() == MackieControlProtocol::MODIFIER_CONTROL) {
647 delta = sign * (ticks / (float) 0xff);
649 delta = sign * (ticks / (float) 0x3f);
653 if (ev->controller_number == Jog::ID && _jog_wheel) {
655 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", ticks));
656 _jog_wheel->jog_event (delta);
659 // add external (pedal?) control here
664 Strip* strip = dynamic_cast<Strip*> (&pot->group());
666 strip->handle_pot (*pot, delta);
671 Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
673 MidiByteArray bytes (count, raw_bytes);
675 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
677 if (_mcp.device_info().no_handshake()) {
681 /* always save the device type ID so that our outgoing sysex messages
686 mackie_sysex_hdr[4] = bytes[4];
688 mackie_sysex_hdr_xt[4] = bytes[4];
694 LCP: Connection Challenge
696 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
697 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device connection challenge\n");
698 write_sysex (host_connection_query (bytes));
700 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mackie Control Device ready, current status = %1\n", _active));
705 case 0x03: /* LCP Connection Confirmation */
706 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device confirms connection, ardour replies\n");
707 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
708 write_sysex (host_connection_confirmation (bytes));
713 case 0x04: /* LCP: Confirmation Denied */
714 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device denies connection\n");
718 error << "MCP: unknown sysex: " << bytes << endmsg;
723 calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
726 back_insert_iterator<MidiByteArray> back (l);
727 copy (begin, end, back);
729 MidiByteArray retval;
731 // this is how to calculate the response to the challenge.
732 // from the Logic docs.
733 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
734 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
735 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
736 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
742 Surface::host_connection_query (MidiByteArray & bytes)
744 MidiByteArray response;
746 if (bytes[4] != 0x10 && bytes[4] != 0x11) {
747 /* not a Logic Control device - no response required */
751 // handle host connection query
752 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
754 if (bytes.size() != 18) {
755 cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
759 // build and send host connection reply
761 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
762 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
767 Surface::host_connection_confirmation (const MidiByteArray & bytes)
769 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
771 // decode host connection confirmation
772 if (bytes.size() != 14) {
774 os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
775 throw MackieControlException (os.str());
778 // send version request
779 return MidiByteArray (2, 0x13, 0x00);
783 Surface::turn_it_on ()
791 _mcp.device_ready ();
793 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
797 update_view_mode_display ();
799 if (_mcp.device_info ().has_global_controls ()) {
800 _mcp.update_global_button (Button::Read, _mcp.metering_active ());
805 Surface::write_sysex (const MidiByteArray & mba)
812 buf << sysex_hdr() << mba << MIDI::eox;
817 Surface::write_sysex (MIDI::byte msg)
820 buf << sysex_hdr() << msg << MIDI::eox;
825 Surface::n_strips (bool with_locked_strips) const
827 if (with_locked_strips) {
828 return strips.size();
833 for (Strips::const_iterator it = strips.begin(); it != strips.end(); ++it) {
834 if (!(*it)->locked()) {
842 Surface::nth_strip (uint32_t n) const
844 if (n > n_strips()) {
853 if (_mcp.device_info().has_timecode_display ()) {
854 display_timecode (string (10, '0'), string (10, ' '));
857 if (_mcp.device_info().has_two_character_display()) {
858 show_two_char_display (string (2, '0'), string (2, ' '));
861 if (_mcp.device_info().has_master_fader () && _master_fader) {
862 _port->write (_master_fader->zero ());
866 for (Strips::iterator it = strips.begin(); it != strips.end(); ++it) {
874 Surface::zero_controls ()
876 if (!_mcp.device_info().has_global_controls()) {
880 // turn off global buttons and leds
882 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
883 Control & control = **it;
884 if (!control.group().is_strip()) {
885 _port->write (control.zero());
889 // and the led ring for the master strip
892 _last_master_gain_written = 0.0f;
896 Surface::periodic (uint64_t now_usecs)
898 master_gain_changed();
899 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
900 (*s)->periodic (now_usecs);
905 Surface::redisplay (ARDOUR::microseconds_t now)
907 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
908 (*s)->redisplay (now);
913 Surface::write (const MidiByteArray& data)
918 DEBUG_TRACE (DEBUG::MackieControl, "surface not active, write ignored\n");
923 Surface::map_routes (const vector<boost::shared_ptr<Route> >& routes)
925 vector<boost::shared_ptr<Route> >::const_iterator r;
926 Strips::iterator s = strips.begin();
928 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mapping %1 routes\n", routes.size()));
930 for (r = routes.begin(); r != routes.end() && s != strips.end(); ++s) {
932 /* don't try to assign routes to a locked strip. it won't
933 use it anyway, but if we do, then we get out of sync
934 with the proposed mapping.
937 if (!(*s)->locked()) {
938 (*s)->set_route (*r);
943 for (; s != strips.end(); ++s) {
944 (*s)->set_route (boost::shared_ptr<Route>());
949 translate_seven_segment (char achar)
951 achar = toupper (achar);
953 if (achar >= 0x40 && achar <= 0x60) {
955 } else if (achar >= 0x21 && achar <= 0x3f) {
963 Surface::show_two_char_display (const std::string & msg, const std::string & dots)
965 if (_stype != mcu || !_mcp.device_info().has_two_character_display() || msg.length() != 2 || dots.length() != 2) {
969 MidiByteArray right (3, 0xb0, 0x4b, 0x00);
970 MidiByteArray left (3, 0xb0, 0x4a, 0x00);
972 right[2] = translate_seven_segment (msg[0]) + (dots[0] == '.' ? 0x40 : 0x00);
973 left[2] = translate_seven_segment (msg[1]) + (dots[1] == '.' ? 0x40 : 0x00);
975 _port->write (right);
980 Surface::show_two_char_display (unsigned int value, const std::string & /*dots*/)
983 os << setfill('0') << setw(2) << value % 100;
984 show_two_char_display (os.str());
988 Surface::display_timecode (const std::string & timecode, const std::string & last_timecode)
990 if (!_active || !_mcp.device_info().has_timecode_display()) {
993 // if there's no change, send nothing, not even sysex header
994 if (timecode == last_timecode) return;
996 // length sanity checking
997 string local_timecode = timecode;
999 // truncate to 10 characters
1000 if (local_timecode.length() > 10) {
1001 local_timecode = local_timecode.substr (0, 10);
1004 // pad to 10 characters
1005 while (local_timecode.length() < 10) {
1006 local_timecode += " ";
1009 // translate characters.
1010 // Only the characters that actually changed are sent.
1011 int position = 0x3f;
1013 for (i = local_timecode.length () - 1; i >= 0; i--) {
1015 if (local_timecode[i] == last_timecode[i]) {
1018 MidiByteArray retval (2, 0xb0, position);
1019 retval << translate_seven_segment (local_timecode[i]);
1020 _port->write (retval);
1025 Surface::update_flip_mode_display ()
1027 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1028 (*s)->potmode_changed (true);
1033 Surface::update_potmode ()
1035 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1036 (*s)->potmode_changed (false);
1041 Surface::subview_mode_changed ()
1043 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1044 (*s)->subview_mode_changed ();
1047 if (_mcp.subview_mode() == MackieControlProtocol::None) {
1048 update_view_mode_display ();
1053 Surface::update_view_mode_display ()
1062 switch (_mcp.view_mode()) {
1063 case MackieControlProtocol::Mixer:
1064 show_two_char_display ("Mx");
1066 text = _("Mixer View");
1068 case MackieControlProtocol::AudioTracks:
1069 show_two_char_display ("AT");
1070 id = Button::AudioTracks;
1071 text = _("Audio Tracks");
1073 case MackieControlProtocol::MidiTracks:
1074 show_two_char_display ("MT");
1075 id = Button::MidiTracks;
1076 text = _("MIDI Tracks");
1078 case MackieControlProtocol::Plugins:
1079 show_two_char_display ("PL");
1080 id = Button::Plugin;
1081 text = _("Plugins");
1083 case MackieControlProtocol::Busses:
1084 show_two_char_display ("BS");
1085 id = Button::Busses;
1086 if (Profile->get_mixbus()) {
1087 text = _("Mixbusses");
1092 case MackieControlProtocol::Auxes:
1093 show_two_char_display ("Au");
1097 case MackieControlProtocol::Selected:
1098 show_two_char_display ("SE");
1100 text = _("Selected Routes");
1106 vector<int> view_mode_buttons;
1107 view_mode_buttons.push_back (Button::View);
1108 view_mode_buttons.push_back (Button::Busses);
1109 view_mode_buttons.push_back (Button::Plugin);
1110 view_mode_buttons.push_back (Button::AudioTracks);
1111 view_mode_buttons.push_back (Button::MidiTracks);
1112 view_mode_buttons.push_back (Button::Aux);
1113 view_mode_buttons.push_back (Button::User);
1117 for (vector<int>::iterator i = view_mode_buttons.begin(); i != view_mode_buttons.end(); ++i) {
1118 map<int,Control*>::iterator x = controls_by_device_independent_id.find (id);
1120 if (x != controls_by_device_independent_id.end()) {
1121 Button* button = dynamic_cast<Button*> (x->second);
1126 _port->write (button->set_state (onoff));
1132 if (!text.empty()) {
1133 display_message_for (text, 1000);
1138 Surface::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& routes)
1140 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1141 (*s)->gui_selection_changed (routes);
1146 Surface::say_hello ()
1148 /* wakeup for Mackie Control */
1149 MidiByteArray wakeup (7, MIDI::sysex, 0x00, 0x00, 0x66, 0x14, 0x00, MIDI::eox);
1150 _port->write (wakeup);
1151 wakeup[4] = 0x15; /* wakup Mackie XT */
1152 _port->write (wakeup);
1153 wakeup[4] = 0x10; /* wakeup Logic Control */
1154 _port->write (wakeup);
1155 wakeup[4] = 0x11; /* wakeup Logic Control XT */
1156 _port->write (wakeup);
1160 Surface::next_jog_mode ()
1165 Surface::set_jog_mode (JogWheel::Mode)
1170 Surface::route_is_locked_to_strip (boost::shared_ptr<Route> r) const
1172 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1173 if ((*s)->route() == r && (*s)->locked()) {
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);