1 /* pminternal.h -- header for interface implementations */
\r
3 /* this file is included by files that implement library internals */
\r
4 /* Here is a guide to implementers:
\r
5 provide an initialization function similar to pm_winmm_init()
\r
6 add your initialization function to pm_init()
\r
7 Note that your init function should never require not-standard
\r
8 libraries or fail in any way. If the interface is not available,
\r
9 simply do not call pm_add_device. This means that non-standard
\r
10 libraries should try to do dynamic linking at runtime using a DLL
\r
11 and return without error if the DLL cannot be found or if there
\r
12 is any other failure.
\r
13 implement functions as indicated in pm_fns_type to open, read, write,
\r
15 call pm_add_device() for each input and output device, passing it a
\r
16 pm_fns_type structure.
\r
17 assumptions about pm_fns_type functions are given below.
\r
24 extern int pm_initialized; /* see note in portmidi.c */
\r
26 /* these are defined in system-specific file */
\r
27 void *pm_alloc(size_t s);
\r
28 void pm_free(void *ptr);
\r
30 /* if an error occurs while opening or closing a midi stream, set these: */
\r
31 extern int pm_hosterror;
\r
32 extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
\r
34 struct pm_internal_struct;
\r
36 /* these do not use PmInternal because it is not defined yet... */
\r
37 typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi,
\r
39 typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
\r
40 PmTimestamp timestamp);
\r
41 typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
\r
42 PmTimestamp timestamp);
\r
43 typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
\r
44 unsigned char byte, PmTimestamp timestamp);
\r
45 typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
\r
47 typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
\r
48 PmTimestamp timestamp);
\r
49 typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
\r
50 /* pm_open_fn should clean up all memory and close the device if any part
\r
51 of the open fails */
\r
52 typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
\r
54 typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
\r
55 /* pm_close_fn should clean up all memory and close the device if any
\r
56 part of the close fails. */
\r
57 typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
\r
58 typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
\r
59 typedef void (*pm_host_error_fn)(struct pm_internal_struct *midi, char * msg,
\r
61 typedef unsigned int (*pm_has_host_error_fn)(struct pm_internal_struct *midi);
\r
64 pm_write_short_fn write_short; /* output short MIDI msg */
\r
65 pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
\r
66 pm_end_sysex_fn end_sysex; /* marks end of sysex message */
\r
67 pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
\r
68 pm_write_realtime_fn write_realtime; /* send real-time message within sysex */
\r
69 pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
\r
70 pm_synchronize_fn synchronize; /* synchronize portmidi time to stream time */
\r
71 pm_open_fn open; /* open MIDI device */
\r
72 pm_abort_fn abort; /* abort */
\r
73 pm_close_fn close; /* close device */
\r
74 pm_poll_fn poll; /* read pending midi events into portmidi buffer */
\r
75 pm_has_host_error_fn has_host_error; /* true when device has had host
\r
77 pm_host_error_fn host_error; /* provide text readable host error message
\r
78 for device (clears and resets) */
\r
79 } pm_fns_node, *pm_fns_type;
\r
82 /* when open fails, the dictionary gets this set of functions: */
\r
83 extern pm_fns_node pm_none_dictionary;
\r
86 PmDeviceInfo pub; /* some portmidi state also saved in here (for autmatic
\r
87 device closing (see PmDeviceInfo struct) */
\r
88 void *descriptor; /* ID number passed to win32 multimedia API open */
\r
89 void *internalDescriptor; /* points to PmInternal device, allows automatic
\r
91 pm_fns_type dictionary;
\r
92 } descriptor_node, *descriptor_type;
\r
94 extern int pm_descriptor_max;
\r
95 extern descriptor_type descriptors;
\r
96 extern int pm_descriptor_index;
\r
98 typedef uint32_t (*time_get_proc_type)(void *time_info);
\r
100 typedef struct pm_internal_struct {
\r
101 int device_id; /* which device is open (index to descriptors) */
\r
102 short write_flag; /* MIDI_IN, or MIDI_OUT */
\r
104 PmTimeProcPtr time_proc; /* where to get the time */
\r
105 void *time_info; /* pass this to get_time() */
\r
106 int32_t buffer_len; /* how big is the buffer or queue? */
\r
109 int32_t latency; /* time delay in ms between timestamps and actual output */
\r
110 /* set to zero to get immediate, simple blocking output */
\r
111 /* if latency is zero, timestamps will be ignored; */
\r
112 /* if midi input device, this field ignored */
\r
114 int sysex_in_progress; /* when sysex status is seen, this flag becomes
\r
115 * true until EOX is seen. When true, new data is appended to the
\r
116 * stream of outgoing bytes. When overflow occurs, sysex data is
\r
117 * dropped (until an EOX or non-real-timei status byte is seen) so
\r
118 * that, if the overflow condition is cleared, we don't start
\r
119 * sending data from the middle of a sysex message. If a sysex
\r
120 * message is filtered, sysex_in_progress is false, causing the
\r
121 * message to be dropped. */
\r
122 PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
\r
123 int sysex_message_count; /* how many bytes in sysex_message so far */
\r
125 int32_t filters; /* flags that filter incoming message classes */
\r
126 int32_t channel_mask; /* filter incoming messages based on channel */
\r
127 PmTimestamp last_msg_time; /* timestamp of last message */
\r
128 PmTimestamp sync_time; /* time of last synchronization */
\r
129 PmTimestamp now; /* set by PmWrite to current time */
\r
130 int first_message; /* initially true, used to run first synchronization */
\r
131 pm_fns_type dictionary; /* implementation functions */
\r
132 void *descriptor; /* system-dependent state */
\r
133 /* the following are used to expedite sysex data */
\r
134 /* on windows, in debug mode, based on some profiling, these optimizations
\r
135 * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
\r
136 * but this does not count time in the driver, so I don't know if it is
\r
139 unsigned char *fill_base; /* addr of ptr to sysex data */
\r
140 uint32_t *fill_offset_ptr; /* offset of next sysex byte */
\r
141 int32_t fill_length; /* how many sysex bytes to write */
\r
145 /* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
\r
146 void pm_init(void);
\r
147 void pm_term(void);
\r
149 /* defined by portMidi, used by pmwinmm */
\r
150 PmError none_write_short(PmInternal *midi, PmEvent *buffer);
\r
151 PmError none_write_byte(PmInternal *midi, unsigned char byte,
\r
152 PmTimestamp timestamp);
\r
153 PmTimestamp none_synchronize(PmInternal *midi);
\r
155 PmError pm_fail_fn(PmInternal *midi);
\r
156 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
\r
157 PmError pm_success_fn(PmInternal *midi);
\r
158 PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
\r
159 pm_fns_type dictionary);
\r
160 uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
\r
161 PmTimestamp timestamp);
\r
162 void pm_read_short(PmInternal *midi, PmEvent *event);
\r
164 #define none_write_flush pm_fail_timestamp_fn
\r
165 #define none_sysex pm_fail_timestamp_fn
\r
166 #define none_poll pm_fail_fn
\r
167 #define success_poll pm_success_fn
\r
169 #define MIDI_REALTIME_MASK 0xf8
\r
170 #define is_real_time(msg) \
\r
171 ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
\r
173 int pm_find_default_device(char *pattern, int is_input);
\r