7 #include "midi++/port.h"
8 #include "midi++/manager.h"
10 #include "ardour/debug.h"
11 #include "ardour/route.h"
12 #include "ardour/panner.h"
13 #include "ardour/panner_shell.h"
14 #include "ardour/rc_configuration.h"
16 #include "control_group.h"
17 #include "surface_port.h"
20 #include "mackie_control_protocol.h"
21 #include "mackie_jog_wheel.h"
35 using namespace Mackie;
38 using ARDOUR::Pannable;
39 using ARDOUR::PannerShell;
41 // The MCU sysex header.4th byte Will be overwritten
42 // when we get an incoming sysex that identifies
44 static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x14);
46 // The MCU extender sysex header.4th byte Will be overwritten
47 // when we get an incoming sysex that identifies
49 static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15);
51 static MidiByteArray empty_midi_byte_array;
53 static GlobalControlDefinition mackie_global_controls[] = {
54 { "jog", 0x3c, Jog::factory, "none" },
55 { "external", 0x2e, Pot::factory, "none" },
56 { "io", 0x28, Button::factory, "assignment" },
57 { "sends", 0x29, Button::factory, "assignment" },
58 { "pan", 0x2a, Button::factory, "assignment" },
59 { "plugin", 0x2b, Button::factory, "assignment" },
60 { "eq", 0x2c, Button::factory, "assignment" },
61 { "dyn", 0x2d, Button::factory, "assignment" },
62 { "left", 0x2e, Button::factory, "bank" },
63 { "right", 0x2f, Button::factory, "bank" },
64 { "channel_left", 0x30, Button::factory, "bank" },
65 { "channel_right", 0x31, Button::factory, "bank" },
66 { "flip", 0x32, Button::factory, "none" },
67 { "edit", 0x33, Button::factory, "none" },
68 { "name_value", 0x34, Button::factory, "display" },
69 { "timecode_beats", 0x35, Button::factory, "display" },
70 { "F1", Button::F1, Button::factory, "none" },
71 { "F2", Button::F2, Button::factory, "none" },
72 { "F3", Button::F3, Button::factory, "none" },
73 { "F4", Button::F4, Button::factory, "none" },
74 { "F5", Button::F5, Button::factory, "none" },
75 { "F6", Button::F6, Button::factory, "none" },
76 { "F7", Button::F7, Button::factory, "none" },
77 { "F8", Button::F8, Button::factory, "none" },
78 { "F9", Button::F9, Button::factory, "none" },
79 { "F10", Button::F10, Button::factory, "none" },
80 { "F11", Button::F11, Button::factory, "none" },
81 { "F12", Button::F12, Button::factory, "none" },
82 { "F13", Button::F13, Button::factory, "none" },
83 { "F14", Button::F14, Button::factory, "none" },
84 { "F15", Button::F15, Button::factory, "none" },
85 { "F16", Button::F16, Button::factory, "none" },
86 { "shift", 0x46, Button::factory, "modifiers" },
87 { "option", 0x47, Button::factory, "modifiers" },
88 { "control", 0x48, Button::factory, "modifiers" },
89 { "cmd_alt", 0x49, Button::factory, "modifiers" },
90 { "on", 0x4a, Button::factory, "automation" },
91 { "rec_ready", 0x4b, Button::factory, "automation" },
92 { "undo", 0x4c, Button::factory, "functions" },
93 { "save", Button::Save, Button::factory, "automation" },
94 { "touch", Button::Touch, Button::factory, "automation" },
95 { "redo", Button::Redo, Button::factory, "functions" },
96 { "marker", Button::Marker, Button::factory, "functions" },
97 { "enter", Button::Enter, Button::factory, "functions" },
98 { "cancel", Button::Cancel, Button::factory, "functions" },
99 { "mixer", Button::Mixer, Button::factory, "functions" },
100 { "frm_left", 0x54, Button::factory, "transport" },
101 { "frm_right", 0x55, Button::factory, "transport" },
102 { "loop", Button::Loop, Button::factory, "transport" },
103 { "punch_in", 0x57, Button::factory, "transport" },
104 { "punch_out", 0x58, Button::factory, "transport" },
105 { "home", Button::Home, Button::factory, "transport" },
106 { "end", Button::End, Button::factory, "transport" },
107 { "rewind", Button::Rewind, Button::factory, "transport" },
108 { "ffwd", Button::Ffwd, Button::factory, "transport" },
109 { "stop", Button::Stop, Button::factory, "transport" },
110 { "play", Button::Play, Button::factory, "transport" },
111 { "record", Button::Record, Button::factory, "transport" },
112 { "cursor_up", Button::CursorUp, Button::factory, "cursor" },
113 { "cursor_down", Button::CursorDown, Button::factory, "cursor" },
114 { "cursor_left", Button::CursorLeft, Button::factory, "cursor" },
115 { "cursor_right", Button::CursorRight, Button::factory, "cursor" },
116 { "zoom", Button::Zoom, Button::factory, "none" },
117 { "scrub", Button::Scrub, Button::factory, "none" },
118 { "user_a", Button::UserA, Button::factory, "user" },
119 { "user_b", Button::UserB, Button::factory, "user" },
120 { "fader_touch", 0x70, Led::factory, "master" },
121 { "timecode", 0x71, Led::factory, "none" },
122 { "beats", 0x72, Led::factory, "none" },
123 { "solo", 0x73, Led::factory, "none" },
124 { "relay_click", 0x73, Led::factory, "none" },
125 { "", 0, Button::factory, "" }
128 Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
132 , _name (device_name)
137 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init\n");
139 _port = new SurfacePort (*this);
141 if (_mcp.device_info().has_global_controls()) {
145 if (_mcp.device_info().has_jog_wheel()) {
146 _jog_wheel = new Mackie::JogWheel (_mcp);
149 uint32_t n = _mcp.device_info().strip_cnt();
155 connect_to_signals ();
159 MidiByteArray wakeup (7, MIDI::sysex, 0x00, 0x00, 0x66, 0x14, 0x00, MIDI::eox);
160 _port->write (wakeup);
161 wakeup[4] = 0x15; /* wakup Mackie XT */
162 _port->write (wakeup);
163 wakeup[4] = 0x10; /* wakupe Logic Control */
164 _port->write (wakeup);
165 wakeup[4] = 0x11; /* wakeup Logic Control XT */
166 _port->write (wakeup);
168 DEBUG_TRACE (DEBUG::MackieControl, "Surface::init finish\n");
173 DEBUG_TRACE (DEBUG::MackieControl, "Surface: destructor\n");
179 // Reset (reboot into offline mode)
180 // _write_sysex (0x63);
183 for (Groups::iterator it = groups.begin(); it != groups.end(); ++it) {
188 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
197 Surface::sysex_hdr() const
200 case mcu: return mackie_sysex_hdr;
201 case ext: return mackie_sysex_hdr_xt;
203 cout << "SurfacePort::sysex_hdr _port_type not known" << endl;
204 return mackie_sysex_hdr;
208 Surface::init_controls()
212 groups["assignment"] = new Group ("assignment");
213 groups["automation"] = new Group ("automation");
214 groups["bank"] = new Group ("bank");
215 groups["cursor"] = new Group ("cursor");
216 groups["display"] = new Group ("display");
217 groups["functions"] = new Group ("functions");
218 groups["modifiers"] = new Group ("modifiers");
219 groups["none"] = new Group ("none");
220 groups["transport"] = new Group ("transport");
221 groups["user"] = new Group ("user");
222 groups["master"] = new Group ("master");
224 for (uint32_t n = 0; mackie_global_controls[n].name[0]; ++n) {
225 group = groups[mackie_global_controls[n].group_name];
226 Control* control = mackie_global_controls[n].factory (*this, mackie_global_controls[n].id, mackie_global_controls[n].name, *group);
227 controls_by_name[mackie_global_controls[n].name] = control;
228 group->add (*control);
232 static StripControlDefinition mackie_strip_controls[] = {
233 { "gain", 0, Fader::factory, },
234 { "vpot", Pot::base_id, Pot::factory, },
235 { "recenable", Button::recenable_base_id, Button::factory, },
236 { "solo", Button::solo_base_id, Button::factory, },
237 { "mute", Button::mute_base_id, Button::factory, },
238 { "select", Button::select_base_id, Button::factory, },
239 { "vselect", Button::vselect_base_id, Button::factory, },
240 { "fader_touch", Button::fader_touch_base_id, Button::factory, },
241 { "meter", 0, Meter::factory, },
242 { "", 0, Button::factory, }
246 Surface::init_strips (uint32_t n)
248 for (uint32_t i = 0; i < n; ++i) {
252 snprintf (name, sizeof (name), "strip_%d", (8* _number) + i);
254 Strip* strip = new Strip (*this, name, i, mackie_strip_controls);
256 groups[name] = strip;
257 strips.push_back (strip);
262 Surface::scaled_delta (float delta, float current_speed)
264 /* XXX needs work before use */
265 return (std::pow (float(delta + 1), 2) + current_speed) / 100.0;
269 Surface::display_bank_start (uint32_t current_bank)
271 if (current_bank == 0) {
272 // send Ar. to 2-char display on the master
273 _port->write (two_char_display ("Ar", ".."));
275 // write the current first remote_id to the 2-char display
276 _port->write (two_char_display (current_bank));
281 Surface::blank_jog_ring ()
283 Control* control = controls_by_name["jog"];
286 Pot* pot = dynamic_cast<Pot*> (control);
288 _port->write (pot->set_onoff (false));
294 Surface::has_timecode_display () const
300 Surface::scrub_scaling_factor () const
306 Surface::connect_to_signals ()
311 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 connecting to signals on port %2\n",
312 number(), _port->input_port().name()));
314 MIDI::Parser* p = _port->input_port().parser();
317 p->sysex.connect_same_thread (*this, boost::bind (&Surface::handle_midi_sysex, this, _1, _2, _3));
318 /* V-Pot messages are Controller */
319 p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2));
320 /* Button messages are NoteOn */
321 p->note_on.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2));
322 /* Fader messages are Pitchbend */
323 p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 0U));
324 p->channel_pitchbend[1].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 1U));
325 p->channel_pitchbend[2].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 2U));
326 p->channel_pitchbend[3].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 3U));
327 p->channel_pitchbend[4].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 4U));
328 p->channel_pitchbend[5].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 5U));
329 p->channel_pitchbend[6].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 6U));
330 p->channel_pitchbend[7].connect_same_thread (*this, boost::bind (&Surface::handle_midi_pitchbend_message, this, _1, _2, 7U));
337 Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id)
339 /* Pitchbend messages are fader messages. Nothing in the data we get
340 * from the MIDI::Parser conveys the fader ID, which was given by the
341 * channel ID in the status byte.
343 * Instead, we have used bind() to supply the fader-within-strip ID
344 * when we connected to the per-channel pitchbend events.
347 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi pitchbend on port %3, fader = %1 value = %2\n",
348 fader_id, pb, _number));
350 Fader* fader = faders[fader_id];
353 Strip* strip = dynamic_cast<Strip*> (&fader->group());
355 float midi_pos = pb >> 4; // only the top 10 bytes are used
356 strip->handle_fader (*fader, midi_pos/1023.0);
361 DEBUG_TRACE (DEBUG::MackieControl, "fader not found\n");
366 Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
368 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::handle_note_on %1 = %2\n", (int) ev->note_number, (int) ev->velocity));
370 Button* button = buttons[ev->note_number];
373 Strip* strip = dynamic_cast<Strip*> (&button->group());
376 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 button %2 pressed ? %3\n",
377 strip->index(), button->name(), (ev->velocity == 0x7f)));
378 strip->handle_button (*button, ev->velocity == 0x7f ? press : release);
381 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("global button %1\n", button->id()));
382 _mcp.handle_button_event (*this, *button, ev->velocity == 0x7f ? press : release);
385 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("no button found for %1\n", ev->note_number));
390 Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev)
392 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::handle_midi_controller %1 = %2\n", (int) ev->controller_number, (int) ev->value));
394 Pot* pot = pots[ev->controller_number];
396 if (!pot && ev->controller_number == Jog::base_id) {
397 pot = dynamic_cast<Pot*> (controls_by_name["jog"]);
403 // bit 6 gives the sign
404 float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
405 // bits 0..5 give the velocity. we interpret this as "ticks
406 // moved before this message was sent"
407 float ticks = (ev->value & 0x3f);
409 /* euphonix and perhaps other devices send zero
410 when they mean 1, we think.
414 float delta = sign * (ticks / (float) 0x3f);
416 Strip* strip = dynamic_cast<Strip*> (&pot->group());
419 strip->handle_pot (*pot, delta);
421 JogWheel* wheel = dynamic_cast<JogWheel*> (pot);
423 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", state.ticks));
424 wheel->jog_event (*_port, *pot, delta);
426 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("External controller moved %1\n", state.ticks));
427 cout << "external controller" << delta << endl;
431 DEBUG_TRACE (DEBUG::MackieControl, "pot not found\n");
436 Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
438 MidiByteArray bytes (count, raw_bytes);
441 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
443 /* always save the device type ID so that our outgoing sysex messages
448 mackie_sysex_hdr[3] = bytes[4];
450 mackie_sysex_hdr_xt[3] = bytes[4];
456 LCP: Connection Challenge
458 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
459 write_sysex (host_connection_query (bytes));
465 case 0x03: /* LCP Connection Confirmation */
466 if (bytes[4] == 0x10 || bytes[4] == 0x11) {
467 write_sysex (host_connection_confirmation (bytes));
472 case 0x04: /* LCP: Confirmation Denied */
476 error << "MCP: unknown sysex: " << bytes << endmsg;
481 calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
484 back_insert_iterator<MidiByteArray> back (l);
485 copy (begin, end, back);
487 MidiByteArray retval;
489 // this is how to calculate the response to the challenge.
490 // from the Logic docs.
491 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
492 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
493 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
494 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
499 // not used right now
501 Surface::host_connection_query (MidiByteArray & bytes)
503 MidiByteArray response;
505 if (bytes[4] != 0x10 && bytes[4] != 0x11) {
506 /* not a Logic Control device - no response required */
510 // handle host connection query
511 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
513 if (bytes.size() != 18) {
514 cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
518 // build and send host connection reply
520 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
521 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
525 // not used right now
527 Surface::host_connection_confirmation (const MidiByteArray & bytes)
529 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
531 // decode host connection confirmation
532 if (bytes.size() != 14) {
534 os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
535 throw MackieControlException (os.str());
538 // send version request
539 return MidiByteArray (2, 0x13, 0x00);
543 Surface::handle_port_inactive (SurfacePort * port)
549 Surface::write_sysex (const MidiByteArray & mba)
556 buf << sysex_hdr() << mba << MIDI::eox;
561 Surface::write_sysex (MIDI::byte msg)
564 buf << sysex_hdr() << msg << MIDI::eox;
569 Surface::drop_routes ()
571 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
572 (*s)->set_route (boost::shared_ptr<Route>());
577 Surface::n_strips () const
579 return strips.size();
583 Surface::nth_strip (uint32_t n) const
585 if (n > n_strips()) {
594 // TODO turn off Timecode displays
597 for (Strips::iterator it = strips.begin(); it != strips.end(); ++it) {
598 _port->write ((*it)->zero());
601 // turn off global buttons and leds
602 // global buttons are only ever on mcu_port, so we don't have
603 // to figure out which port.
605 for (Controls::iterator it = controls.begin(); it != controls.end(); ++it) {
606 Control & control = **it;
607 if (!control.group().is_strip()) {
608 _port->write (control.zero());
612 // any hardware-specific stuff
613 // clear 2-char display
614 _port->write (two_char_display (" "));
616 // and the led ring for the master strip
621 Surface::periodic (uint64_t now_usecs)
623 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
624 (*s)->periodic (now_usecs);
630 Surface::write (const MidiByteArray& data)
636 Surface::jog_wheel_state_display (JogWheel::State state)
640 _port->write (two_char_display ("Zm"));
642 case JogWheel::scroll:
643 _port->write (two_char_display ("Sc"));
645 case JogWheel::scrub:
646 _port->write (two_char_display ("Sb"));
648 case JogWheel::shuttle:
649 _port->write (two_char_display ("Sh"));
651 case JogWheel::speed:
652 _port->write (two_char_display ("Sp"));
654 case JogWheel::select:
655 _port->write (two_char_display ("Se"));
661 Surface::map_routes (const vector<boost::shared_ptr<Route> >& routes)
663 vector<boost::shared_ptr<Route> >::const_iterator r;
666 for (s = strips.begin(); s != strips.end(); ++s) {
667 (*s)->set_route (boost::shared_ptr<Route>());
670 for (r = routes.begin(), s = strips.begin(); r != routes.end() && s != strips.end(); ++r, ++s) {
671 (*s)->set_route (*r);
675 static char translate_seven_segment (char achar)
677 achar = toupper (achar);
678 if (achar >= 0x40 && achar <= 0x60)
680 else if (achar >= 0x21 && achar <= 0x3f)
687 Surface::two_char_display (const std::string & msg, const std::string & dots)
690 return MidiByteArray();
693 if (msg.length() != 2) throw MackieControlException ("MackieMidiBuilder::two_char_display: msg must be exactly 2 characters");
694 if (dots.length() != 2) throw MackieControlException ("MackieMidiBuilder::two_char_display: dots must be exactly 2 characters");
696 MidiByteArray bytes (6, 0xb0, 0x4a, 0x00, 0xb0, 0x4b, 0x00);
698 // chars are understood by the surface in right-to-left order
699 // could also exchange the 0x4a and 0x4b, above
700 bytes[5] = translate_seven_segment (msg[0]) + (dots[0] == '.' ? 0x40 : 0x00);
701 bytes[2] = translate_seven_segment (msg[1]) + (dots[1] == '.' ? 0x40 : 0x00);
707 Surface::two_char_display (unsigned int value, const std::string & /*dots*/)
710 os << setfill('0') << setw(2) << value % 100;
711 return two_char_display (os.str());
715 Surface::display_timecode (const std::string & timecode, const std::string & timecode_last)
717 if (has_timecode_display()) {
718 _port->write (timecode_display (timecode, timecode_last));
723 Surface::timecode_display (const std::string & timecode, const std::string & last_timecode)
725 // if there's no change, send nothing, not even sysex header
726 if (timecode == last_timecode) return MidiByteArray();
728 // length sanity checking
729 string local_timecode = timecode;
731 // truncate to 10 characters
732 if (local_timecode.length() > 10) {
733 local_timecode = local_timecode.substr (0, 10);
736 // pad to 10 characters
737 while (local_timecode.length() < 10) {
738 local_timecode += " ";
741 // find the suffix of local_timecode that differs from last_timecode
742 std::pair<string::const_iterator,string::iterator> pp = mismatch (last_timecode.begin(), last_timecode.end(), local_timecode.begin());
744 MidiByteArray retval;
747 retval << sysex_hdr();
749 // code for timecode display
752 // translate characters. These are sent in reverse order of display
753 // hence the reverse iterators
754 string::reverse_iterator rend = reverse_iterator<string::iterator> (pp.second);
755 for (string::reverse_iterator it = local_timecode.rbegin(); it != rend; ++it) {
756 retval << translate_seven_segment (*it);
766 Surface::update_flip_mode_display ()
768 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
769 (*s)->flip_mode_changed (true);
774 Surface::update_view_mode_display ()
779 switch (_mcp.view_mode()) {
780 case MackieControlProtocol::Mixer:
781 _port->write (two_char_display ("Mx"));
782 button = buttons[Button::Pan];
784 case MackieControlProtocol::Dynamics:
785 _port->write (two_char_display ("Dy"));
786 button = buttons[Button::Dyn];
788 case MackieControlProtocol::EQ:
789 _port->write (two_char_display ("EQ"));
790 button = buttons[Button::Eq];
792 case MackieControlProtocol::Loop:
793 _port->write (two_char_display ("LP"));
794 button = buttons[Button::Loop];
796 case MackieControlProtocol::AudioTracks:
797 _port->write (two_char_display ("AT"));
799 case MackieControlProtocol::MidiTracks:
800 _port->write (two_char_display ("MT"));
802 case MackieControlProtocol::Busses:
803 _port->write (two_char_display ("Bs"));
805 case MackieControlProtocol::Sends:
806 _port->write (two_char_display ("Sn"));
807 button = buttons[Button::Sends];
809 case MackieControlProtocol::Plugins:
810 _port->write (two_char_display ("Pl"));
811 button = buttons[Button::Plugin];
816 _port->write (button->set_state (on));
820 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
821 _port->write ((*s)->display (1, text));
827 Surface::gui_selection_changed (ARDOUR::RouteNotificationListPtr routes)
829 for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) {
830 _port->write ((*s)->gui_selection_changed (routes));