*** empty log message ***
[chuck-blob.git] / v1 / midiio_osx.cpp
blobae15fd6b66e9e63cfb579ba58ab7cb4ebbb6ac6b
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: midiio_osx.cpp
27 // desc: midi io osx implementation
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // Ari Lazier (alazier@cs.princeton.edu)
32 //-----------------------------------------------------------------------------
33 #include "midiio_osx.h"
34 #include <stdio.h>
39 //-----------------------------------------------------------------------------
40 // name: MidiOut()
41 // desc: constructor
42 //-----------------------------------------------------------------------------
43 MidiOut::MidiOut()
45 UINT__ m_device_num = 0;
46 m_midi_out = NULL;
47 m_midi_port = NULL;
48 m_midi_endpoint = NULL;
49 m_msg[0] = '\0';
55 //-----------------------------------------------------------------------------
56 // name: ~MidiOut()
57 // desc: destructor
58 //-----------------------------------------------------------------------------
59 MidiOut::~MidiOut()
61 this->close();
67 //-----------------------------------------------------------------------------
68 // name: open()
69 // desc: open a device
70 //-----------------------------------------------------------------------------
71 BOOL__ MidiOut::open( int device_num )
73 OSStatus err = 0;
75 // close
76 this->close();
78 m_device_num = device_num;
80 // get the number of devices
81 int num_src = MIDIGetNumberOfDestinations();
82 if( num_src < 1 )
84 sprintf( m_msg, "error: no MIDI destinations available" );
85 goto error;
88 // check to see if device is in range
89 if( device_num < 0 || device_num >= num_src )
91 sprintf( m_msg, "error: cannot open MIDI output device '%d'", device_num );
92 goto error;
95 // create client
96 err = MIDIClientCreate( CFSTR( "ChucK_MIDI_Output_Client" ),
97 NULL, NULL, &m_midi_out );
98 if( err != noErr )
100 sprintf( m_msg, "error: cannot open MIDI output client" );
101 goto error;
104 // make the port
105 err = MIDIOutputPortCreate( m_midi_out,
106 CFSTR( "ChucK_MIDI_Output_Port" ),
107 &m_midi_port );
108 if( err != noErr )
110 sprintf( m_msg, "error: cannot open MIDI output port" );
111 goto error;
114 // source
115 m_midi_endpoint = MIDIGetDestination( m_device_num );
117 return TRUE;
119 error:
120 this->close();
122 return FALSE;
128 //-----------------------------------------------------------------------------
129 // name: close()
130 // desc: close the device
131 //-----------------------------------------------------------------------------
132 BOOL__ MidiOut::close( )
134 // close midi out
135 if( m_midi_endpoint )
137 MIDIEndpointDispose( m_midi_endpoint );
138 m_midi_endpoint = NULL;
141 if( m_midi_port )
143 MIDIPortDispose( m_midi_port );
144 m_midi_port = NULL;
147 if( m_midi_out )
149 MIDIClientDispose( m_midi_out );
150 m_midi_out = NULL;
153 return TRUE;
159 //-----------------------------------------------------------------------------
160 // name: drain()
161 // desc: ...
162 //-----------------------------------------------------------------------------
163 BOOL__ MidiOut::drain()
165 return TRUE;
171 //-----------------------------------------------------------------------------
172 // name: send()
173 // desc: send 1 BYTE__ midi message
174 //-----------------------------------------------------------------------------
175 UINT__ MidiOut::send( BYTE__ status )
177 MidiMsg msg;
179 // send
180 msg.data[0] = status;
182 return this->send( &msg, 1 );
188 //-----------------------------------------------------------------------------
189 // name: send()
190 // desc: send 2 BYTE__ midi message
191 //-----------------------------------------------------------------------------
192 UINT__ MidiOut::send( BYTE__ status, BYTE__ data1 )
194 MidiMsg msg;
196 // send
197 msg.data[0] = status;
198 msg.data[1] = data1;
200 return this->send( &msg, 2 );
206 //-----------------------------------------------------------------------------
207 // name: send()
208 // desc: send 3 BYTE__ midi message
209 //-----------------------------------------------------------------------------
210 UINT__ MidiOut::send( BYTE__ status, BYTE__ data1, BYTE__ data2 )
212 MidiMsg msg;
214 // send
215 msg.data[0] = status;
216 msg.data[1] = data1;
217 msg.data[2] = data2;
219 return this->send( &msg, 3 );
225 //-----------------------------------------------------------------------------
226 // name: send()
227 // desc: send midi message
228 //-----------------------------------------------------------------------------
229 UINT__ MidiOut::send( const MidiMsg * msg, DWORD__ length )
231 OSStatus err = 0;
232 MIDIPacketList pl;
234 if( length == 0 )
235 length = 3;
237 // fill the packet
238 pl.numPackets = 1;
239 pl.packet[0].timeStamp = 0;
240 pl.packet[0].length = length;
241 pl.packet[0].data[0] = msg->data[0];
242 pl.packet[0].data[1] = msg->data[1];
243 pl.packet[0].data[2] = msg->data[2];
245 // go
246 err = MIDISend( m_midi_port, m_midi_endpoint, &pl );
248 // check err
249 if( err != noErr )
250 sprintf( m_msg, "error: cannot send MIDI packet" );
252 return err == noErr;
257 //-----------------------------------------------------------------------------
258 // name: MidiIn()
259 // desc: constructor
260 //-----------------------------------------------------------------------------
261 MidiIn::MidiIn()
263 m_device_num = 0;
264 m_midi_in = NULL;
265 m_midi_port = NULL;
266 m_midi_endpoint = NULL;
268 pthread_mutex_init( &m_mutex, NULL );
269 m_buffer.initialize( 1024, sizeof( MidiMsg ) );
271 m_msg[0] = '\0';
277 //-----------------------------------------------------------------------------
278 // name: ~MidiIn()
279 // desc: destructor
280 //-----------------------------------------------------------------------------
281 MidiIn::~MidiIn( )
283 this->close();
284 pthread_mutex_destroy( &m_mutex );
290 //-----------------------------------------------------------------------------
291 // name: open()
292 // desc: open
293 //-----------------------------------------------------------------------------
294 BOOL__ MidiIn::open( int device_num )
296 OSStatus err = 0;
298 // close it first
299 this->close();
301 m_device_num = device_num;
303 // get the number of devices
304 int num_src = MIDIGetNumberOfSources();
305 if( num_src < 1 )
307 sprintf( m_msg, "error: no MIDI sources available" );
308 goto error;
311 // check to see if device is in range
312 if( device_num < 0 || device_num >= num_src )
314 sprintf( m_msg, "error: cannot open MIDI input device '%d'", device_num );
315 goto error;
318 // create client
319 err = MIDIClientCreate( CFSTR( "ChucK_MIDI_Input_Client" ),
320 NULL, NULL, &m_midi_in );
321 if( err != noErr )
323 sprintf( m_msg, "error: cannot open MIDI input client" );
324 goto error;
327 // make the port
328 err = MIDIInputPortCreate( m_midi_in,
329 CFSTR( "ChucK_MIDI_Input_Port" ),
330 midi_in_cb,
331 (void *)this,
332 &m_midi_port );
333 if( err != noErr )
335 sprintf( m_msg, "error: cannot open MIDI input port" );
336 goto error;
339 // connect to source
340 m_midi_endpoint = MIDIGetSource( m_device_num );
341 err = MIDIPortConnectSource( m_midi_port, m_midi_endpoint, NULL );
342 if( err != noErr )
344 sprintf( m_msg, "error: cannot connect to MIDI source" );
345 goto error;
348 return TRUE;
350 error:
351 this->close();
353 return FALSE;
359 //-----------------------------------------------------------------------------
360 // name: close()
361 // desc: close
362 //-----------------------------------------------------------------------------
363 BOOL__ MidiIn::close()
365 // close midi out
366 if( m_midi_endpoint )
368 MIDIEndpointDispose( m_midi_endpoint );
369 m_midi_endpoint = NULL;
372 if( m_midi_port )
374 MIDIPortDispose( m_midi_port );
375 m_midi_port = NULL;
378 if( m_midi_in )
380 MIDIClientDispose( m_midi_in );
381 m_midi_in = NULL;
384 // pthread_cancel( m_cb_thread_id );
386 return TRUE;
392 //-----------------------------------------------------------------------------
393 // name: get()
394 // desc: get message
395 //-----------------------------------------------------------------------------
396 UINT__ MidiIn::recv( MidiMsg * msg )
398 UINT__ r = 0;
399 //pthread_mutex_lock( &m_mutex );
400 r = m_buffer.get( msg, 1 );
401 //pthread_mutex_unlock( &m_mutex );
403 return r;
409 //-----------------------------------------------------------------------------
410 // name: midi_in_cb()
411 // desc: ...
412 //-----------------------------------------------------------------------------
413 void MidiIn::midi_in_cb( const MIDIPacketList * list,
414 void * port_data,
415 void * connect_data )
417 MidiIn * min = (MidiIn *)port_data;
418 BYTE__ byte = 0;
419 int n = 0, num_args = 0, num_left = 0, length = 0;
420 MidiMsg msg;
421 const MIDIPacket * packet = &list->packet[0];
423 pthread_mutex_lock( &min->m_mutex );
424 for( UINT__ i = 0; i < list->numPackets; i++, packet = MIDIPacketNext( packet ) )
426 length = packet->length;
427 n = 0;
429 while( n < length )
431 byte = packet->data[n++];
433 if( byte & 0x80 ) // status byte
435 if( (byte & 0xf0) == 0xf0 ) // system msg
436 continue;
438 if( ( (byte & 0xf0) == 0xc0 ) || ( (byte & 0xf0) == 0xd0 ) )
439 num_args = 1;
440 else
441 num_args = 2;
443 msg.data[0] = 0;
444 msg.data[1] = byte;
445 msg.data[2] = 0;
446 msg.data[3] = 0;
447 num_left = num_args;
449 else // data byte
451 if( num_left == num_args )
452 msg.data[2] = byte;
453 else
454 msg.data[3] = byte;
456 num_left--;
458 if( !num_left )
460 if( ((msg.data[1] & 0xf0) == 0xc0) || ((msg.data[1] & 0xf0) == 0xd0) )
461 num_left = 1;
462 else
463 num_left = 2;
465 min->m_buffer.put( &msg, 1 );
470 pthread_mutex_unlock( &min->m_mutex );