aboutsummaryrefslogtreecommitdiff
path: root/pd/portmidi_osx/portmidi.h
blob: 3e648c90be83b97638a68b2a1c582c701dd37c6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#ifndef PORT_MIDI_H
#define PORT_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/*
 * PortMidi Portable Real-Time Audio Library
 * PortMidi API Header File
 * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
 *
 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
 * Copyright (c) 2001 Roger B. Dannenberg
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * Any person wishing to distribute modifications to the Software is
 * requested to send the modifications to the original developer so that
 * they can be incorporated into the canonical version.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/* CHANGELOG FOR PORTMIDI -- THIS VERSION IS 1.0
 *
 * 21Jan02 RBD Added tests in Pm_OpenInput() and Pm_OpenOutput() to
 *               prevent opening an input as output and vice versa.
 *             Added comments and documentation.
 *             Implemented Pm_Terminate().
 */

#ifndef FALSE
    #define FALSE 0
#endif
#ifndef TRUE
    #define TRUE 1
#endif


typedef enum {
    pmNoError = 0,

    pmHostError = -10000,
    pmInvalidDeviceId, /* out of range or 
                          output device when input is requested or
                          input device when output is requested */
    //pmInvalidFlag,
    pmInsufficientMemory,
    pmBufferTooSmall,
    pmBufferOverflow,
    pmBadPtr,
    pmInternalError
} PmError;

/*
    Pm_Initialize() is the library initialisation function - call this before
    using the library.
*/

PmError Pm_Initialize( void );

/*
    Pm_Terminate() is the library termination function - call this after
    using the library.
*/

PmError Pm_Terminate( void );

/*
    Return host specific error number. All host-specific errors are translated
    to the single error class pmHostError. To find out the original error
    number, call Pm_GetHostError().
    This can be called after a function returns a PmError equal to pmHostError.
*/
int Pm_GetHostError();

/*
    Translate the error number into a human readable message.
*/
const char *Pm_GetErrorText( PmError errnum );


/*
    Device enumeration mechanism.

    Device ids range from 0 to Pm_CountDevices()-1.

    Devices may support input, output or both. Device 0 is always the "default"
    device. Other platform specific devices are specified by positive device
    ids.
*/

typedef int PmDeviceID;
#define pmNoDevice -1

typedef struct {
    int structVersion; 
    const char *interf;
    const char *name;
    int input; /* true iff input is available */
    int output; /* true iff output is available */
} PmDeviceInfo;


int Pm_CountDevices( void );
/*
    Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()

    Return the default device ID or pmNoDevice if there is no devices.
    The result can be passed to Pm_OpenMidi().
    
    On the PC, the user can specify a default device by
    setting an environment variable. For example, to use device #1.

        set PM_RECOMMENDED_OUTPUT_DEVICE=1
    
    The user should first determine the available device ID by using
    the supplied application "pm_devs".
*/
PmDeviceID Pm_GetDefaultInputDeviceID( void );
PmDeviceID Pm_GetDefaultOutputDeviceID( void );

/*
    PmTimestamp is used to represent a millisecond clock with arbitrary
    start time. The type is used for all MIDI timestampes and clocks.
*/

typedef long PmTimestamp;

/* TRUE if t1 before t2? */
#define PmBefore(t1,t2) ((t1-t2) < 0)


/*
    Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
    referring to the device specified by id.
    If id is out of range the function returns NULL.

    The returned structure is owned by the PortMidi implementation and must
    not be manipulated or freed. The pointer is guaranteed to be valid
    between calls to Pm_Initialize() and Pm_Terminate().
*/

const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );


/*
    A single PortMidiStream is a descriptor for an open MIDI device.
*/

typedef void PortMidiStream;
#define PmStream PortMidiStream

typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);


/*
    Pm_Open() opens a device; for either input or output.

    Port is the address of a PortMidiStream pointer which will receive
    a pointer to the newly opened stream.

    inputDevice is the id of the device used for input (see PmDeviceID above.)

    inputDriverInfo is a pointer to an optional driver specific data structure
    containing additional information for device setup or handle processing.
    inputDriverInfo is never required for correct operation. If not used
    inputDriverInfo should be NULL.

    outputDevice is the id of the device used for output (see PmDeviceID above.)

    outputDriverInfo is a pointer to an optional driver specific data structure
    containing additional information for device setup or handle processing.
    outputDriverInfo is never required for correct operation. If not used
    outputDriverInfo should be NULL.

    latency is the delay in milliseconds applied to timestamps to determine 
    when the output should actually occur.

    time_proc is a pointer to a procedure that returns time in milliseconds. It
    may be NULL, in which case a default millisecond timebase is used.

    time_info is a pointer passed to time_proc. 

    thru points to a PmMidi descriptor opened for output; Midi input will be
    copied to this output. To disable Midi thru, use NULL.

    return value:
    Upon success Pm_Open() returns PmNoError and places a pointer to a
    valid PortMidiStream in the stream argument.
    If a call to Pm_Open() fails a nonzero error code is returned (see
    PMError above) and the value of port is invalid.

*/

PmError Pm_OpenInput( PortMidiStream** stream,
                PmDeviceID inputDevice,
                void *inputDriverInfo,
                long bufferSize,
                PmTimeProcPtr time_proc,
                void *time_info,
                PmStream* thru );


PmError Pm_OpenOutput( PortMidiStream** stream,
                PmDeviceID outputDevice,
                void *outputDriverInfo,
                long bufferSize,
                PmTimeProcPtr time_proc,
                void *time_info,
                long latency );


/*
    Pm_Abort() terminates outgoing messages immediately
 */
PmError Pm_Abort( PortMidiStream* stream );
     
/*
    Pm_Close() closes a midi stream, flushing any pending buffers.
*/

PmError Pm_Close( PortMidiStream* stream );


/*
    Pm_Message() encodes a short Midi message into a long word. If data1
    and/or data2 are not present, use zero. The port parameter is the
    index of the Midi port if the device supports more than one.

    Pm_MessagePort(), Pm_MessageStatus(), Pm_MessageData1(), and 
    Pm_MessageData2() extract fields from a long-encoded midi message.
*/

#define Pm_Message(status, data1, data2) \
         ((((data2) << 16) & 0xFF0000) | \
          (((data1) << 8) & 0xFF00) | \
          ((status) & 0xFF))

#define Pm_MessageStatus(msg) ((msg) & 0xFF)
#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)

/* All midi data comes in the form of PmEvent structures. A sysex
   message is encoded as a sequence of PmEvent structures, with each
   structure carrying 4 bytes of the message, i.e. only the first
   PmEvent carries the status byte.

   When receiving sysex messages, the sysex message is terminated
   by either an EOX status byte (anywhere in the 4 byte message) or
   by a non-real-time status byte in the low order byte of message.
   If you get a non-real-time status byte, it means the sysex message
   was somehow truncated. It is permissible to interleave real-time
   messages within sysex messages.
 */

typedef long PmMessage;

typedef struct {
    PmMessage      message;
    PmTimestamp    timestamp;
} PmEvent;


/*
    Pm_Read() retrieves midi data into a buffer, and returns the number
    of events read. Result is a non-negative number unless an error occurs, 
    in which case a PmError value will be returned.

    Buffer Overflow

    The problem: if an input overflow occurs, data will be lost, ultimately 
    because there is no flow control all the way back to the data source. 
    When data is lost, the receiver should be notified and some sort of 
    graceful recovery should take place, e.g. you shouldn't resume receiving 
    in the middle of a long sysex message.

    With a lock-free fifo, which is pretty much what we're stuck with to 
    enable portability to the Mac, it's tricky for the producer and consumer 
    to synchronously reset the buffer and resume normal operation.

    Solution: the buffer managed by PortMidi will be flushed when an overflow
    occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
    and ordinary processing resumes as soon as a new message arrives. The
    remainder of a partial sysex message is not considered to be a "new
    message" and will be flushed as well.

*/

PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );

/*
    Pm_Poll() tests whether input is available, returning TRUE, FALSE, or
    an error value. 
*/

PmError Pm_Poll( PortMidiStream *stream);

/* 
    Pm_Write() writes midi data from a buffer. This may contain short
    messages or sysex messages that are converted into a sequence of PmEvent
    structures. Use Pm_WriteSysEx() to write a sysex message stored as a
    contiguous array of bytes.
*/

PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );

/*
    Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
*/

PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);

/*
    Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
*/
PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, char *msg);

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PORT_MIDI_H */