PortMidi
Cross-platform MIDI IO library
pminternal.h
Go to the documentation of this file.
1 
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 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 extern int pm_initialized; /* see note in portmidi.c */
27 
28 /* these are defined in system-specific file */
29 void *pm_alloc(size_t s);
30 void pm_free(void *ptr);
31 
32 /* if a host error (an error reported by the host MIDI API that is not
33  * mapped to a PortMidi error code) occurs in a synchronous operation
34  * (i.e., not in a callback from another thread) set these: */
35 extern int pm_hosterror; /* boolean */
36 extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
37 
38 struct pm_internal_struct;
39 
40 /* these do not use PmInternal because it is not defined yet... */
41 typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi,
42  PmEvent *buffer);
43 typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
44  PmTimestamp timestamp);
45 typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
46  PmTimestamp timestamp);
47 typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
48  unsigned char byte, PmTimestamp timestamp);
49 typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
50  PmEvent *buffer);
51 typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
52  PmTimestamp timestamp);
53 typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
54 /* pm_open_fn should clean up all memory and close the device if any part
55  of the open fails */
56 typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
57  void *driverInfo);
58 typedef PmError (*pm_create_fn)(int is_input, const char *name,
59  void *driverInfo);
60 typedef PmError (*pm_delete_fn)(PmDeviceID id);
61 typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
62 /* pm_close_fn should clean up all memory and close the device if any
63  part of the close fails. */
64 typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
65 typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
66 typedef unsigned int (*pm_check_host_error_fn)(struct pm_internal_struct *midi);
67 
68 typedef struct {
69  pm_write_short_fn write_short; /* output short MIDI msg */
70  pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
71  pm_end_sysex_fn end_sysex; /* marks end of sysex message */
72  pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
73  pm_write_realtime_fn write_realtime; /* send real-time msg within sysex */
74  pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
75  pm_synchronize_fn synchronize; /* synchronize PM time to stream time */
76  pm_open_fn open; /* open MIDI device */
77  pm_abort_fn abort; /* abort */
78  pm_close_fn close; /* close device */
79  pm_poll_fn poll; /* read pending midi events into portmidi buffer */
80  pm_check_host_error_fn check_host_error; /* true when device has had host */
81  /* error; sets pm_hosterror and writes message to pm_hosterror_text */
82 } pm_fns_node, *pm_fns_type;
83 
84 
85 /* when open fails, the dictionary gets this set of functions: */
86 extern pm_fns_node pm_none_dictionary;
87 
88 typedef struct {
89  PmDeviceInfo pub; /* some portmidi state also saved in here (for automatic
90  device closing -- see PmDeviceInfo struct) */
91  int deleted; /* is this is a deleted virtual device? */
92  void *descriptor; /* ID number passed to win32 multimedia API open,
93  * coreMIDI endpoint, etc., representing the device */
94  struct pm_internal_struct *pm_internal; /* points to PmInternal device */
95  /* when the device is open, allows automatic device closing */
96  pm_fns_type dictionary;
97 } descriptor_node, *descriptor_type;
98 
99 extern int pm_descriptor_max;
100 extern descriptor_type pm_descriptors;
101 extern int pm_descriptor_len;
102 
103 typedef uint32_t (*time_get_proc_type)(void *time_info);
104 
105 typedef struct pm_internal_struct {
106  int device_id; /* which device is open (index to pm_descriptors) */
107  short is_input; /* MIDI IN (true) or MIDI OUT (false) */
108 
109  PmTimeProcPtr time_proc; /* where to get the time */
110  void *time_info; /* pass this to get_time() */
111  int32_t buffer_len; /* how big is the buffer or queue? */
112  PmQueue *queue;
113 
114  int32_t latency; /* time delay in ms between timestamps and actual output */
115  /* set to zero to get immediate, simple blocking output */
116  /* if latency is zero, timestamps will be ignored; */
117  /* if midi input device, this field ignored */
118 
119  int sysex_in_progress; /* when sysex status is seen, this flag becomes
120  * true until EOX is seen. When true, new data is appended to the
121  * stream of outgoing bytes. When overflow occurs, sysex data is
122  * dropped (until an EOX or non-real-timei status byte is seen) so
123  * that, if the overflow condition is cleared, we don't start
124  * sending data from the middle of a sysex message. If a sysex
125  * message is filtered, sysex_in_progress is false, causing the
126  * message to be dropped. */
127  PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
128  int sysex_message_count; /* how many bytes in sysex_message so far */
129 
130  int32_t filters; /* flags that filter incoming message classes */
131  int32_t channel_mask; /* filter incoming messages based on channel */
132  PmTimestamp last_msg_time; /* timestamp of last message */
133  PmTimestamp sync_time; /* time of last synchronization */
134  PmTimestamp now; /* set by PmWrite to current time */
135  int first_message; /* initially true, used to run first synchronization */
136  pm_fns_type dictionary; /* implementation functions */
137  void *api_info; /* system-dependent state */
138  /* the following are used to expedite sysex data */
139  /* on windows, in debug mode, based on some profiling, these optimizations
140  * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
141  * but this does not count time in the driver, so I don't know if it is
142  * important
143  */
144  unsigned char *fill_base; /* addr of ptr to sysex data */
145  uint32_t *fill_offset_ptr; /* offset of next sysex byte */
146  uint32_t fill_length; /* how many sysex bytes to write */
147 } PmInternal;
148 
149 
150 /* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
151 void pm_init(void);
152 void pm_term(void);
153 
154 /* defined by portMidi, used by pmwinmm */
155 PmError none_write_short(PmInternal *midi, PmEvent *buffer);
156 PmError none_write_byte(PmInternal *midi, unsigned char byte,
157  PmTimestamp timestamp);
158 PmTimestamp none_synchronize(PmInternal *midi);
159 
160 PmError pm_fail_fn(PmInternal *midi);
161 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
162 PmError pm_success_fn(PmInternal *midi);
163 PmError pm_add_interf(char *interf, pm_create_fn create_fn,
164  pm_delete_fn delete_fn);
165 PmError pm_add_device(char *interf, const char *name, int is_input,
166  int is_virtual, void *descriptor, pm_fns_type dictionary);
167 void pm_undo_add_device(int id);
168 uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
169  PmTimestamp timestamp);
170 void pm_read_short(PmInternal *midi, PmEvent *event);
171 
172 #define none_write_flush pm_fail_timestamp_fn
173 #define none_sysex pm_fail_timestamp_fn
174 #define none_poll pm_fail_fn
175 #define success_poll pm_success_fn
176 
177 #define MIDI_REALTIME_MASK 0xf8
178 #define is_real_time(msg) \
179  ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
180 
181 int pm_find_default_device(char *pattern, int is_input);
182 
183 #ifdef __cplusplus
184 }
185 #endif
186 
#define PM_HOST_ERROR_MSG_LEN
Any host error msg has at most this many characters, including EOS.
Definition: portmidi.h:199
PmError
PortMidi error code; a common return type.
Definition: portmidi.h:100
void PmQueue
The queue representation is opaque.
Definition: pmutil.h:21
Definition: portmidi.h:218
All MIDI data comes in the form of PmEvent structures.
Definition: portmidi.h:828
int32_t PmTimestamp
Represents a millisecond clock with arbitrary start time.
Definition: portmidi.h:333
int PmDeviceID
Devices are represented as small integers.
Definition: portmidi.h:206
uint32_t PmMessage
see PmEvent
Definition: portmidi.h:757