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;
44 // The MCU sysex header
45 MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 );
47 // The MCU extender sysex header
48 MidiByteArray mackie_sysex_hdr_xt ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11 );
50 MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t port_type )
51 : SurfacePort( port, number )
53 , _port_type( port_type )
55 , _initialising( true )
57 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
60 MackiePort::~MackiePort()
62 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
64 DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
67 int MackiePort::strips() const
69 if ( _port_type == mcu )
73 // BCF2000 only has 8 faders, so reserve one for master
74 case bcf2000: return 7;
75 case mackie: return 8;
78 throw MackieControlException( "MackiePort::strips: don't know what emulation we're using" );
83 // must be an extender, ie no master fader
88 // should really be in MackiePort
89 void MackiePort::open()
91 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this));
93 port().input()->sysex.connect (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3));
95 // make sure the device is connected
99 void MackiePort::close()
101 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n");
103 // disconnect signals
104 any_connection.disconnect();
105 sysex_connection.disconnect();
107 // TODO emit a "closing" signal?
110 const MidiByteArray & MackiePort::sysex_hdr() const
112 switch ( _port_type )
114 case mcu: return mackie_sysex_hdr;
115 case ext: return mackie_sysex_hdr_xt;
117 cout << "MackiePort::sysex_hdr _port_type not known" << endl;
118 return mackie_sysex_hdr;
121 MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
124 back_insert_iterator<MidiByteArray> back ( l );
125 copy( begin, end, back );
127 MidiByteArray retval;
129 // this is how to calculate the response to the challenge.
130 // from the Logic docs.
131 retval << ( 0x7f & ( l[0] + ( l[1] ^ 0xa ) - l[3] ) );
132 retval << ( 0x7f & ( ( l[2] >> l[3] ) ^ ( l[0] + l[3] ) ) );
133 retval << ( 0x7f & ( (l[3] - ( l[2] << 2 )) ^ ( l[0] | l[1] ) ) );
134 retval << ( 0x7f & ( l[1] - l[2] + ( 0xf0 ^ ( l[3] << 4 ) ) ) );
139 // not used right now
140 MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
142 // handle host connection query
143 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
145 if ( bytes.size() != 18 )
147 finalise_init( false );
149 os << "expecting 18 bytes, read " << bytes << " from " << port().name();
150 throw MackieControlException( os.str() );
153 // build and send host connection reply
154 MidiByteArray response;
156 copy( bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter( response ) );
157 response << calculate_challenge_response( bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4 );
161 // not used right now
162 MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
164 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
166 // decode host connection confirmation
167 if ( bytes.size() != 14 )
169 finalise_init( false );
171 os << "expecting 14 bytes, read " << bytes << " from " << port().name();
172 throw MackieControlException( os.str() );
175 // send version request
176 return MidiByteArray( 2, 0x13, 0x00 );
179 void MackiePort::probe_emulation (const MidiByteArray &)
182 cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
184 MidiByteArray version_string;
185 for ( int i = 6; i < 11; ++i ) version_string << bytes[i];
186 cout << "version_string: " << version_string << endl;
189 // TODO investigate using serial number. Also, possibly size of bytes might
190 // give an indication. Also, apparently MCU sends non-documented messages
194 //cout << "MackiePort::probe_emulation out of sequence." << endl;
198 finalise_init( true );
201 void MackiePort::init()
203 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init\n");
206 _initialising = true;
208 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
210 // emit pre-init signal
213 // kick off initialisation. See docs in header file for init()
215 // bypass the init sequence because sometimes the first
216 // message doesn't get to the unit, and there's no way
217 // to do a timed lock in Glib.
218 //write_sysex ( MidiByteArray ( 2, 0x13, 0x00 ) );
220 finalise_init( true );
223 void MackiePort::finalise_init( bool yn )
225 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
227 bool emulation_ok = false;
229 // probing doesn't work very well, so just use a config variable
230 // to set the emulation mode
231 // TODO This might have to be specified on a per-port basis
232 // in the config file
233 // if an mcu and a bcf are needed to work as one surface
234 if ( _emulation == none )
236 // TODO same as code in mackie_control_protocol.cc
237 if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
239 _emulation = bcf2000;
242 else if ( ARDOUR::Config->get_mackie_emulation() == "mcu" )
249 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
250 emulation_ok = false;
254 yn = yn && emulation_ok;
256 SurfacePort::active( yn );
261 // start handling messages from controls
265 _initialising = false;
269 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
272 void MackiePort::connect_any()
274 if (!any_connection.connected()) {
275 port().input()->any.connect (any_connection, boost::bind (&MackiePort::handle_midi_any, this, _1, _2, _3));
279 bool MackiePort::wait_for_init()
281 Glib::Mutex::Lock lock( init_mutex );
282 while (_initialising) {
283 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
284 init_cond.wait( init_mutex );
285 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
287 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
288 return SurfacePort::active();
291 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
293 MidiByteArray bytes( count, raw_bytes );
294 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
299 // not used right now
300 write_sysex (host_connection_query (bytes));
303 // not used right now
304 write_sysex (host_connection_confirmation (bytes));
308 cout << "host connection error" << bytes << endl;
311 probe_emulation (bytes);
314 cout << "unknown sysex: " << bytes << endl;
318 Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
320 // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
321 // Reason being that this method is called for every single incoming
322 // midi event, and it needs to be as efficient as possible.
324 Control * control = 0;
325 MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
329 case MackieMidiBuilder::midi_fader_id:
331 int midi_id = bytes[0] & 0x0f;
332 control = _mcp.surface().faders[midi_id];
335 MidiByteArray mba( count, bytes );
337 os << "control for fader" << bytes << " id " << midi_id << " is null";
338 throw MackieControlException( os.str() );
344 case MackieMidiBuilder::midi_button_id:
345 control = _mcp.surface().buttons[bytes[1]];
348 MidiByteArray mba( count, bytes );
350 os << "control for button " << bytes << " is null";
351 throw MackieControlException( os.str() );
355 // pot (jog wheel, external control)
356 case MackieMidiBuilder::midi_pot_id:
357 control = _mcp.surface().pots[bytes[1]];
360 MidiByteArray mba( count, bytes );
362 os << "control for rotary " << mba << " is null";
363 throw MackieControlException( os.str() );
368 MidiByteArray mba( count, bytes );
370 os << "Cannot find control for " << bytes;
371 throw MackieControlException( os.str() );
376 bool MackiePort::handle_control_timeout_event ( Control * control )
378 // empty control_state
379 ControlState control_state;
380 control->in_use( false );
381 control_event( *this, *control, control_state );
383 // only call this method once from the timer
387 // converts midi messages into control_event signals
388 // it might be worth combining this with lookup_control
389 // because they have similar logic flows.
390 void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
392 MidiByteArray bytes( count, raw_bytes );
393 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_any %1\n", bytes));
397 // ignore sysex messages
398 if ( raw_bytes[0] == MIDI::sysex ) return;
403 MidiByteArray mba( count, raw_bytes );
404 os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
405 throw MackieControlException( os.str() );
408 Control & control = lookup_control( raw_bytes, count );
409 control.in_use( true );
411 // This handles incoming bytes. Outgoing bytes
412 // are sent by the signal handlers.
413 switch (control.type()) {
415 case Control::type_fader:
417 // only the top-order 10 bits out of 14 are used
418 int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
420 // in_use is set by the MackieControlProtocol::handle_strip_button
422 // relies on implicit ControlState constructor
423 control_event( *this, control, float(midi_pos) / float(0x3ff) );
428 case Control::type_button:
430 ControlState control_state( raw_bytes[2] == 0x7f ? press : release );
431 control.in_use( control_state.button_state == press );
432 control_event( *this, control, control_state );
437 // pot (jog wheel, external control)
438 case Control::type_pot:
442 // bytes[2] & 0b01000000 (0x40) give sign
443 state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1;
444 // bytes[2] & 0b00111111 (0x3f) gives delta
445 state.ticks = ( raw_bytes[2] & 0x3f);
446 state.delta = float( state.ticks ) / float( 0x3f );
449 Pots only emit events when they move, not when they
450 stop moving. So to get a stop event, we need to use a timeout.
452 // this is set to false ...
453 control.in_use( true );
455 // ... by this timeout
457 // first disconnect any previous timeouts
458 control.in_use_connection.disconnect();
460 // now connect a new timeout to call handle_control_timeout_event
461 // XXX should this use the GUI event loop (default) or the
462 // MIDI UI event loop ?
464 sigc::slot<bool> timeout_slot = sigc::bind
465 (sigc::mem_fun( *this, &MackiePort::handle_control_timeout_event), &control);
467 control.in_use_connection = Glib::signal_timeout().connect (timeout_slot , control.in_use_timeout());
469 // emit the control event
470 control_event( *this, control, state );
474 cerr << "Do not understand control type " << control;
478 catch( MackieControlException & e ) {
479 MidiByteArray bytes( count, raw_bytes );
480 cout << bytes << ' ' << e.what() << endl;
483 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes));