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 <midi++/types.h>
29 #include <midi++/port.h>
30 #include <sigc++/sigc++.h>
31 #include <boost/shared_array.hpp>
32 #include <ardour/configuration.h>
39 using namespace Mackie;
41 // The MCU sysex header
42 MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 );
44 // The MCU extender sysex header
45 MidiByteArray mackie_sysex_hdr_xt ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11 );
47 MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t port_type )
48 : SurfacePort( port, number )
50 , _port_type( port_type )
52 , _initialising( true )
55 cout << "MackiePort::MackiePort" <<endl;
59 MackiePort::~MackiePort()
62 cout << "~MackiePort" << endl;
66 cout << "~MackiePort finished" << endl;
70 int MackiePort::strips() const
72 if ( _port_type == mcu )
76 // BCF2000 only has 8 faders, so reserve one for master
77 case bcf2000: return 7;
78 case mackie: return 8;
81 throw MackieControlException( "MackiePort::strips: don't know what emulation we're using" );
86 // must be an extender, ie no master fader
91 // should really be in MackiePort
92 void MackiePort::open()
95 cout << "MackiePort::open " << *this << endl;
97 _sysex = port().input()->sysex.connect( ( mem_fun (*this, &MackiePort::handle_midi_sysex) ) );
99 // make sure the device is connected
103 void MackiePort::close()
106 cout << "MackiePort::close" << endl;
109 // disconnect signals
113 // TODO emit a "closing" signal?
115 cout << "MackiePort::close finished" << endl;
119 const MidiByteArray & MackiePort::sysex_hdr() const
121 switch ( _port_type )
123 case mcu: return mackie_sysex_hdr;
124 case ext: return mackie_sysex_hdr_xt;
126 cout << "MackiePort::sysex_hdr _port_type not known" << endl;
127 return mackie_sysex_hdr;
130 MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
133 back_insert_iterator<MidiByteArray> back ( l );
134 copy( begin, end, back );
136 MidiByteArray retval;
138 // this is how to calculate the response to the challenge.
139 // from the Logic docs.
140 retval << ( 0x7f & ( l[0] + ( l[1] ^ 0xa ) - l[3] ) );
141 retval << ( 0x7f & ( ( l[2] >> l[3] ) ^ ( l[0] + l[3] ) ) );
142 retval << ( 0x7f & ( (l[3] - ( l[2] << 2 )) ^ ( l[0] | l[1] ) ) );
143 retval << ( 0x7f & ( l[1] - l[2] + ( 0xf0 ^ ( l[3] << 4 ) ) ) );
148 // not used right now
149 MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
151 // handle host connection query
153 cout << "host connection query: " << bytes << endl;
156 if ( bytes.size() != 18 )
158 finalise_init( false );
160 os << "expecting 18 bytes, read " << bytes << " from " << port().name();
161 throw MackieControlException( os.str() );
164 // build and send host connection reply
165 MidiByteArray response;
167 copy( bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter( response ) );
168 response << calculate_challenge_response( bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4 );
172 // not used right now
173 MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
176 cout << "host_connection_confirmation: " << bytes << endl;
179 // decode host connection confirmation
180 if ( bytes.size() != 14 )
182 finalise_init( false );
184 os << "expecting 14 bytes, read " << bytes << " from " << port().name();
185 throw MackieControlException( os.str() );
188 // send version request
189 return MidiByteArray( 2, 0x13, 0x00 );
192 void MackiePort::probe_emulation (const MidiByteArray &)
195 cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
197 MidiByteArray version_string;
198 for ( int i = 6; i < 11; ++i ) version_string << bytes[i];
199 cout << "version_string: " << version_string << endl;
202 // TODO investigate using serial number. Also, possibly size of bytes might
203 // give an indication. Also, apparently MCU sends non-documented messages
207 //cout << "MackiePort::probe_emulation out of sequence." << endl;
211 finalise_init( true );
214 void MackiePort::init()
217 cout << "MackiePort::init" << endl;
220 _initialising = true;
223 cout << "MackiePort::init lock acquired" << endl;
225 // emit pre-init signal
228 // kick off initialisation. See docs in header file for init()
230 // bypass the init sequence because sometimes the first
231 // message doesn't get to the unit, and there's no way
232 // to do a timed lock in Glib.
233 //write_sysex ( MidiByteArray ( 2, 0x13, 0x00 ) );
235 finalise_init( true );
238 void MackiePort::finalise_init( bool yn )
241 cout << "MackiePort::finalise_init" << endl;
243 bool emulation_ok = false;
245 // probing doesn't work very well, so just use a config variable
246 // to set the emulation mode
247 // TODO This might have to be specified on a per-port basis
248 // in the config file
249 // if an mcu and a bcf are needed to work as one surface
250 if ( _emulation == none )
252 // TODO same as code in mackie_control_protocol.cc
253 if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
255 _emulation = bcf2000;
258 else if ( ARDOUR::Config->get_mackie_emulation() == "mcu" )
265 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
266 emulation_ok = false;
270 yn = yn && emulation_ok;
272 SurfacePort::active( yn );
278 // start handling messages from controls
281 _initialising = false;
285 cout << "MackiePort::finalise_init lock released" << endl;
289 void MackiePort::connect_any()
292 Doesn't work because there isn't an == operator for slots
293 MIDI::Signal::slot_list_type slots = port().input()->any.slots();
295 if ( find( slots.begin(), slots.end(), mem_fun( *this, &MackiePort::handle_midi_any ) ) == slots.end() )
297 // TODO but this will break if midi tracing is turned on
298 if ( port().input()->any.empty() )
301 cout << "connect input parser " << port().input() << " to handle_midi_any" << endl;
303 _any = port().input()->any.connect( mem_fun( *this, &MackiePort::handle_midi_any ) );
305 cout << "input parser any connections: " << port().input()->any.size() << endl;
310 cout << "MackiePort::connect_any already connected" << endl;
314 bool MackiePort::wait_for_init()
316 Glib::Mutex::Lock lock( init_mutex );
317 while ( _initialising )
320 cout << "MackiePort::wait_for_active waiting" << endl;
322 init_cond.wait( init_mutex );
324 cout << "MackiePort::wait_for_active released" << endl;
328 cout << "MackiePort::wait_for_active returning" << endl;
330 return SurfacePort::active();
333 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
335 MidiByteArray bytes( count, raw_bytes );
337 cout << "handle_midi_sysex: " << bytes << endl;
342 // not used right now
343 write_sysex( host_connection_query( bytes ) );
346 // not used right now
347 write_sysex( host_connection_confirmation( bytes ) );
351 cout << "host connection error" << bytes << endl;
354 probe_emulation( bytes );
357 cout << "unknown sysex: " << bytes << endl;
361 Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
363 // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
364 // Reason being that this method is called for every single incoming
365 // midi event, and it needs to be as efficient as possible.
366 Control * control = 0;
367 MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
371 case MackieMidiBuilder::midi_fader_id:
373 int midi_id = bytes[0] & 0x0f;
374 control = _mcp.surface().faders[midi_id];
377 MidiByteArray mba( count, bytes );
379 os << "control for fader" << bytes << " id " << midi_id << " is null";
380 throw MackieControlException( os.str() );
386 case MackieMidiBuilder::midi_button_id:
387 control = _mcp.surface().buttons[bytes[1]];
390 MidiByteArray mba( count, bytes );
392 os << "control for button " << bytes << " is null";
393 throw MackieControlException( os.str() );
397 // pot (jog wheel, external control)
398 case MackieMidiBuilder::midi_pot_id:
399 control = _mcp.surface().pots[bytes[1]];
402 MidiByteArray mba( count, bytes );
404 os << "control for rotary " << mba << " is null";
405 throw MackieControlException( os.str() );
410 MidiByteArray mba( count, bytes );
412 os << "Cannot find control for " << bytes;
413 throw MackieControlException( os.str() );
418 bool MackiePort::handle_control_timeout_event ( Control * control )
420 // empty control_state
421 ControlState control_state;
422 control->in_use( false );
423 control_event( *this, *control, control_state );
425 // only call this method once from the timer
429 // converts midi messages into control_event signals
430 // it might be worth combining this with lookup_control
431 // because they have similar logic flows.
432 void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
435 MidiByteArray bytes( count, raw_bytes );
436 cout << "MackiePort::handle_midi_any " << bytes << endl;
440 // ignore sysex messages
441 if ( raw_bytes[0] == MIDI::sysex ) return;
447 MidiByteArray mba( count, raw_bytes );
448 os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
449 throw MackieControlException( os.str() );
452 Control & control = lookup_control( raw_bytes, count );
453 control.in_use( true );
455 // This handles incoming bytes. Outgoing bytes
456 // are sent by the signal handlers.
457 switch ( control.type() )
460 case Control::type_fader:
462 // only the top-order 10 bits out of 14 are used
463 int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
465 // in_use is set by the MackieControlProtocol::handle_strip_button
467 // relies on implicit ControlState constructor
468 control_event( *this, control, float(midi_pos) / float(0x3ff) );
473 case Control::type_button:
475 ControlState control_state( raw_bytes[2] == 0x7f ? press : release );
476 control.in_use( control_state.button_state == press );
477 control_event( *this, control, control_state );
482 // pot (jog wheel, external control)
483 case Control::type_pot:
487 // bytes[2] & 0b01000000 (0x40) give sign
488 state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1;
489 // bytes[2] & 0b00111111 (0x3f) gives delta
490 state.ticks = ( raw_bytes[2] & 0x3f);
491 state.delta = float( state.ticks ) / float( 0x3f );
494 Pots only emit events when they move, not when they
495 stop moving. So to get a stop event, we need to use a timeout.
497 // this is set to false ...
498 control.in_use( true );
500 // ... by this timeout
502 // first disconnect any previous timeouts
503 control.in_use_connection.disconnect();
505 // now connect a new timeout to call handle_control_timeout_event
506 sigc::slot<bool> timeout_slot = sigc::bind(
507 mem_fun( *this, &MackiePort::handle_control_timeout_event )
510 control.in_use_connection = Glib::signal_timeout().connect(
512 , control.in_use_timeout()
515 // emit the control event
516 control_event( *this, control, state );
520 cerr << "Do not understand control type " << control;
523 catch( MackieControlException & e )
525 MidiByteArray bytes( count, raw_bytes );
526 cout << bytes << ' ' << e.what() << endl;
529 cout << "finished MackiePort::handle_midi_any " << bytes << endl;