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 "midi++/port.h"
30 #include "ardour/audioengine.h"
31 #include "ardour/automation_control.h"
32 #include "ardour/debug.h"
33 #include "ardour/route.h"
34 #include "ardour/panner.h"
35 #include "ardour/panner_shell.h"
36 #include "ardour/rc_configuration.h"
37 #include "ardour/session.h"
38 #include "ardour/utils.h"
40 #include <gtkmm2ext/gui_thread.h>
42 #include "control_group.h"
43 #include "surface_port.h"
46 #include "mackie_control_protocol.h"
47 #include "jog_wheel.h"
59 #ifdef PLATFORM_WINDOWS
60 #define random() rand()
67 using ARDOUR::Pannable;
68 using ARDOUR::AutomationControl;
69 using namespace ArdourSurface;
70 using namespace Mackie;
72 #define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
74 // The MCU sysex header.4th byte Will be overwritten
75 // when we get an incoming sysex that identifies
77 static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x14);
79 // The MCU extender sysex header.4th byte Will be overwritten
80 // when we get an incoming sysex that identifies
82 static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15);
84 static MidiByteArray empty_midi_byte_array;
86 Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
95 , _last_master_gain_written (-0.0f)
96 , connection_state (0)
99 DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface init\n");
102 _port = new SurfacePort (*this);
104 throw failed_constructor ();
107 /* only the first Surface object has global controls */
108 /* lets use master_position instead */
109 uint32_t mp = _mcp.device_info().master_position();
111 DEBUG_TRACE (DEBUG::MackieControl, "Surface matches MasterPosition. Might have global controls.\n");
112 if (_mcp.device_info().has_global_controls()) {
114 DEBUG_TRACE (DEBUG::MackieControl, "init_controls done\n");
117 if (_mcp.device_info().has_master_fader()) {
119 DEBUG_TRACE (DEBUG::MackieControl, "setup_master done\n");
123 uint32_t n = _mcp.device_info().strip_cnt();
127 DEBUG_TRACE (DEBUG::MackieControl, "init_strips done\n");
130 if (_mcp.device_info().uses_ipmidi()) {
131 /* ipMIDI port already exists, we can just assume that we're
134 * If the user still hasn't connected the ipMIDI surface and/or
135 * turned it on, then they have to press "Discover Mackie
136 * Devices" in the GUI at the right time.
139 connection_state |= (InputConnected|OutputConnected);
143 connect_to_signals ();
145 DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface done\n");
150 DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface init\n");
153 g_source_destroy (input_source);
157 // delete groups (strips)
158 for (Groups::iterator it = groups.begin(); it != groups.end(); ++it) {
162 // delete controls (global buttons, master fader etc)
163 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
169 // the ports take time to release and we may be rebuilding right away
170 // in the case of changing devices.
172 DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface done\n");
176 Surface::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
182 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->input_name());
183 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->output_name());
185 if (ni == name1 || ni == name2) {
187 connection_state |= InputConnected;
189 connection_state &= ~InputConnected;
191 } else if (no == name1 || no == name2) {
193 connection_state |= OutputConnected;
195 connection_state &= ~OutputConnected;
202 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
204 /* this will send a device query message, which should
205 result in a response that will kick off device type
206 discovery and activation of the surface(s).
208 The intended order of events is:
210 - each surface sends a device query message
211 - devices respond with either MCP or LCP response (sysex in both
213 - sysex message causes Surface::turn_it_on() which tells the
214 MCP object that the surface is ready, and sets up strip
215 displays and binds faders and buttons for that surface
217 In the case of LCP, where this is a handshake process that could
218 fail, the response process to the initial sysex after a device query
219 will mark the surface inactive, which won't shut anything down
220 but will stop any writes to the device.
222 Note: there are no known cases of the handshake process failing.
224 We actually can't initiate this in this callback, so we have
225 to queue it with the MCP event loop.
228 /* XXX this is a horrible hack. Without a short sleep here,
229 something prevents the device wakeup messages from being
230 sent and/or the responses from being received.
237 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
241 return true; /* connection status changed */
247 XMLNode* node = new XMLNode (X_("Surface"));
248 node->add_property (X_("name"), _name);
249 node->add_child_nocopy (_port->get_state());
254 Surface::set_state (const XMLNode& node, int version)
256 /* Look for a node named after the device we're part of */
258 XMLNodeList const& children = node.children();
261 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
262 XMLProperty const* prop = (*c)->property (X_("name"));
264 if (prop->value() == _name) {
275 XMLNode* portnode = mynode->child (X_("Port"));
277 if (_port->set_state (*portnode, version)) {
286 Surface::sysex_hdr() const
289 case mcu: return mackie_sysex_hdr;
290 case ext: return mackie_sysex_hdr_xt;
292 cout << "SurfacePort::sysex_hdr _port_type not known" << endl;
293 return mackie_sysex_hdr;
296 static GlobalControlDefinition mackie_global_controls[] = {
297 { "external", Pot::External, Pot::factory, "none" },
298 { "fader_touch", Led::FaderTouch, Led::factory, "master" },
299 { "timecode", Led::Timecode, Led::factory, "none" },
300 { "beats", Led::Beats, Led::factory, "none" },
301 { "solo", Led::RudeSolo, Led::factory, "none" },
302 { "relay_click", Led::RelayClick, Led::factory, "none" },
303 { "", 0, Led::factory, "" }
307 Surface::init_controls()
311 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating groups\n");
312 groups["assignment"] = new Group ("assignment");
313 groups["automation"] = new Group ("automation");
314 groups["bank"] = new Group ("bank");
315 groups["cursor"] = new Group ("cursor");
316 groups["display"] = new Group ("display");
317 groups["function select"] = new Group ("function select");
318 groups["global view"] = new Group ("global view");
319 groups["master"] = new Group ("master");
320 groups["modifiers"] = new Group ("modifiers");
321 groups["none"] = new Group ("none");
322 groups["transport"] = new Group ("transport");
323 groups["user"] = new Group ("user");
324 groups["utilities"] = new Group ("utilities");
326 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating jog wheel\n");
327 if (_mcp.device_info().has_jog_wheel()) {
328 _jog_wheel = new Mackie::JogWheel (_mcp);
331 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: creating global controls\n");
332 for (uint32_t n = 0; mackie_global_controls[n].name[0]; ++n) {
333 group = groups[mackie_global_controls[n].group_name];
334 Control* control = mackie_global_controls[n].factory (*this, mackie_global_controls[n].id, mackie_global_controls[n].name, *group);
335 controls_by_device_independent_id[mackie_global_controls[n].id] = control;
338 /* add global buttons */
339 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init_controls: adding global buttons\n");
340 const map<Button::ID,GlobalButtonInfo>& global_buttons (_mcp.device_info().global_buttons());
342 for (map<Button::ID,GlobalButtonInfo>::const_iterator b = global_buttons.begin(); b != global_buttons.end(); ++b){
343 group = groups[b->second.group];
344 controls_by_device_independent_id[b->first] = Button::factory (*this, b->first, b->second.id, b->second.label, *group);
349 Surface::init_strips (uint32_t n)
351 const map<Button::ID,StripButtonInfo>& strip_buttons (_mcp.device_info().strip_buttons());
353 for (uint32_t i = 0; i < n; ++i) {
357 snprintf (name, sizeof (name), "strip_%d", (8* _number) + i);
359 Strip* strip = new Strip (*this, name, i, strip_buttons);
361 groups[name] = strip;
362 strips.push_back (strip);
367 Surface::master_monitor_may_have_changed ()
369 std::cerr << "MMmhc\n";
371 std::cerr << " done\n";
375 Surface::setup_master ()
377 boost::shared_ptr<Route> m;
379 if ((m = _mcp.get_session().monitor_out()) == 0) {
380 m = _mcp.get_session().master_out();
384 _master_fader->set_control (boost::shared_ptr<AutomationControl>());
385 master_connection.disconnect ();
389 if (!_master_fader) {
390 _master_fader = dynamic_cast<Fader*> (Fader::factory (*this, _mcp.device_info().strip_cnt(), "master", *groups["master"]));
392 Groups::iterator group_it;
393 group_it = groups.find("master");
395 DeviceInfo device_info = _mcp.device_info();
396 GlobalButtonInfo master_button = device_info.get_global_button(Button::MasterFaderTouch);
397 Button* bb = dynamic_cast<Button*> (Button::factory (
399 Button::MasterFaderTouch,
405 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface %1 Master Fader new button BID %2 id %3\n",
406 number(), Button::MasterFaderTouch, bb->id()));
408 master_connection.disconnect ();
411 _master_fader->set_control (m->gain_control());
412 m->gain_control()->Changed.connect (master_connection, MISSING_INVALIDATOR, boost::bind (&Surface::master_gain_changed, this), ui_context());
413 _last_master_gain_written = FLT_MAX; /* some essentially impossible value */
414 master_gain_changed ();
418 Surface::master_gain_changed ()
420 if (!_master_fader) {
424 boost::shared_ptr<AutomationControl> ac = _master_fader->control();
426 std::cerr << "no control!\n";
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 std::cerr << "send " << normalized_position << std::endl;
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 if (_mcp.main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
533 /* user is doing a reset to unity gain but device sends a PB
534 * message in the middle of the touch on/off messages. Ignore
540 Fader* fader = faders[fader_id];
543 Strip* strip = dynamic_cast<Strip*> (&fader->group());
544 float pos = pb / 16384.0;
546 strip->handle_fader (*fader, pos);
548 DEBUG_TRACE (DEBUG::MackieControl, "Handling master fader\n");
550 fader->set_value (pos); // alter master gain
551 _port->write (fader->set_position (pos)); // write back value (required for servo)
554 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
559 Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
561 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_note_on_message %1 = %2\n", (int) ev->note_number, (int) ev->velocity));
563 if (_mcp.device_info().no_handshake()) {
567 if (_mcp.device_info().device_type() == DeviceInfo::HUI && ev->note_number == 0 && ev->velocity == 127) {
571 /* fader touch sense is given by "buttons" 0xe..0xe7 and 0xe8 for the
575 if (ev->note_number >= 0xE0 && ev->note_number <= 0xE8) {
576 Fader* fader = faders[ev->note_number];
578 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface: fader touch message, fader = %1\n", fader));
582 Strip* strip = dynamic_cast<Strip*> (&fader->group());
584 if (ev->velocity > 64) {
585 strip->handle_fader_touch (*fader, true);
587 strip->handle_fader_touch (*fader, false);
593 Button* button = buttons[ev->note_number];
597 if (ev->velocity > 64) {
601 Strip* strip = dynamic_cast<Strip*> (&button->group());
604 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 button %2 pressed ? %3\n",
605 strip->index(), button->name(), (ev->velocity > 64)));
606 strip->handle_button (*button, ev->velocity > 64 ? press : release);
609 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("global button %1\n", button->id()));
610 _mcp.handle_button_event (*this, *button, ev->velocity > 64 ? press : release);
613 if (ev->velocity <= 64) {
618 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("no button found for %1\n", (int) ev->note_number));
621 /* button release should reset timer AFTER handler(s) have run */
625 Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
627 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::handle_midi_controller %1 = %2\n", (int) ev->controller_number, (int) ev->value));
629 if (_mcp.device_info().no_handshake()) {
633 Pot* pot = pots[ev->controller_number];
635 // bit 6 gives the sign
636 float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
637 // bits 0..5 give the velocity. we interpret this as "ticks
638 // moved before this message was sent"
639 float ticks = (ev->value & 0x3f);
641 /* euphonix and perhaps other devices send zero
642 when they mean 1, we think.
648 if (mcp().main_modifier_state() == MackieControlProtocol::MODIFIER_CONTROL) {
649 delta = sign * (ticks / (float) 0xff);
651 delta = sign * (ticks / (float) 0x3f);
655 if (ev->controller_number == Jog::ID && _jog_wheel) {
657 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", ticks));
658 _jog_wheel->jog_event (delta);
661 // add external (pedal?) control here
666 Strip* strip = dynamic_cast<Strip*> (&pot->group());
668 strip->handle_pot (*pot, delta);
673 Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
675 MidiByteArray bytes (count, raw_bytes);
677 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
679 if (_mcp.device_info().no_handshake()) {
683 /* always save the device type ID so that our outgoing sysex messages
688 mackie_sysex_hdr[4] = bytes[4];
690 mackie_sysex_hdr_xt[4] = bytes[4];
696 LCP: Connection Challenge
698 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
699 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device connection challenge\n");
700 write_sysex (host_connection_query (bytes));
702 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mackie Control Device ready, current status = %1\n", _active));
707 case 0x03: /* LCP Connection Confirmation */
708 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device confirms connection, ardour replies\n");
709 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
710 write_sysex (host_connection_confirmation (bytes));
715 case 0x04: /* LCP: Confirmation Denied */
716 DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device denies connection\n");
720 error << "MCP: unknown sysex: " << bytes << endmsg;
725 calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
728 back_insert_iterator<MidiByteArray> back (l);
729 copy (begin, end, back);
731 MidiByteArray retval;
733 // this is how to calculate the response to the challenge.
734 // from the Logic docs.
735 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
736 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
737 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
738 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
744 Surface::host_connection_query (MidiByteArray & bytes)
746 MidiByteArray response;
748 if (bytes[4] != 0x10 && bytes[4] != 0x11) {
749 /* not a Logic Control device - no response required */
753 // handle host connection query
754 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
756 if (bytes.size() != 18) {
757 cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
761 // build and send host connection reply
763 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
764 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
769 Surface::host_connection_confirmation (const MidiByteArray & bytes)
771 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
773 // decode host connection confirmation
774 if (bytes.size() != 14) {
776 os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
777 throw MackieControlException (os.str());
780 // send version request
781 return MidiByteArray (2, 0x13, 0x00);
785 Surface::turn_it_on ()
793 _mcp.device_ready ();
795 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
799 update_view_mode_display ();
801 if (_mcp.device_info ().has_global_controls ()) {
802 _mcp.update_global_button (Button::Read, _mcp.metering_active ());
807 Surface::write_sysex (const MidiByteArray & mba)
814 buf << sysex_hdr() << mba << MIDI::eox;
819 Surface::write_sysex (MIDI::byte msg)
822 buf << sysex_hdr() << msg << MIDI::eox;
827 Surface::n_strips (bool with_locked_strips) const
829 if (with_locked_strips) {
830 return strips.size();
835 for (Strips::const_iterator it = strips.begin(); it != strips.end(); ++it) {
836 if (!(*it)->locked()) {
844 Surface::nth_strip (uint32_t n) const
846 if (n > n_strips()) {
855 if (_mcp.device_info().has_timecode_display ()) {
856 display_timecode (string (10, '0'), string (10, ' '));
859 if (_mcp.device_info().has_two_character_display()) {
860 show_two_char_display (string (2, '0'), string (2, ' '));
863 if (_mcp.device_info().has_master_fader () && _master_fader) {
864 _port->write (_master_fader->zero ());
868 for (Strips::iterator it = strips.begin(); it != strips.end(); ++it) {
876 Surface::zero_controls ()
878 if (!_mcp.device_info().has_global_controls()) {
882 // turn off global buttons and leds
884 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
885 Control & control = **it;
886 if (!control.group().is_strip()) {
887 _port->write (control.zero());
891 // and the led ring for the master strip
894 _last_master_gain_written = 0.0f;
898 Surface::periodic (uint64_t now_usecs)
900 master_gain_changed();
901 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
902 (*s)->periodic (now_usecs);
907 Surface::redisplay (ARDOUR::microseconds_t now)
909 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
910 (*s)->redisplay (now);
915 Surface::write (const MidiByteArray& data)
920 DEBUG_TRACE (DEBUG::MackieControl, "surface not active, write ignored\n");
925 Surface::map_routes (const vector<boost::shared_ptr<Route> >& routes)
927 vector<boost::shared_ptr<Route> >::const_iterator r;
928 Strips::iterator s = strips.begin();
930 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mapping %1 routes\n", routes.size()));
932 for (r = routes.begin(); r != routes.end() && s != strips.end(); ++s) {
934 /* don't try to assign routes to a locked strip. it won't
935 use it anyway, but if we do, then we get out of sync
936 with the proposed mapping.
939 if (!(*s)->locked()) {
940 (*s)->set_route (*r);
945 for (; s != strips.end(); ++s) {
946 (*s)->set_route (boost::shared_ptr<Route>());
953 translate_seven_segment (char achar)
955 achar = toupper (achar);
957 if (achar >= 0x40 && achar <= 0x60) {
959 } else if (achar >= 0x21 && achar <= 0x3f) {
967 Surface::show_two_char_display (const std::string & msg, const std::string & dots)
969 if (_stype != mcu || !_mcp.device_info().has_two_character_display() || msg.length() != 2 || dots.length() != 2) {
973 MidiByteArray right (3, 0xb0, 0x4b, 0x00);
974 MidiByteArray left (3, 0xb0, 0x4a, 0x00);
976 right[2] = translate_seven_segment (msg[0]) + (dots[0] == '.' ? 0x40 : 0x00);
977 left[2] = translate_seven_segment (msg[1]) + (dots[1] == '.' ? 0x40 : 0x00);
979 _port->write (right);
984 Surface::show_two_char_display (unsigned int value, const std::string & /*dots*/)
987 os << setfill('0') << setw(2) << value % 100;
988 show_two_char_display (os.str());
992 Surface::display_timecode (const std::string & timecode, const std::string & last_timecode)
994 if (!_active || !_mcp.device_info().has_timecode_display()) {
997 // if there's no change, send nothing, not even sysex header
998 if (timecode == last_timecode) return;
1000 // length sanity checking
1001 string local_timecode = timecode;
1003 // truncate to 10 characters
1004 if (local_timecode.length() > 10) {
1005 local_timecode = local_timecode.substr (0, 10);
1008 // pad to 10 characters
1009 while (local_timecode.length() < 10) {
1010 local_timecode += " ";
1013 // translate characters.
1014 // Only the characters that actually changed are sent.
1015 int position = 0x3f;
1017 for (i = local_timecode.length () - 1; i >= 0; i--) {
1019 if (local_timecode[i] == last_timecode[i]) {
1022 MidiByteArray retval (2, 0xb0, position);
1023 retval << translate_seven_segment (local_timecode[i]);
1024 _port->write (retval);
1029 Surface::update_flip_mode_display ()
1031 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1032 (*s)->potmode_changed (true);
1037 Surface::update_potmode ()
1039 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
1040 (*s)->potmode_changed (false);
1045 Surface::update_view_mode_display ()
1054 switch (_mcp.view_mode()) {
1055 case MackieControlProtocol::Mixer:
1056 show_two_char_display ("Mx");
1058 text = _("Mixer View");
1060 case MackieControlProtocol::AudioTracks:
1061 show_two_char_display ("AT");
1062 id = Button::AudioTracks;
1063 text = _("Audio Tracks");
1065 case MackieControlProtocol::MidiTracks:
1066 show_two_char_display ("MT");
1067 id = Button::MidiTracks;
1068 text = _("MIDI Tracks");
1070 case MackieControlProtocol::Plugins:
1071 show_two_char_display ("PL");
1072 id = Button::Plugin;
1073 text = _("Plugins");
1075 case MackieControlProtocol::Busses:
1076 show_two_char_display ("BS");
1077 id = Button::Busses;
1080 case MackieControlProtocol::Auxes:
1081 show_two_char_display ("AB");
1085 case MackieControlProtocol::Selected:
1086 show_two_char_display ("SE");
1088 text = _("Selected Routes");
1094 vector<int> view_mode_buttons;
1095 view_mode_buttons.push_back (Button::View);
1096 view_mode_buttons.push_back (Button::Busses);
1097 view_mode_buttons.push_back (Button::Plugin);
1098 view_mode_buttons.push_back (Button::AudioTracks);
1099 view_mode_buttons.push_back (Button::MidiTracks);
1100 view_mode_buttons.push_back (Button::Aux);
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 (!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::notify_metering_state_changed()
1171 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1172 (*s)->notify_metering_state_changed ();
1180 /* reset msg for Mackie Control */
1191 Surface::toggle_backlight ()
1194 int onoff = random() %2;
1196 msg << sysex_hdr ();
1198 msg << (onoff ? 0x1 : 0x0);
1205 Surface::recalibrate_faders ()
1209 msg << sysex_hdr ();
1218 Surface::set_touch_sensitivity (int sensitivity)
1220 /* NOTE: assumed called from GUI code, hence sleep() */
1222 /* sensitivity already clamped by caller */
1227 msg << sysex_hdr ();
1229 msg << 0xff; /* overwritten for each fader below */
1230 msg << (sensitivity & 0x7f);
1233 for (int fader = 0; fader < 9; ++fader) {
1241 Surface::hui_heartbeat ()
1247 MidiByteArray msg (3, MIDI::on, 0x0, 0x0);
1252 Surface::connected ()
1254 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 now connected, trying to ping device...\n", _name));
1258 if (_mcp.device_info().no_handshake()) {
1264 Surface::display_line (string const& msg, int line_num)
1266 MidiByteArray midi_msg;
1267 midi_msg << sysex_hdr ();
1269 midi_msg << (line_num ? 0x38 : 0x0); /* offsets into char array
1271 * correspond to line
1276 midi_msg.insert (midi_msg.end(), 55, ' ');
1280 /* ascii data to display. @param msg is UTF-8 which is not legal. */
1281 string ascii = Glib::convert_with_fallback (msg, "UTF-8", "ISO-8859-1", "_");
1282 string::size_type len = ascii.length();
1285 midi_msg << ascii.substr (0, 55);
1289 for (string::size_type i = len; i < 55; ++i) {
1295 midi_msg << MIDI::eox;
1300 /** display @param msg on the 55x2 screen for @param msecs milliseconds
1302 * @param msg is assumed to be UTF-8 encoded, and will be converted
1303 * to ASCII with an underscore as fallback character before being
1304 * sent to the device.
1307 Surface::display_message_for (string const& msg, uint64_t msecs)
1309 string::size_type newline;
1311 if ((newline = msg.find ('\n')) == string::npos) {
1313 _port->write (display_line (msg, 0));
1314 _port->write (display_line (string(), 1));
1316 } else if (newline == 0) {
1318 _port->write (display_line (string(), 0));
1319 _port->write (display_line (msg.substr (1), 1));
1323 string first_line = msg.substr (0, newline-1);
1324 string second_line = msg.substr (newline+1);
1326 _port->write (display_line (first_line, 0));
1327 _port->write (display_line (second_line.substr (0, second_line.find_first_of ('\n')), 1));
1330 for (Strips::const_iterator s = strips.begin(); s != strips.end(); ++s) {
1331 (*s)->block_screen_display_for (msecs);