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
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"
39 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
45 UINT__ m_device_num
= 0;
48 m_midi_endpoint
= NULL
;
55 //-----------------------------------------------------------------------------
58 //-----------------------------------------------------------------------------
67 //-----------------------------------------------------------------------------
69 // desc: open a device
70 //-----------------------------------------------------------------------------
71 BOOL__
MidiOut::open( int device_num
)
78 m_device_num
= device_num
;
80 // get the number of devices
81 int num_src
= MIDIGetNumberOfDestinations();
84 sprintf( m_msg
, "error: no MIDI destinations available" );
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
);
96 err
= MIDIClientCreate( CFSTR( "ChucK_MIDI_Output_Client" ),
97 NULL
, NULL
, &m_midi_out
);
100 sprintf( m_msg
, "error: cannot open MIDI output client" );
105 err
= MIDIOutputPortCreate( m_midi_out
,
106 CFSTR( "ChucK_MIDI_Output_Port" ),
110 sprintf( m_msg
, "error: cannot open MIDI output port" );
115 m_midi_endpoint
= MIDIGetDestination( m_device_num
);
128 //-----------------------------------------------------------------------------
130 // desc: close the device
131 //-----------------------------------------------------------------------------
132 BOOL__
MidiOut::close( )
135 if( m_midi_endpoint
)
137 MIDIEndpointDispose( m_midi_endpoint
);
138 m_midi_endpoint
= NULL
;
143 MIDIPortDispose( m_midi_port
);
149 MIDIClientDispose( m_midi_out
);
159 //-----------------------------------------------------------------------------
162 //-----------------------------------------------------------------------------
163 BOOL__
MidiOut::drain()
171 //-----------------------------------------------------------------------------
173 // desc: send 1 BYTE__ midi message
174 //-----------------------------------------------------------------------------
175 UINT__
MidiOut::send( BYTE__ status
)
180 msg
.data
[0] = status
;
182 return this->send( &msg
, 1 );
188 //-----------------------------------------------------------------------------
190 // desc: send 2 BYTE__ midi message
191 //-----------------------------------------------------------------------------
192 UINT__
MidiOut::send( BYTE__ status
, BYTE__ data1
)
197 msg
.data
[0] = status
;
200 return this->send( &msg
, 2 );
206 //-----------------------------------------------------------------------------
208 // desc: send 3 BYTE__ midi message
209 //-----------------------------------------------------------------------------
210 UINT__
MidiOut::send( BYTE__ status
, BYTE__ data1
, BYTE__ data2
)
215 msg
.data
[0] = status
;
219 return this->send( &msg
, 3 );
225 //-----------------------------------------------------------------------------
227 // desc: send midi message
228 //-----------------------------------------------------------------------------
229 UINT__
MidiOut::send( const MidiMsg
* msg
, DWORD__ length
)
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];
246 err
= MIDISend( m_midi_port
, m_midi_endpoint
, &pl
);
250 sprintf( m_msg
, "error: cannot send MIDI packet" );
257 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
266 m_midi_endpoint
= NULL
;
268 pthread_mutex_init( &m_mutex
, NULL
);
269 m_buffer
.initialize( 1024, sizeof( MidiMsg
) );
277 //-----------------------------------------------------------------------------
280 //-----------------------------------------------------------------------------
284 pthread_mutex_destroy( &m_mutex
);
290 //-----------------------------------------------------------------------------
293 //-----------------------------------------------------------------------------
294 BOOL__
MidiIn::open( int device_num
)
301 m_device_num
= device_num
;
303 // get the number of devices
304 int num_src
= MIDIGetNumberOfSources();
307 sprintf( m_msg
, "error: no MIDI sources available" );
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
);
319 err
= MIDIClientCreate( CFSTR( "ChucK_MIDI_Input_Client" ),
320 NULL
, NULL
, &m_midi_in
);
323 sprintf( m_msg
, "error: cannot open MIDI input client" );
328 err
= MIDIInputPortCreate( m_midi_in
,
329 CFSTR( "ChucK_MIDI_Input_Port" ),
335 sprintf( m_msg
, "error: cannot open MIDI input port" );
340 m_midi_endpoint
= MIDIGetSource( m_device_num
);
341 err
= MIDIPortConnectSource( m_midi_port
, m_midi_endpoint
, NULL
);
344 sprintf( m_msg
, "error: cannot connect to MIDI source" );
359 //-----------------------------------------------------------------------------
362 //-----------------------------------------------------------------------------
363 BOOL__
MidiIn::close()
366 if( m_midi_endpoint
)
368 MIDIEndpointDispose( m_midi_endpoint
);
369 m_midi_endpoint
= NULL
;
374 MIDIPortDispose( m_midi_port
);
380 MIDIClientDispose( m_midi_in
);
384 // pthread_cancel( m_cb_thread_id );
392 //-----------------------------------------------------------------------------
395 //-----------------------------------------------------------------------------
396 UINT__
MidiIn::recv( MidiMsg
* msg
)
399 //pthread_mutex_lock( &m_mutex );
400 r
= m_buffer
.get( msg
, 1 );
401 //pthread_mutex_unlock( &m_mutex );
409 //-----------------------------------------------------------------------------
410 // name: midi_in_cb()
412 //-----------------------------------------------------------------------------
413 void MidiIn::midi_in_cb( const MIDIPacketList
* list
,
415 void * connect_data
)
417 MidiIn
* min
= (MidiIn
*)port_data
;
419 int n
= 0, num_args
= 0, num_left
= 0, length
= 0;
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
;
431 byte
= packet
->data
[n
++];
433 if( byte
& 0x80 ) // status byte
435 if( (byte
& 0xf0) == 0xf0 ) // system msg
438 if( ( (byte
& 0xf0) == 0xc0 ) || ( (byte
& 0xf0) == 0xd0 ) )
451 if( num_left
== num_args
)
460 if( ((msg
.data
[1] & 0xf0) == 0xc0) || ((msg
.data
[1] & 0xf0) == 0xd0) )
465 min
->m_buffer
.put( &msg
, 1 );
470 pthread_mutex_unlock( &min
->m_mutex
);