2 Copyright (C) 2006,2007 John Anderson
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.
18 #include "mackie_port.h"
20 #include "mackie_control_exception.h"
21 #include "mackie_control_protocol.h"
22 #include "mackie_midi_builder.h"
26 #include <glibmm/main.h>
28 #include <boost/shared_array.hpp>
30 #include "midi++/types.h"
31 #include "midi++/port.h"
33 #include "ardour/debug.h"
34 #include "ardour/rc_configuration.h"
41 using namespace Mackie;
42 using namespace ARDOUR;
45 // The MCU sysex header
46 MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10);
48 // The MCU extender sysex header
49 MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11);
51 MackiePort::MackiePort (MackieControlProtocol & mcp, MIDI::Port & input_port, MIDI::Port & output_port, int number, port_type_t port_type)
52 : SurfacePort (input_port, output_port, number)
54 , _port_type (port_type)
56 , _initialising (true)
58 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
61 MackiePort::~MackiePort()
63 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
65 DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
68 int MackiePort::strips() const
70 if (_port_type == mcu)
74 // BCF2000 only has 8 faders, so reserve one for master
75 case bcf2000: return 7;
76 case mackie: return 8;
79 throw MackieControlException ("MackiePort::strips: don't know what emulation we're using");
84 // must be an extender, ie no master fader
89 // should really be in MackiePort
90 void MackiePort::open()
92 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
94 input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
96 // make sure the device is connected
100 void MackiePort::close()
102 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
104 // disconnect signals
105 any_connection.disconnect();
106 sysex_connection.disconnect();
108 // TODO emit a "closing" signal?
111 const MidiByteArray & MackiePort::sysex_hdr() const
115 case mcu: return mackie_sysex_hdr;
116 case ext: return mackie_sysex_hdr_xt;
118 cout << "MackiePort::sysex_hdr _port_type not known" << endl;
119 return mackie_sysex_hdr;
122 MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
125 back_insert_iterator<MidiByteArray> back (l);
126 copy (begin, end, back);
128 MidiByteArray retval;
130 // this is how to calculate the response to the challenge.
131 // from the Logic docs.
132 retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
133 retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
134 retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
135 retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
140 // not used right now
141 MidiByteArray MackiePort::host_connection_query (MidiByteArray & bytes)
143 // handle host connection query
144 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
146 if (bytes.size() != 18) {
147 finalise_init (false);
148 cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
152 // build and send host connection reply
153 MidiByteArray response;
155 copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
156 response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
160 // not used right now
161 MidiByteArray MackiePort::host_connection_confirmation (const MidiByteArray & bytes)
163 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
165 // decode host connection confirmation
166 if (bytes.size() != 14) {
167 finalise_init (false);
169 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
170 throw MackieControlException (os.str());
173 // send version request
174 return MidiByteArray (2, 0x13, 0x00);
177 void MackiePort::probe_emulation (const MidiByteArray &)
180 cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
182 MidiByteArray version_string;
183 for (int i = 6; i < 11; ++i) version_string << bytes[i];
184 cout << "version_string: " << version_string << endl;
187 // TODO investigate using serial number. Also, possibly size of bytes might
188 // give an indication. Also, apparently MCU sends non-documented messages
192 //cout << "MackiePort::probe_emulation out of sequence." << endl;
196 finalise_init (true);
199 void MackiePort::init()
201 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init\n");
204 _initialising = true;
206 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
208 // emit pre-init signal
211 // kick off initialisation. See docs in header file for init()
213 // bypass the init sequence because sometimes the first
214 // message doesn't get to the unit, and there's no way
215 // to do a timed lock in Glib.
216 //write_sysex (MidiByteArray (2, 0x13, 0x00));
218 finalise_init (true);
221 void MackiePort::finalise_init (bool yn)
223 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
225 bool emulation_ok = false;
227 // probing doesn't work very well, so just use a config variable
228 // to set the emulation mode
229 // TODO This might have to be specified on a per-port basis
230 // in the config file
231 // if an mcu and a bcf are needed to work as one surface
232 if (_emulation == none)
234 // TODO same as code in mackie_control_protocol.cc
235 if (ARDOUR::Config->get_mackie_emulation() == "bcf")
237 _emulation = bcf2000;
240 else if (ARDOUR::Config->get_mackie_emulation() == "mcu")
247 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
248 emulation_ok = false;
252 yn = yn && emulation_ok;
254 SurfacePort::active (yn);
259 // start handling messages from controls
263 _initialising = false;
267 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
270 void MackiePort::connect_any()
272 if (!any_connection.connected()) {
273 input_port().parser()->any.connect_same_thread (any_connection, boost::bind (&MackiePort::handle_midi_any, this, _1, _2, _3));
277 bool MackiePort::wait_for_init()
279 Glib::Mutex::Lock lock (init_mutex);
280 while (_initialising) {
281 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
282 init_cond.wait (init_mutex);
283 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
285 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
286 return SurfacePort::active();
289 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
291 MidiByteArray bytes (count, raw_bytes);
293 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
298 write_sysex (host_connection_query (bytes));
301 // not used right now
302 write_sysex (host_connection_confirmation (bytes));
306 cout << "host connection error" << bytes << endl;
309 probe_emulation (bytes);
312 cout << "unknown sysex: " << bytes << endl;
316 Control & MackiePort::lookup_control (MIDI::byte * bytes, size_t count)
318 // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
319 // Reason being that this method is called for every single incoming
320 // midi event, and it needs to be as efficient as possible.
322 Control * control = 0;
323 MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
327 case MackieMidiBuilder::midi_fader_id:
329 int midi_id = bytes[0] & 0x0f;
330 control = _mcp.surface().faders[midi_id];
333 MidiByteArray mba (count, bytes);
335 os << "Control for fader" << bytes << " id " << midi_id << " is null";
336 throw MackieControlException (os.str());
342 case MackieMidiBuilder::midi_button_id:
343 control = _mcp.surface().buttons[bytes[1]];
346 MidiByteArray mba (count, bytes);
348 os << "Control for button " << mba << " is null";
349 throw MackieControlException (os.str());
353 // pot (jog wheel, external control)
354 case MackieMidiBuilder::midi_pot_id:
355 control = _mcp.surface().pots[bytes[1]];
358 MidiByteArray mba (count, bytes);
360 os << "Control for rotary " << mba << " is null";
361 throw MackieControlException (os.str());
366 MidiByteArray mba (count, bytes);
368 os << "Cannot find control for " << mba;
369 throw MackieControlException (os.str());
374 // converts midi messages into control_event signals
375 // it might be worth combining this with lookup_control
376 // because they have similar logic flows.
377 void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
379 MidiByteArray bytes (count, raw_bytes);
380 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_any %1\n", bytes));
384 // ignore sysex messages
385 if (raw_bytes[0] == MIDI::sysex) return;
390 MidiByteArray mba (count, raw_bytes);
391 os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
392 throw MackieControlException (os.str());
395 Control & control = lookup_control (raw_bytes, count);
396 control.set_in_use (true);
398 // This handles incoming bytes. Outgoing bytes
399 // are sent by the signal handlers.
400 switch (control.type()) {
402 case Control::type_fader:
404 // only the top-order 10 bits out of 14 are used
405 int midi_pos = ( (raw_bytes[2] << 7) + raw_bytes[1]) >> 4;
407 // in_use is set by the MackieControlProtocol::handle_strip_button
409 // relies on implicit ControlState constructor
410 control_event (*this, control, float(midi_pos) / float(0x3ff));
415 case Control::type_button:
417 ControlState control_state (raw_bytes[2] == 0x7f ? press : release);
418 control.set_in_use (control_state.button_state == press);
419 control_event (*this, control, control_state);
424 // pot (jog wheel, external control)
425 case Control::type_pot:
429 // bytes[2] & 0b01000000 (0x40) give sign
430 state.sign = (raw_bytes[2] & 0x40) == 0 ? 1 : -1;
431 // bytes[2] & 0b00111111 (0x3f) gives delta
432 state.ticks = (raw_bytes[2] & 0x3f);
433 if (state.ticks == 0) {
434 /* euphonix and perhaps other devices send zero
435 when they mean 1, we think.
439 state.delta = float (state.ticks) / float (0x3f);
441 /* Pots only emit events when they move, not when they
442 stop moving. So to get a stop event, we need to use a timeout.
445 control.set_in_use (true);
446 add_in_use_timeout (control, &control);
448 // emit the control event
449 control_event (*this, control, state);
453 cerr << "Do not understand control type " << control;
457 catch (MackieControlException & e) {
458 MidiByteArray bytes (count, raw_bytes);
459 cout << bytes << ' ' << e.what() << endl;
462 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes));