Use a timeout to reset faders' in_use flags when in BCF mode (ie with faders that...
[ardour2.git] / libs / surfaces / mackie / mackie_port.cc
blobbda1c2765d02c359566c9b636d4493cf2fafe462
1 /*
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"
23 #include "controls.h"
24 #include "surface.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"
36 #include "i18n.h"
38 #include <sstream>
40 using namespace std;
41 using namespace Mackie;
42 using namespace ARDOUR;
43 using namespace PBD;
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)
53 , _mcp( mcp )
54 , _port_type( port_type )
55 , _emulation( none )
56 , _initialising( true )
58 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
61 MackiePort::~MackiePort()
63 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
64 close();
65 DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
68 int MackiePort::strips() const
70 if ( _port_type == mcu )
72 switch ( _emulation )
74 // BCF2000 only has 8 faders, so reserve one for master
75 case bcf2000: return 7;
76 case mackie: return 8;
77 case none:
78 default:
79 throw MackieControlException( "MackiePort::strips: don't know what emulation we're using" );
82 else
84 // must be an extender, ie no master fader
85 return 8;
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
97 init();
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
113 switch ( _port_type )
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 )
124 MidiByteArray l;
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 ) ) ) );
137 return retval;
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 )
148 finalise_init( false );
149 ostringstream os;
150 os << "expecting 18 bytes, read " << bytes << " from " << input_port().name();
151 throw MackieControlException( os.str() );
154 // build and send host connection reply
155 MidiByteArray response;
156 response << 0x02;
157 copy( bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter( response ) );
158 response << calculate_challenge_response( bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4 );
159 return response;
162 // not used right now
163 MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
165 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
167 // decode host connection confirmation
168 if ( bytes.size() != 14 )
170 finalise_init( false );
171 ostringstream os;
172 os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
173 throw MackieControlException( os.str() );
176 // send version request
177 return MidiByteArray( 2, 0x13, 0x00 );
180 void MackiePort::probe_emulation (const MidiByteArray &)
182 #if 0
183 cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
185 MidiByteArray version_string;
186 for ( int i = 6; i < 11; ++i ) version_string << bytes[i];
187 cout << "version_string: " << version_string << endl;
188 #endif
190 // TODO investigate using serial number. Also, possibly size of bytes might
191 // give an indication. Also, apparently MCU sends non-documented messages
192 // sometimes.
193 if (!_initialising)
195 //cout << "MackiePort::probe_emulation out of sequence." << endl;
196 return;
199 finalise_init( true );
202 void MackiePort::init()
204 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init\n");
206 init_mutex.lock();
207 _initialising = true;
209 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n");
211 // emit pre-init signal
212 init_event();
214 // kick off initialisation. See docs in header file for init()
216 // bypass the init sequence because sometimes the first
217 // message doesn't get to the unit, and there's no way
218 // to do a timed lock in Glib.
219 //write_sysex ( MidiByteArray ( 2, 0x13, 0x00 ) );
221 finalise_init( true );
224 void MackiePort::finalise_init( bool yn )
226 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n");
228 bool emulation_ok = false;
230 // probing doesn't work very well, so just use a config variable
231 // to set the emulation mode
232 // TODO This might have to be specified on a per-port basis
233 // in the config file
234 // if an mcu and a bcf are needed to work as one surface
235 if ( _emulation == none )
237 // TODO same as code in mackie_control_protocol.cc
238 if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
240 _emulation = bcf2000;
241 emulation_ok = true;
243 else if ( ARDOUR::Config->get_mackie_emulation() == "mcu" )
245 _emulation = mackie;
246 emulation_ok = true;
248 else
250 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
251 emulation_ok = false;
255 yn = yn && emulation_ok;
257 SurfacePort::active( yn );
259 if (yn) {
260 active_event();
262 // start handling messages from controls
263 connect_any();
266 _initialising = false;
267 init_cond.signal();
268 init_mutex.unlock();
270 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n");
273 void MackiePort::connect_any()
275 if (!any_connection.connected()) {
276 input_port().parser()->any.connect_same_thread (any_connection, boost::bind (&MackiePort::handle_midi_any, this, _1, _2, _3));
280 bool MackiePort::wait_for_init()
282 Glib::Mutex::Lock lock( init_mutex );
283 while (_initialising) {
284 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n");
285 init_cond.wait( init_mutex );
286 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n");
288 DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n");
289 return SurfacePort::active();
292 void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
294 MidiByteArray bytes( count, raw_bytes );
295 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
297 switch( bytes[5] )
299 case 0x01:
300 // not used right now
301 write_sysex (host_connection_query (bytes));
302 break;
303 case 0x03:
304 // not used right now
305 write_sysex (host_connection_confirmation (bytes));
306 break;
307 case 0x04:
308 inactive_event ();
309 cout << "host connection error" << bytes << endl;
310 break;
311 case 0x14:
312 probe_emulation (bytes);
313 break;
314 default:
315 cout << "unknown sysex: " << bytes << endl;
319 Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
321 // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
322 // Reason being that this method is called for every single incoming
323 // midi event, and it needs to be as efficient as possible.
325 Control * control = 0;
326 MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
328 switch (midi_type) {
329 // fader
330 case MackieMidiBuilder::midi_fader_id:
332 int midi_id = bytes[0] & 0x0f;
333 control = _mcp.surface().faders[midi_id];
334 if ( control == 0 )
336 MidiByteArray mba( count, bytes );
337 ostringstream os;
338 os << "Control for fader" << bytes << " id " << midi_id << " is null";
339 throw MackieControlException( os.str() );
341 break;
344 // button
345 case MackieMidiBuilder::midi_button_id:
346 control = _mcp.surface().buttons[bytes[1]];
347 if ( control == 0 )
349 MidiByteArray mba( count, bytes );
350 ostringstream os;
351 os << "Control for button " << mba << " is null";
352 throw MackieControlException( os.str() );
354 break;
356 // pot (jog wheel, external control)
357 case MackieMidiBuilder::midi_pot_id:
358 control = _mcp.surface().pots[bytes[1]];
359 if ( control == 0 )
361 MidiByteArray mba( count, bytes );
362 ostringstream os;
363 os << "Control for rotary " << mba << " is null";
364 throw MackieControlException( os.str() );
366 break;
368 default:
369 MidiByteArray mba( count, bytes );
370 ostringstream os;
371 os << "Cannot find control for " << mba;
372 throw MackieControlException( os.str() );
374 return *control;
377 // converts midi messages into control_event signals
378 // it might be worth combining this with lookup_control
379 // because they have similar logic flows.
380 void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count )
382 MidiByteArray bytes( count, raw_bytes );
383 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_any %1\n", bytes));
387 // ignore sysex messages
388 if ( raw_bytes[0] == MIDI::sysex ) return;
390 // sanity checking
391 if (count != 3) {
392 ostringstream os;
393 MidiByteArray mba( count, raw_bytes );
394 os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
395 throw MackieControlException( os.str() );
398 Control & control = lookup_control( raw_bytes, count );
399 control.set_in_use (true);
401 // This handles incoming bytes. Outgoing bytes
402 // are sent by the signal handlers.
403 switch (control.type()) {
404 // fader
405 case Control::type_fader:
407 // only the top-order 10 bits out of 14 are used
408 int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
410 // in_use is set by the MackieControlProtocol::handle_strip_button
412 // relies on implicit ControlState constructor
413 control_event( *this, control, float(midi_pos) / float(0x3ff) );
415 break;
417 // button
418 case Control::type_button:
420 ControlState control_state( raw_bytes[2] == 0x7f ? press : release );
421 control.set_in_use (control_state.button_state == press);
422 control_event( *this, control, control_state );
424 break;
427 // pot (jog wheel, external control)
428 case Control::type_pot:
430 ControlState state;
432 // bytes[2] & 0b01000000 (0x40) give sign
433 state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1;
434 // bytes[2] & 0b00111111 (0x3f) gives delta
435 state.ticks = ( raw_bytes[2] & 0x3f);
436 if (state.ticks == 0) {
437 /* euphonix and perhaps other devices send zero
438 when they mean 1, we think.
440 state.ticks = 1;
442 state.delta = float( state.ticks ) / float( 0x3f );
444 /* Pots only emit events when they move, not when they
445 stop moving. So to get a stop event, we need to use a timeout.
448 control.set_in_use (true);
449 add_in_use_timeout (control, &control);
451 // emit the control event
452 control_event( *this, control, state );
453 break;
455 default:
456 cerr << "Do not understand control type " << control;
460 catch( MackieControlException & e ) {
461 MidiByteArray bytes( count, raw_bytes );
462 cout << bytes << ' ' << e.what() << endl;
465 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes));