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