Fix for building on MacOS X.
[ardour.git] / libs / surfaces / mackie / mackie_port.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3
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.
8
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.
13
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.
17 */
18 #include "mackie_port.h"
19
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"
25
26 #include <midi++/types.h>
27 #include <midi++/port.h>
28 #include <sigc++/sigc++.h>
29 #include <boost/shared_array.hpp>
30 #include <ardour/configuration.h>
31
32 #include "i18n.h"
33
34 #include <sstream>
35
36 using namespace std;
37 using namespace Mackie;
38
39 // The MCU sysex header
40 MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 );
41
42 // The MCU extender sysex header
43 MidiByteArray mackie_sysex_hdr_xt ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11 );
44
45 MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t port_type )
46 : SurfacePort( port, number )
47 , _mcp( mcp )
48 , _port_type( port_type )
49 , _emulation( none )
50 , _initialising( true )
51 {
52         cout << "MackiePort::MackiePort" <<endl;
53 }
54
55 MackiePort::~MackiePort()
56 {
57         close();
58 }
59
60 int MackiePort::strips() const
61 {
62         if ( _port_type == mcu )
63         {
64                 switch ( _emulation )
65                 {
66                         // BCF2000 only has 8 faders, so reserve one for master
67                         case bcf2000: return 7;
68                         case mackie: return 8;
69                         case none:
70                         default:
71                                 throw MackieControlException( "MackiePort::strips: don't know what emulation we're using" );
72                 }
73         }
74         else
75         {
76                 // must be an extender, ie no master fader
77                 return 8;
78         }
79 }
80
81 // should really be in MackiePort
82 void MackiePort::open()
83 {
84         cout << "MackiePort::open " << *this << endl;
85         _sysex = port().input()->sysex.connect( ( mem_fun (*this, &MackiePort::handle_midi_sysex) ) );
86         
87         // make sure the device is connected
88         init();
89 }
90
91 void MackiePort::close()
92 {
93         // disconnect signals
94         _any.disconnect();
95         _sysex.disconnect();
96         
97         // or emit a "closing" signal
98 }
99
100 const MidiByteArray & MackiePort::sysex_hdr() const
101 {
102         switch ( _port_type )
103         {
104                 case mcu: return mackie_sysex_hdr;
105                 case ext: return mackie_sysex_hdr_xt;
106         }
107         cout << "MackiePort::sysex_hdr _port_type not known" << endl;
108         return mackie_sysex_hdr;
109 }
110
111 Control & MackiePort::lookup_control( const MidiByteArray & bytes )
112 {
113         Control * control = 0;
114         int midi_id = -1;
115         MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
116         switch( midi_type )
117         {
118                 // fader
119                 case MackieMidiBuilder::midi_fader_id:
120                         midi_id = bytes[0] & 0x0f;
121                         control = _mcp.surface().faders[midi_id];
122                         if ( control == 0 )
123                         {
124                                 ostringstream os;
125                                 os << "control for fader" << midi_id << " is null";
126                                 throw MackieControlException( os.str() );
127                         }
128                         break;
129                         
130                 // button
131                 case MackieMidiBuilder::midi_button_id:
132                         midi_id = bytes[1];
133                         control = _mcp.surface().buttons[midi_id];
134                         if ( control == 0 )
135                         {
136                                 ostringstream os;
137                                 os << "control for button" << midi_id << " is null";
138                                 throw MackieControlException( os.str() );
139                         }
140                         break;
141                         
142                 // pot (jog wheel, external control)
143                 case MackieMidiBuilder::midi_pot_id:
144                         midi_id = bytes[1] & 0x1f;
145                         control = _mcp.surface().pots[midi_id];
146                         if ( control == 0 )
147                         {
148                                 ostringstream os;
149                                 os << "control for button" << midi_id << " is null";
150                                 throw MackieControlException( os.str() );
151                         }
152                         break;
153                 
154                 default:
155                         ostringstream os;
156                         os << "Cannot find control for " << bytes;
157                         throw MackieControlException( os.str() );
158         }
159         return *control;
160 }
161
162 MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
163 {
164         MidiByteArray l;
165         back_insert_iterator<MidiByteArray> back ( l );
166         copy( begin, end, back );
167         
168         MidiByteArray retval;
169         
170         // this is how to calculate the response to the challenge.
171         // from the Logic docs.
172         retval << ( 0x7f & ( l[0] + ( l[1] ^ 0xa ) - l[3] ) );
173         retval << ( 0x7f & ( ( l[2] >> l[3] ) ^ ( l[0] + l[3] ) ) );
174         retval << ( 0x7f & ( l[3] - ( l[2] << 2 ) ^ ( l[0] | l[1] ) ) );
175         retval << ( 0x7f & ( l[1] - l[2] + ( 0xf0 ^ ( l[3] << 4 ) ) ) );
176         
177         return retval;
178 }
179
180 // not used right now
181 MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
182 {
183         // handle host connection query
184         cout << "host connection query: " << bytes << endl;
185         
186         if ( bytes.size() != 18 )
187         {
188                 finalise_init( false );
189                 ostringstream os;
190                 os << "expecting 18 bytes, read " << bytes << " from " << port().name();
191                 throw MackieControlException( os.str() );
192         }
193
194         // build and send host connection reply
195         MidiByteArray response;
196         response << 0x02;
197         copy( bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter( response ) );
198         response << calculate_challenge_response( bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4 );
199         return response;
200 }
201
202 // not used right now
203 MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
204 {
205         cout << "host_connection_confirmation: " << bytes << endl;
206         
207         // decode host connection confirmation
208         if ( bytes.size() != 14 )
209         {
210                 finalise_init( false );
211                 ostringstream os;
212                 os << "expecting 14 bytes, read " << bytes << " from " << port().name();
213                 throw MackieControlException( os.str() );
214         }
215         
216         // send version request
217         return MidiByteArray( 2, 0x13, 0x00 );
218 }
219
220 void MackiePort::probe_emulation( const MidiByteArray & bytes )
221 {
222         cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
223         string version_string;
224         for ( int i = 6; i < 11; ++i ) version_string.append( 1, (char)bytes[i] );
225         cout << "version_string: " << version_string << endl;
226         
227         // TODO investigate using serial number. Also, possibly size of bytes might
228         // give an indication. Also, apparently MCU sends non-documented messages
229         // sometimes.
230         if (!_initialising)
231         {
232                 cout << "MackiePort::probe_emulation out of sequence." << endl;
233                 return;
234         }
235
236         // probing doesn't work very well, so just use a config variable
237         // to set the emulation mode
238         bool emulation_ok = false;
239         if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
240         {
241                 _emulation = bcf2000;
242                 emulation_ok = true;
243         }
244         else if ( ARDOUR::Config->get_mackie_emulation() == "mcu" )
245         {
246                 _emulation = mackie;
247                 emulation_ok = true;
248         }
249         else
250         {
251                 cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
252                 emulation_ok = false;
253         }
254         
255         finalise_init( emulation_ok );
256 }
257
258 void MackiePort::init()
259 {
260         cout << "MackiePort::init" << endl;
261         init_mutex.lock();
262         _initialising = true;
263         
264         cout << "MackiePort::lock acquired" << endl;
265         // emit pre-init signal
266         init_event();
267         
268         // kick off initialisation. See docs in header file for init()
269         write_sysex ( MidiByteArray (2, 0x13, 0x00 ));
270 }
271
272 void MackiePort::finalise_init( bool yn )
273 {
274         cout << "MackiePort::finalise_init" << endl;
275         
276         SurfacePort::active( yn );
277
278         if ( yn )
279         {
280                 active_event();
281                 
282                 // start handling messages from controls
283                 _any = port().input()->any.connect( ( mem_fun (*this, &MackiePort::handle_midi_any) ) );
284         }
285         _initialising = false;
286         init_cond.signal();
287         init_mutex.unlock();
288 }
289
290 bool MackiePort::wait_for_init()
291 {
292         Glib::Mutex::Lock lock( init_mutex );
293         while ( _initialising )
294         {
295                 cout << "MackiePort::wait_for_active waiting" << endl;
296                 init_cond.wait( init_mutex );
297                 cout << "MackiePort::wait_for_active released" << endl;
298         }
299         cout << "MackiePort::wait_for_active returning" << endl;
300         return SurfacePort::active();
301 }
302
303 void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
304 {
305         MidiByteArray bytes( count, raw_bytes );
306         cout << "handle_midi_sysex: " << bytes << endl;
307         switch( bytes[5] )
308         {
309                 case 0x01:
310                         // not used right now
311                         write_sysex( host_connection_query( bytes ) );
312                         break;
313                 case 0x03:
314                         // not used right now
315                         write_sysex( host_connection_confirmation( bytes ) );
316                         break;
317                 case 0x04:
318                         inactive_event();
319                         cout << "host connection error" << bytes << endl;
320                         break;
321                 case 0x14:
322                         probe_emulation( bytes );
323                         break;
324                 default:
325                         cout << "unknown sysex: " << bytes << endl;
326         }
327 }
328
329 // converts midi messages into control_event signals
330 void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
331 {
332         MidiByteArray bytes( count, raw_bytes );
333         try
334         {
335                 // ignore sysex messages
336                 if ( bytes[0] == MIDI::sysex ) return;
337
338                 Control & control = lookup_control( bytes );
339                 
340                 // This handles incoming bytes. Outgoing bytes
341                 // are sent by the signal handlers.
342                 switch ( control.type() )
343                 {
344                         // fader
345                         case Control::type_fader:
346                                 {
347                                         // for a BCF2000, max is 7f for high-order byte and 0x70 for low-order byte
348                                         // According to the Logic docs, these should both be 0x7f.
349                                         // Although it does mention something about only the top-order
350                                         // 10 bits out of 14 being used
351                                         int midi_pos = ( bytes[2] << 7 ) + bytes[1];
352                                         control_event( *this, control, float(midi_pos) / float(0x3fff) );
353                                 }
354                                 break;
355                                 
356                         // button
357                         case Control::type_button:
358                                 control_event( *this, control, bytes[2] == 0x7f ? press : release );
359                                 break;
360                                 
361                         // pot (jog wheel, external control)
362                         case Control::type_pot:
363                                 {
364                                         ControlState state;
365                                         
366                                         // bytes[2] & 0b01000000 (0x40) give sign
367                                         int sign = ( bytes[2] & 0x40 ) == 0 ? 1 : -1; 
368                                         // bytes[2] & 0b00111111 (0x3f) gives delta
369                                         state.ticks = ( bytes[2] & 0x3f) * sign;
370                                         state.delta = float( state.ticks ) / float( 0x3f );
371                                         
372                                         control_event( *this, control, state );
373                                 }
374                                 break;
375                         default:
376                                 cerr << "Do not understand control type " << control;
377                 }
378         }
379         catch( MackieControlException & e )
380         {
381                 cout << bytes << ' ' << e.what() << endl;
382         }
383 }