aboutsummaryrefslogtreecommitdiff
path: root/portmidi/pm_common/pminternal.h
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/pm_common/pminternal.h')
-rwxr-xr-xportmidi/pm_common/pminternal.h190
1 files changed, 190 insertions, 0 deletions
diff --git a/portmidi/pm_common/pminternal.h b/portmidi/pm_common/pminternal.h
new file mode 100755
index 0000000..8b3d8f5
--- /dev/null
+++ b/portmidi/pm_common/pminternal.h
@@ -0,0 +1,190 @@
1/** @file pminternal.h header for PortMidi implementations */
2
3/* this file is included by files that implement library internals */
4/* Here is a guide to implementers:
5 provide an initialization function similar to pm_winmm_init()
6 add your initialization function to pm_init()
7 Note that your init function should never require not-standard
8 libraries or fail in any way. If the interface is not available,
9 simply do not call pm_add_device. This means that non-standard
10 libraries should try to do dynamic linking at runtime using a DLL
11 and return without error if the DLL cannot be found or if there
12 is any other failure.
13 implement functions as indicated in pm_fns_type to open, read, write,
14 close, etc.
15 call pm_add_device() for each input and output device, passing it a
16 pm_fns_type structure.
17 assumptions about pm_fns_type functions are given below.
18 */
19
20/** @cond INTERNAL - add INTERNAL to Doxygen ENABLED_SECTIONS to include */
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26extern int pm_initialized; /* see note in portmidi.c */
27extern PmDeviceID pm_default_input_device_id;
28extern PmDeviceID pm_default_output_device_id;
29
30/* these are defined in system-specific file */
31void *pm_alloc(size_t s);
32void pm_free(void *ptr);
33
34/* if a host error (an error reported by the host MIDI API that is not
35 * mapped to a PortMidi error code) occurs in a synchronous operation
36 * (i.e., not in a callback from another thread) set these: */
37extern int pm_hosterror; /* boolean */
38extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
39
40struct pm_internal_struct;
41
42/* these do not use PmInternal because it is not defined yet... */
43typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi,
44 PmEvent *buffer);
45typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
46 PmTimestamp timestamp);
47typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
48 PmTimestamp timestamp);
49typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
50 unsigned char byte, PmTimestamp timestamp);
51typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
52 PmEvent *buffer);
53typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
54 PmTimestamp timestamp);
55typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
56/* pm_open_fn should clean up all memory and close the device if any part
57 of the open fails */
58typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
59 void *driverInfo);
60typedef PmError (*pm_create_fn)(int is_input, const char *name,
61 void *driverInfo);
62typedef PmError (*pm_delete_fn)(PmDeviceID id);
63typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
64/* pm_close_fn should clean up all memory and close the device if any
65 part of the close fails. */
66typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
67typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
68typedef unsigned int (*pm_check_host_error_fn)(struct pm_internal_struct *midi);
69
70typedef struct {
71 pm_write_short_fn write_short; /* output short MIDI msg */
72 pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
73 pm_end_sysex_fn end_sysex; /* marks end of sysex message */
74 pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
75 pm_write_realtime_fn write_realtime; /* send real-time msg within sysex */
76 pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
77 pm_synchronize_fn synchronize; /* synchronize PM time to stream time */
78 pm_open_fn open; /* open MIDI device */
79 pm_abort_fn abort; /* abort */
80 pm_close_fn close; /* close device */
81 pm_poll_fn poll; /* read pending midi events into portmidi buffer */
82 pm_check_host_error_fn check_host_error; /* true when device has had host */
83 /* error; sets pm_hosterror and writes message to pm_hosterror_text */
84} pm_fns_node, *pm_fns_type;
85
86
87/* when open fails, the dictionary gets this set of functions: */
88extern pm_fns_node pm_none_dictionary;
89
90typedef struct {
91 PmDeviceInfo pub; /* some portmidi state also saved in here (for automatic
92 device closing -- see PmDeviceInfo struct) */
93 int deleted; /* is this is a deleted virtual device? */
94 void *descriptor; /* ID number passed to win32 multimedia API open,
95 * coreMIDI endpoint, etc., representing the device */
96 struct pm_internal_struct *pm_internal; /* points to PmInternal device */
97 /* when the device is open, allows automatic device closing */
98 pm_fns_type dictionary;
99} descriptor_node, *descriptor_type;
100
101extern int pm_descriptor_max;
102extern descriptor_type pm_descriptors;
103extern int pm_descriptor_len;
104
105typedef uint32_t (*time_get_proc_type)(void *time_info);
106
107typedef struct pm_internal_struct {
108 int device_id; /* which device is open (index to pm_descriptors) */
109 short is_input; /* MIDI IN (true) or MIDI OUT (false) */
110 short is_removed; /* MIDI device was removed */
111 PmTimeProcPtr time_proc; /* where to get the time */
112 void *time_info; /* pass this to get_time() */
113 int32_t buffer_len; /* how big is the buffer or queue? */
114 PmQueue *queue;
115
116 int32_t latency; /* time delay in ms between timestamps and actual output */
117 /* set to zero to get immediate, simple blocking output */
118 /* if latency is zero, timestamps will be ignored; */
119 /* if midi input device, this field ignored */
120
121 int sysex_in_progress; /* when sysex status is seen, this flag becomes
122 * true until EOX is seen. When true, new data is appended to the
123 * stream of outgoing bytes. When overflow occurs, sysex data is
124 * dropped (until an EOX or non-real-timei status byte is seen) so
125 * that, if the overflow condition is cleared, we don't start
126 * sending data from the middle of a sysex message. If a sysex
127 * message is filtered, sysex_in_progress is false, causing the
128 * message to be dropped. */
129 PmMessage message; /* buffer for 4 bytes of sysex data */
130 int message_count; /* how many bytes in sysex_message so far */
131 int short_message_count; /* how many bytes are expected in short message */
132 unsigned char running_status; /* running status byte or zero if none */
133 int32_t filters; /* flags that filter incoming message classes */
134 int32_t channel_mask; /* filter incoming messages based on channel */
135 PmTimestamp last_msg_time; /* timestamp of last message */
136 PmTimestamp sync_time; /* time of last synchronization */
137 PmTimestamp now; /* set by PmWrite to current time */
138 int first_message; /* initially true, used to run first synchronization */
139 pm_fns_type dictionary; /* implementation functions */
140 void *api_info; /* system-dependent state */
141 /* the following are used to expedite sysex data */
142 /* on windows, in debug mode, based on some profiling, these optimizations
143 * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
144 * but this does not count time in the driver, so I don't know if it is
145 * important
146 */
147 unsigned char *fill_base; /* addr of ptr to sysex data */
148 uint32_t *fill_offset_ptr; /* offset of next sysex byte */
149 uint32_t fill_length; /* how many sysex bytes to write */
150} PmInternal;
151
152/* what is the length of this short message? */
153int pm_midi_length(PmMessage msg);
154
155/* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
156void pm_init(void);
157void pm_term(void);
158
159/* defined by portMidi, used by pmwinmm */
160PmError none_write_short(PmInternal *midi, PmEvent *buffer);
161PmError none_write_byte(PmInternal *midi, unsigned char byte,
162 PmTimestamp timestamp);
163PmTimestamp none_synchronize(PmInternal *midi);
164
165PmError pm_fail_fn(PmInternal *midi);
166PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
167PmError pm_success_fn(PmInternal *midi);
168PmError pm_add_interf(char *interf, pm_create_fn create_fn,
169 pm_delete_fn delete_fn);
170PmError pm_add_device(char *interf, const char *name, int is_input,
171 int is_virtual, void *descriptor, pm_fns_type dictionary);
172void pm_undo_add_device(int id);
173uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
174 PmTimestamp timestamp);
175void pm_read_short(PmInternal *midi, PmEvent *event);
176
177#define none_write_flush pm_fail_timestamp_fn
178#define none_sysex pm_fail_timestamp_fn
179#define none_poll pm_fail_fn
180#define success_poll pm_success_fn
181
182#define MIDI_REALTIME_MASK 0xf8
183#define is_real_time(msg) \
184 ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
185
186#ifdef __cplusplus
187}
188#endif
189
190/** @endcond */