aboutsummaryrefslogtreecommitdiff
path: root/portmidi/pm_common/portmidi.c
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/pm_common/portmidi.c')
-rwxr-xr-xportmidi/pm_common/portmidi.c1472
1 files changed, 1472 insertions, 0 deletions
diff --git a/portmidi/pm_common/portmidi.c b/portmidi/pm_common/portmidi.c
new file mode 100755
index 0000000..e78ee73
--- /dev/null
+++ b/portmidi/pm_common/portmidi.c
@@ -0,0 +1,1472 @@
1/* portmidi.c -- cross-platform MIDI I/O library */
2/* see license.txt for license */
3
4#include "stdlib.h"
5#include "string.h"
6#include "portmidi.h"
7#include "porttime.h"
8#include "pmutil.h"
9#include "pminternal.h"
10#include <assert.h>
11
12#define MIDI_CLOCK 0xf8
13#define MIDI_ACTIVE 0xfe
14#define MIDI_STATUS_MASK 0x80
15#define MIDI_SYSEX 0xf0
16#define MIDI_EOX 0xf7
17#define MIDI_START 0xFA
18#define MIDI_STOP 0xFC
19#define MIDI_CONTINUE 0xFB
20#define MIDI_F9 0xF9
21#define MIDI_FD 0xFD
22#define MIDI_RESET 0xFF
23#define MIDI_NOTE_ON 0x90
24#define MIDI_NOTE_OFF 0x80
25#define MIDI_CHANNEL_AT 0xD0
26#define MIDI_POLY_AT 0xA0
27#define MIDI_PROGRAM 0xC0
28#define MIDI_CONTROL 0xB0
29#define MIDI_PITCHBEND 0xE0
30#define MIDI_MTC 0xF1
31#define MIDI_SONGPOS 0xF2
32#define MIDI_SONGSEL 0xF3
33#define MIDI_TUNE 0xF6
34
35#define is_empty(midi) ((midi)->tail == (midi)->head)
36
37/* these are not static so that (possibly) some system-dependent code
38 * could override the portmidi.c default which is to use the first
39 * device added using pm_add_device()
40 */
41PmDeviceID pm_default_input_device_id = -1;
42PmDeviceID pm_default_output_device_id = -1;
43
44/* this is not static so that pm_init can set it directly
45 * (see pmmac.c:pm_init())
46 */
47int pm_initialized = FALSE;
48
49int pm_hosterror; /* boolean */
50
51/* if PM_CHECK_ERRORS is enabled, but the caller wants to
52 * handle an error condition, declare this as extern and
53 * set to FALSE (this override is provided specifically
54 * for the test program virttest.c, where pmNameConflict
55 * is expected in a call to Pm_CreateVirtualInput()):
56 */
57int pm_check_errors = TRUE;
58
59char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
60
61#ifdef PM_CHECK_ERRORS
62
63#include <stdio.h>
64
65#define STRING_MAX 80
66
67static void prompt_and_exit(void)
68{
69 char line[STRING_MAX];
70 printf("type ENTER...");
71 char *rslt = fgets(line, STRING_MAX, stdin);
72 /* this will clean up open ports: */
73 exit(-1);
74}
75
76static PmError pm_errmsg(PmError err)
77{
78 if (!pm_check_errors) { /* see pm_check_errors declaration above */
79 ;
80 } else if (err == pmHostError) {
81 /* it seems pointless to allocate memory and copy the string,
82 * so I will do the work of Pm_GetHostErrorText directly
83 */
84 printf("PortMidi found host error...\n %s\n", pm_hosterror_text);
85 pm_hosterror = FALSE;
86 pm_hosterror_text[0] = 0; /* clear the message */
87 prompt_and_exit();
88 } else if (err < 0) {
89 printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
90 prompt_and_exit();
91 }
92 return err;
93}
94#else
95#define pm_errmsg(err) err
96#endif
97
98
99int pm_midi_length(PmMessage msg)
100{
101 int status, high, low;
102 static int high_lengths[] = {
103 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */
104 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */
105 };
106 static int low_lengths[] = {
107 1, 2, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */
108 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */
109 };
110
111 status = msg & 0xFF;
112 high = status >> 4;
113 low = status & 15;
114
115 return (high != 0xF) ? high_lengths[high] : low_lengths[low];
116}
117
118
119/*
120====================================================================
121system implementation of portmidi interface
122====================================================================
123*/
124
125int pm_descriptor_max = 0;
126int pm_descriptor_len = 0;
127descriptor_type pm_descriptors = NULL;
128
129/* interface pm_descriptors are simple: an array of string/fnptr pairs: */
130#define MAX_INTERF 4
131static struct {
132 const char *interf;
133 pm_create_fn create_fn;
134 pm_delete_fn delete_fn;
135} pm_interf_list[MAX_INTERF];
136
137static int pm_interf_list_len = 0;
138
139
140/* pm_add_interf -- describe an interface to library
141 *
142 * This is called at initialization time, once for each
143 * supported interface (e.g., CoreMIDI). The strings
144 * are retained but NOT COPIED, so do not destroy them!
145 *
146 * The purpose is to register functions that create/delete
147 * a virtual input or output device.
148 *
149 * returns pmInsufficientMemor if interface memory is
150 * exceeded, otherwise returns pmNoError.
151 */
152PmError pm_add_interf(char *interf, pm_create_fn create_fn,
153 pm_delete_fn delete_fn)
154{
155 if (pm_interf_list_len >= MAX_INTERF) {
156 return pmInsufficientMemory;
157 }
158 pm_interf_list[pm_interf_list_len].interf = interf;
159 pm_interf_list[pm_interf_list_len].create_fn = create_fn;
160 pm_interf_list[pm_interf_list_len].delete_fn = delete_fn;
161 pm_interf_list_len++;
162 return pmNoError;
163}
164
165
166PmError pm_create_virtual(PmInternal *midi, int is_input, const char *interf,
167 const char *name, void *device_info)
168{
169 int i;
170 if (pm_interf_list_len == 0) {
171 return pmNotImplemented;
172 }
173 if (!interf) {
174 /* default interface is the first one */
175 interf = pm_interf_list[0].interf;
176 }
177 for (i = 0; i < pm_interf_list_len; i++) {
178 if (strcmp(pm_interf_list[i].interf,
179 interf) == 0) {
180 int id = (*pm_interf_list[i].create_fn)(is_input, name,
181 device_info);
182 pm_descriptors[id].pub.is_virtual = TRUE;
183 return id;
184 }
185 }
186 return pmInterfaceNotSupported;
187}
188
189
190/* pm_add_device -- describe interface/device pair to library
191 *
192 * This is called at intialization time, once for each
193 * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1).
194 * This is also called when user creates a virtual device.
195 *
196 * Normally, increasing integer indices are returned. If the device
197 * is virtual, a linear search is performed to ensure that the name
198 * is unique. If the name is already taken, the call will fail and
199 * no device is added.
200 *
201 * interf is assumed to be static memory, so it is NOT COPIED and
202 * NOT FREED.
203 * name is owned by caller, COPIED if needed, and FREED by PortMidi.
204 * Caller is resposible for freeing name when pm_add_device returns.
205 *
206 * returns pmInvalidDeviceId if device memory is exceeded or a virtual
207 * device would take the name of an existing device.
208 * otherwise returns index (portmidi device_id) of the added device
209 */
210PmError pm_add_device(char *interf, const char *name, int is_input,
211 int is_virtual, void *descriptor, pm_fns_type dictionary) {
212 /* printf("pm_add_device: %s %s %d %p %p\n",
213 interf, name, is_input, descriptor, dictionary); */
214 int device_id;
215 PmDeviceInfo *d;
216 /* if virtual, search for duplicate name or unused ID; otherwise,
217 * just add a new device at the next integer available:
218 */
219 for (device_id = (is_virtual ? 0 : pm_descriptor_len);
220 device_id < pm_descriptor_len; device_id++) {
221 d = &pm_descriptors[device_id].pub;
222 d->structVersion = PM_DEVICEINFO_VERS;
223 if (strcmp(d->interf, interf) == 0 && strcmp(d->name, name) == 0) {
224 /* only reuse a name if it is a deleted virtual device with
225 * a matching direction (input or output) */
226 if (pm_descriptors[device_id].deleted && is_input == d->input) {
227 /* here, we know d->is_virtual because only virtual devices
228 * can be deleted, and we know is_virtual because we are
229 * in this loop.
230 */
231 pm_free((void *) d->name); /* reuse this device entry */
232 d->name = NULL;
233 break;
234 /* name conflict exists if the new device appears to others as
235 * the same direction (input or output) as the existing device.
236 * Note that virtual inputs appear to others as outputs and
237 * vice versa.
238 * The direction of the new virtual device to others is "output"
239 * if is_input, i.e., virtual inputs appear to others as outputs.
240 * The existing device appears to others as "output" if
241 * (d->is_virtual == d->input) by the same logic.
242 * The compare will detect if device directions are the same:
243 */
244 } else if (is_input == (d->is_virtual == d->input)) {
245 return pmNameConflict;
246 }
247 }
248 }
249 if (device_id >= pm_descriptor_max) {
250 // expand pm_descriptors
251 descriptor_type new_descriptors = (descriptor_type)
252 pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
253 if (!new_descriptors) return pmInsufficientMemory;
254 if (pm_descriptors) {
255 memcpy(new_descriptors, pm_descriptors,
256 sizeof(descriptor_node) * pm_descriptor_max);
257 pm_free(pm_descriptors);
258 }
259 pm_descriptor_max += 32;
260 pm_descriptors = new_descriptors;
261 }
262 if (device_id == pm_descriptor_len) {
263 pm_descriptor_len++; /* extending array of pm_descriptors */
264 }
265 d = &pm_descriptors[device_id].pub;
266 d->interf = interf;
267 d->name = pm_alloc(strlen(name) + 1);
268 if (!d->name) {
269 return pmInsufficientMemory;
270 }
271#if defined(WIN32) && !defined(_WIN32)
272#pragma warning(suppress: 4996) // don't use suggested strncpy_s
273#endif
274 strcpy(d->name, name);
275 d->input = is_input;
276 d->output = !is_input;
277 d->is_virtual = FALSE; /* caller should set to TRUE if this is virtual */
278
279 /* default state: nothing to close (for automatic device closing) */
280 d->opened = FALSE;
281
282 pm_descriptors[device_id].deleted = FALSE;
283
284 /* ID number passed to win32 multimedia API open */
285 pm_descriptors[device_id].descriptor = descriptor;
286
287 /* points to PmInternal, allows automatic device closing */
288 pm_descriptors[device_id].pm_internal = NULL;
289
290 pm_descriptors[device_id].dictionary = dictionary;
291
292 /* set the defaults to the first input and output we see */
293 if (is_input && pm_default_input_device_id == -1) {
294 pm_default_input_device_id = device_id;
295 } else if (!is_input && pm_default_output_device_id == -1) {
296 pm_default_output_device_id = device_id;
297 }
298
299 return device_id;
300}
301
302
303/* Undo a successful call to pm_add_device(). If a new device was
304 * allocated, it must be the last device in pm_descriptors, so it is
305 * easy to delete by decrementing the length of pm_descriptors, but
306 * first free the name (which was copied to the heap). Otherwise,
307 * the device must be a virtual device that was created previously
308 * and is in the interior of the array of pm_descriptors. Leave it,
309 * but mark it as deleted.
310 */
311void pm_undo_add_device(int id)
312{
313 /* Clear some fields (not all are strictly necessary) */
314 pm_descriptors[id].deleted = TRUE;
315 pm_descriptors[id].descriptor = NULL;
316 pm_descriptors[id].pm_internal = NULL;
317
318 if (id == pm_descriptor_len - 1) {
319 pm_free(pm_descriptors[id].pub.name);
320 pm_descriptor_len--;
321 }
322}
323
324
325/* utility to look up device, given a pattern,
326 note: pattern is modified
327 */
328int Pm_FindDevice(char *pattern, int is_input)
329{
330 int id = pmNoDevice;
331 int i;
332 /* first parse pattern into name, interf parts */
333 char *interf_pref = ""; /* initially assume it is not there */
334 char *name_pref = strstr(pattern, ", ");
335
336 if (name_pref) { /* found separator, adjust the pointer */
337 interf_pref = pattern;
338 name_pref[0] = 0;
339 name_pref += 2;
340 } else {
341 name_pref = pattern; /* whole string is the name pattern */
342 }
343 for (i = 0; i < pm_descriptor_len; i++) {
344 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
345 if (info->input == is_input &&
346 strstr(info->name, name_pref) &&
347 strstr(info->interf, interf_pref)) {
348 id = i;
349 break;
350 }
351 }
352 return id;
353}
354
355
356/*
357====================================================================
358portmidi implementation
359====================================================================
360*/
361
362PMEXPORT int Pm_CountDevices(void)
363{
364 Pm_Initialize();
365 /* no error checking -- Pm_Initialize() does not fail */
366 return pm_descriptor_len;
367}
368
369
370PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo(PmDeviceID id)
371{
372 Pm_Initialize(); /* no error check needed */
373 if (id >= 0 && id < pm_descriptor_len && !pm_descriptors[id].deleted) {
374 return &pm_descriptors[id].pub;
375 }
376 return NULL;
377}
378
379/* pm_success_fn -- "noop" function pointer */
380PmError pm_success_fn(PmInternal *midi)
381{
382 return pmNoError;
383}
384
385/* none_write -- returns an error if called */
386PmError none_write_short(PmInternal *midi, PmEvent *buffer)
387{
388 return pmBadPtr;
389}
390
391/* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
392PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp)
393{
394 return pmBadPtr;
395}
396
397PmError none_write_byte(PmInternal *midi, unsigned char byte,
398 PmTimestamp timestamp)
399{
400 return pmBadPtr;
401}
402
403/* pm_fail_fn -- generic function, returns error if called */
404PmError pm_fail_fn(PmInternal *midi)
405{
406 return pmBadPtr;
407}
408
409static PmError none_open(PmInternal *midi, void *driverInfo)
410{
411 return pmBadPtr;
412}
413
414static unsigned int none_check_host_error(PmInternal * midi)
415{
416 return FALSE;
417}
418
419PmTimestamp none_synchronize(PmInternal *midi)
420{
421 return 0;
422}
423
424#define none_abort pm_fail_fn
425#define none_close pm_fail_fn
426
427pm_fns_node pm_none_dictionary = {
428 none_write_short,
429 none_sysex,
430 none_sysex,
431 none_write_byte,
432 none_write_short,
433 none_write_flush,
434 none_synchronize,
435 none_open,
436 none_abort,
437 none_close,
438 none_poll,
439 none_check_host_error,
440};
441
442
443PMEXPORT const char *Pm_GetErrorText(PmError errnum)
444{
445 const char *msg;
446
447 switch(errnum)
448 {
449 case pmNoError:
450 msg = "";
451 break;
452 case pmHostError:
453 msg = "PortMidi: Host error";
454 break;
455 case pmInvalidDeviceId:
456 msg = "PortMidi: Invalid device ID";
457 break;
458 case pmInsufficientMemory:
459 msg = "PortMidi: Insufficient memory";
460 break;
461 case pmBufferTooSmall:
462 msg = "PortMidi: Buffer too small";
463 break;
464 case pmBadPtr:
465 msg = "PortMidi: Bad pointer";
466 break;
467 case pmInternalError:
468 msg = "PortMidi: Internal PortMidi Error";
469 break;
470 case pmBufferOverflow:
471 msg = "PortMidi: Buffer overflow";
472 break;
473 case pmBadData:
474 msg = "PortMidi: Invalid MIDI message Data";
475 break;
476 case pmBufferMaxSize:
477 msg = "PortMidi: Buffer cannot be made larger";
478 break;
479 case pmNotImplemented:
480 msg = "PortMidi: Function is not implemented";
481 break;
482 case pmInterfaceNotSupported:
483 msg = "PortMidi: Interface not supported";
484 break;
485 case pmNameConflict:
486 msg = "PortMidi: Cannot create virtual device: name is taken";
487 break;
488 case pmDeviceRemoved:
489 msg = "PortMidi: Output attempted after (USB) device removed";
490 break;
491 default:
492 msg = "PortMidi: Illegal error number";
493 break;
494 }
495 return msg;
496}
497
498
499/* This can be called whenever you get a pmHostError return value
500 * or TRUE from Pm_HasHostError().
501 * The error will always be in the global pm_hosterror_text.
502 */
503PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len)
504{
505 assert(msg);
506 assert(len > 0);
507 if (pm_hosterror) {
508#if defined(WIN32) && !defined(_WIN32)
509#pragma warning(suppress: 4996) // don't use suggested strncpy_s
510#endif
511 strncpy(msg, (char *) pm_hosterror_text, len);
512 pm_hosterror = FALSE;
513 pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
514 might help with debugging */
515 msg[len - 1] = 0; /* make sure string is terminated */
516 } else {
517 msg[0] = 0; /* no string to return */
518 }
519}
520
521
522PMEXPORT int Pm_HasHostError(PortMidiStream * stream)
523{
524 if (pm_hosterror) return TRUE;
525 if (stream) {
526 PmInternal * midi = (PmInternal *) stream;
527 return (*midi->dictionary->check_host_error)(midi);
528 }
529 return FALSE;
530}
531
532
533PMEXPORT PmError Pm_Initialize(void)
534{
535 if (!pm_initialized) {
536 pm_descriptor_len = 0;
537 pm_interf_list_len = 0;
538 pm_hosterror = FALSE;
539 pm_hosterror_text[0] = 0; /* the null string */
540 pm_init();
541 pm_initialized = TRUE;
542 }
543 return pmNoError;
544}
545
546
547PMEXPORT PmError Pm_Terminate(void)
548{
549 if (pm_initialized) {
550 pm_term();
551 /* if there are no devices, pm_descriptors might still be NULL */
552 if (pm_descriptors != NULL) {
553 int i; /* free names copied into pm_descriptors */
554 for (i = 0; i < pm_descriptor_len; i++) {
555 if (pm_descriptors[i].pub.name) {
556 pm_free(pm_descriptors[i].pub.name);
557 }
558 }
559 pm_free(pm_descriptors);
560 pm_descriptors = NULL;
561 }
562 pm_descriptor_len = 0;
563 pm_descriptor_max = 0;
564 pm_interf_list_len = 0;
565 pm_initialized = FALSE;
566 }
567 return pmNoError;
568}
569
570
571/* Pm_Read -- read up to length messages from source into buffer */
572/*
573 * returns number of messages actually read, or error code
574 */
575PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length)
576{
577 PmInternal *midi = (PmInternal *) stream;
578 int n = 0;
579 PmError err = pmNoError;
580 pm_hosterror = FALSE;
581 /* arg checking */
582 if(midi == NULL)
583 err = pmBadPtr;
584 else if(!pm_descriptors[midi->device_id].pub.opened)
585 err = pmBadPtr;
586 else if(!pm_descriptors[midi->device_id].pub.input)
587 err = pmBadPtr;
588 /* First poll for data in the buffer...
589 * This either simply checks for data, or attempts first to fill the buffer
590 * with data from the MIDI hardware; this depends on the implementation.
591 * We could call Pm_Poll here, but that would redo a lot of redundant
592 * parameter checking, so I copied some code from Pm_Poll to here: */
593 else err = (*(midi->dictionary->poll))(midi);
594
595 if (err != pmNoError) {
596 if (err == pmHostError) {
597 midi->dictionary->check_host_error(midi);
598 }
599 return pm_errmsg(err);
600 }
601
602 while (n < length) {
603 err = Pm_Dequeue(midi->queue, buffer++);
604 if (err == pmBufferOverflow) {
605 /* ignore the data we have retreived so far */
606 return pm_errmsg(pmBufferOverflow);
607 } else if (err == 0) { /* empty queue */
608 break;
609 }
610 n++;
611 }
612 return n;
613}
614
615PMEXPORT PmError Pm_Poll(PortMidiStream *stream)
616{
617 PmInternal *midi = (PmInternal *) stream;
618 PmError err;
619
620 pm_hosterror = FALSE;
621 /* arg checking */
622 if(midi == NULL)
623 err = pmBadPtr;
624 else if (!pm_descriptors[midi->device_id].pub.opened)
625 err = pmBadPtr;
626 else if (!pm_descriptors[midi->device_id].pub.input)
627 err = pmBadPtr;
628 else
629 err = (*(midi->dictionary->poll))(midi);
630
631 if (err != pmNoError) {
632 return pm_errmsg(err);
633 }
634
635 return (PmError) !Pm_QueueEmpty(midi->queue);
636}
637
638
639/* this is called from Pm_Write and Pm_WriteSysEx to issue a
640 * call to the system-dependent end_sysex function and handle
641 * the error return
642 */
643static PmError pm_end_sysex(PmInternal *midi)
644{
645 PmError err = (*midi->dictionary->end_sysex)(midi, 0);
646 midi->sysex_in_progress = FALSE;
647 return err;
648}
649
650
651/* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
652 Pm_WriteSysEx all operate a state machine that "outputs" calls to
653 write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
654
655PMEXPORT PmError Pm_Write(PortMidiStream *stream, PmEvent *buffer,
656 int32_t length)
657{
658 PmInternal *midi = (PmInternal *) stream;
659 PmError err = pmNoError;
660 int i;
661 int bits;
662
663 pm_hosterror = FALSE;
664 /* arg checking */
665 if (midi == NULL) {
666 err = pmBadPtr;
667 } else {
668 descriptor_type desc = &pm_descriptors[midi->device_id];
669 if (!desc || !desc->pub.opened ||
670 !desc->pub.output || !desc->pm_internal) {
671 err = pmBadPtr;
672 } else if (desc->pm_internal->is_removed) {
673 err = pmDeviceRemoved;
674 }
675 }
676 if (err != pmNoError) goto pm_write_error;
677
678 if (midi->latency == 0) {
679 midi->now = 0;
680 } else {
681 midi->now = (*(midi->time_proc))(midi->time_info);
682 if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
683 /* time to resync */
684 midi->now = (*midi->dictionary->synchronize)(midi);
685 midi->first_message = FALSE;
686 }
687 }
688 /* error recovery: when a sysex is detected, we call
689 * dictionary->begin_sysex() followed by calls to
690 * dictionary->write_byte() and dictionary->write_realtime()
691 * until an end-of-sysex is detected, when we call
692 * dictionary->end_sysex(). After an error occurs,
693 * Pm_Write() continues to call functions. For example,
694 * it will continue to call write_byte() even after
695 * an error sending a sysex message, and end_sysex() will be
696 * called when an EOX or non-real-time status is found.
697 * When errors are detected, Pm_Write() returns immediately,
698 * so it is possible that this will drop data and leave
699 * sysex messages in a partially transmitted state.
700 */
701 for (i = 0; i < length; i++) {
702 uint32_t msg = buffer[i].message;
703 bits = 0;
704 /* is this a sysex message? */
705 if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
706 if (midi->sysex_in_progress) {
707 /* error: previous sysex was not terminated by EOX */
708 midi->sysex_in_progress = FALSE;
709 err = pmBadData;
710 goto pm_write_error;
711 }
712 midi->sysex_in_progress = TRUE;
713 if ((err = (*midi->dictionary->begin_sysex)(midi,
714 buffer[i].timestamp)) != pmNoError)
715 goto pm_write_error;
716 if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
717 buffer[i].timestamp)) != pmNoError)
718 goto pm_write_error;
719 bits = 8;
720 /* fall through to continue sysex processing */
721 } else if ((msg & MIDI_STATUS_MASK) &&
722 (Pm_MessageStatus(msg) != MIDI_EOX)) {
723 /* a non-sysex message */
724 if (midi->sysex_in_progress) {
725 /* this should be a realtime message */
726 if (is_real_time(msg)) {
727 if ((err = (*midi->dictionary->write_realtime)(midi,
728 &(buffer[i]))) != pmNoError)
729 goto pm_write_error;
730 } else {
731 midi->sysex_in_progress = FALSE;
732 err = pmBadData;
733 /* ignore any error from this, because we already have one */
734 /* pass 0 as timestamp -- it's ignored */
735 (*midi->dictionary->end_sysex)(midi, 0);
736 goto pm_write_error;
737 }
738 } else { /* regular short midi message */
739 if ((err = (*midi->dictionary->write_short)(midi,
740 &(buffer[i]))) != pmNoError)
741 goto pm_write_error;
742 continue;
743 }
744 }
745 if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
746 /* see if we can accelerate data transfer */
747 if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
748 (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
749 (msg & 0x80808080) == 0) { /* all data */
750 /* copy 4 bytes from msg to fill_base + fill_offset */
751 unsigned char *ptr = midi->fill_base +
752 *(midi->fill_offset_ptr);
753 ptr[0] = msg; ptr[1] = msg >> 8;
754 ptr[2] = msg >> 16; ptr[3] = msg >> 24;
755 (*midi->fill_offset_ptr) += 4;
756 continue;
757 }
758 /* no acceleration, so do byte-by-byte copying */
759 while (bits < 32) {
760 unsigned char midi_byte = (unsigned char) (msg >> bits);
761 if ((err = (*midi->dictionary->write_byte)(midi, midi_byte,
762 buffer[i].timestamp)) != pmNoError)
763 goto pm_write_error;
764 if (midi_byte == MIDI_EOX) {
765 err = pm_end_sysex(midi);
766 if (err != pmNoError) goto error_exit;
767 break; /* from while loop */
768 }
769 bits += 8;
770 }
771 } else {
772 /* not in sysex mode, but message did not start with status */
773 err = pmBadData;
774 goto pm_write_error;
775 }
776 }
777 /* after all messages are processed, send the data */
778 if (!midi->sysex_in_progress)
779 err = (*midi->dictionary->write_flush)(midi, 0);
780pm_write_error:
781 if (err == pmHostError) {
782 midi->dictionary->check_host_error(midi);
783 }
784error_exit:
785 return pm_errmsg(err);
786}
787
788
789PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when,
790 PmMessage msg)
791{
792 PmEvent event;
793
794 event.timestamp = when;
795 event.message = msg;
796 return Pm_Write(stream, &event, 1);
797}
798
799
800PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
801 unsigned char *msg)
802{
803 /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
804 /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
805 #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
806 PmEvent buffer[BUFLEN];
807 int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
808 PmInternal *midi = (PmInternal *) stream;
809 PmError err = pmNoError;
810 /* the next byte in the buffer is represented by an index, bufx, and
811 a shift in bits */
812 int shift = 0;
813 int bufx = 0;
814 buffer[0].message = 0;
815 buffer[0].timestamp = when;
816
817 while (1) {
818 /* insert next byte into buffer */
819 buffer[bufx].message |= ((*msg) << shift);
820 shift += 8;
821 if (*msg++ == MIDI_EOX) break;
822 if (shift == 32) {
823 shift = 0;
824 bufx++;
825 if (bufx == buffer_size) {
826 err = Pm_Write(stream, buffer, buffer_size);
827 /* note: Pm_Write has already called errmsg() */
828 if (err) return err;
829 /* prepare to fill another buffer */
830 bufx = 0;
831 buffer_size = BUFLEN;
832 /* optimization: maybe we can just copy bytes */
833 if (midi->fill_base) {
834 while (*(midi->fill_offset_ptr) < midi->fill_length) {
835 midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
836 if (*msg++ == MIDI_EOX) {
837 err = pm_end_sysex(midi);
838 if (err != pmNoError) return pm_errmsg(err);
839 goto end_of_sysex;
840 }
841 }
842 /* I thought that I could do a pm_Write here and
843 * change this if to a loop, avoiding calls in Pm_Write
844 * to the slower write_byte, but since
845 * sysex_in_progress is true, this will not flush
846 * the buffer, and we'll infinite loop: */
847 /* err = Pm_Write(stream, buffer, 0);
848 if (err) return err; */
849 /* instead, the way this works is that Pm_Write calls
850 * write_byte on 4 bytes. The first, since the buffer
851 * is full, will flush the buffer and allocate a new
852 * one. This primes the buffer so
853 * that we can return to the loop above and fill it
854 * efficiently without a lot of function calls.
855 */
856 buffer_size = 1; /* get another message started */
857 }
858 }
859 buffer[bufx].message = 0;
860 buffer[bufx].timestamp = when;
861 }
862 /* keep inserting bytes until you find MIDI_EOX */
863 }
864end_of_sysex:
865 /* we're finished sending full buffers, but there may
866 * be a partial one left.
867 */
868 if (shift != 0) bufx++; /* add partial message to buffer len */
869 if (bufx) { /* bufx is number of PmEvents to send from buffer */
870 err = Pm_Write(stream, buffer, bufx);
871 if (err) return err;
872 }
873 return pmNoError;
874}
875
876
877
878PmError pm_create_internal(PmInternal **stream, PmDeviceID device_id,
879 int is_input, int latency, PmTimeProcPtr time_proc,
880 void *time_info, int buffer_size)
881{
882 PmInternal *midi;
883 if (device_id < 0 || device_id >= pm_descriptor_len) {
884 return pmInvalidDeviceId;
885 }
886 if (latency < 0) { /* force a legal value */
887 latency = 0;
888 }
889 /* create portMidi internal data */
890 midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
891 *stream = midi;
892 if (!midi) {
893 return pmInsufficientMemory;
894 }
895 midi->device_id = device_id;
896 midi->is_input = is_input;
897 midi->is_removed = FALSE;
898 midi->time_proc = time_proc;
899 /* if latency != 0, we need a time reference for output.
900 we always need a time reference for input.
901 If none is provided, use PortTime library */
902 if (time_proc == NULL && (latency != 0 || is_input)) {
903 if (!Pt_Started())
904 Pt_Start(1, 0, 0);
905 /* time_get does not take a parameter, so coerce */
906 midi->time_proc = (PmTimeProcPtr) Pt_Time;
907 }
908 midi->time_info = time_info;
909 if (is_input) {
910 midi->latency = 0; /* unused by input */
911 if (buffer_size <= 0) buffer_size = 256; /* default buffer size */
912 midi->queue = Pm_QueueCreate(buffer_size, (int32_t) sizeof(PmEvent));
913 if (!midi->queue) {
914 /* free portMidi data */
915 *stream = NULL;
916 pm_free(midi);
917 return pmInsufficientMemory;
918 }
919 } else {
920 /* if latency zero, output immediate (timestamps ignored) */
921 /* if latency < 0, use 0 but don't return an error */
922 if (latency < 0) latency = 0;
923 midi->latency = latency;
924 midi->queue = NULL; /* unused by output; input needs to allocate: */
925 }
926 midi->buffer_len = buffer_size; /* portMidi input storage */
927 midi->sysex_in_progress = FALSE;
928 midi->message = 0;
929 midi->message_count = 0;
930 midi->filters = (is_input ? PM_FILT_ACTIVE : 0);
931 midi->channel_mask = 0xFFFF;
932 midi->sync_time = 0;
933 midi->first_message = TRUE;
934 midi->api_info = NULL;
935 midi->fill_base = NULL;
936 midi->fill_offset_ptr = NULL;
937 midi->fill_length = 0;
938 midi->dictionary = pm_descriptors[device_id].dictionary;
939 pm_descriptors[device_id].pm_internal = midi;
940 return pmNoError;
941}
942
943
944PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
945 PmDeviceID inputDevice,
946 void *inputDriverInfo,
947 int32_t bufferSize,
948 PmTimeProcPtr time_proc,
949 void *time_info)
950{
951 PmInternal *midi;
952 PmError err = pmNoError;
953 pm_hosterror = FALSE;
954 *stream = NULL; /* invariant: *stream == midi */
955
956 /* arg checking */
957 if (!pm_descriptors[inputDevice].pub.input)
958 err = pmInvalidDeviceId;
959 else if (pm_descriptors[inputDevice].pub.opened)
960 err = pmInvalidDeviceId;
961 if (err != pmNoError)
962 goto error_return;
963
964 /* common initialization of PmInternal structure (midi): */
965 err = pm_create_internal(&midi, inputDevice, TRUE, 0, time_proc,
966 time_info, bufferSize);
967 *stream = midi;
968 if (err) {
969 goto error_return;
970 }
971
972 /* open system dependent input device */
973 err = (*midi->dictionary->open)(midi, inputDriverInfo);
974 if (err) {
975 *stream = NULL;
976 pm_descriptors[inputDevice].pm_internal = NULL;
977 /* free portMidi data */
978 Pm_QueueDestroy(midi->queue);
979 pm_free(midi);
980 } else {
981 /* portMidi input open successful */
982 pm_descriptors[inputDevice].pub.opened = TRUE;
983 }
984error_return:
985 /* note: if there is a pmHostError, it is the responsibility
986 * of the system-dependent code (*midi->dictionary->open)()
987 * to set pm_hosterror and pm_hosterror_text
988 */
989 return pm_errmsg(err);
990}
991
992
993PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
994 PmDeviceID outputDevice,
995 void *outputDriverInfo,
996 int32_t bufferSize,
997 PmTimeProcPtr time_proc,
998 void *time_info,
999 int32_t latency)
1000{
1001 PmInternal *midi;
1002 PmError err = pmNoError;
1003 pm_hosterror = FALSE;
1004 *stream = NULL;
1005
1006 /* arg checking */
1007 if (outputDevice < 0 || outputDevice >= pm_descriptor_len)
1008 err = pmInvalidDeviceId;
1009 else if (!pm_descriptors[outputDevice].pub.output)
1010 err = pmInvalidDeviceId;
1011 else if (pm_descriptors[outputDevice].pub.opened)
1012 err = pmInvalidDeviceId;
1013 if (err != pmNoError)
1014 goto error_return;
1015
1016 /* common initialization of PmInternal structure (midi): */
1017 err = pm_create_internal(&midi, outputDevice, FALSE, latency, time_proc,
1018 time_info, bufferSize);
1019 *stream = midi;
1020 if (err) {
1021 goto error_return;
1022 }
1023
1024 /* open system dependent output device */
1025 err = (*midi->dictionary->open)(midi, outputDriverInfo);
1026 if (err) {
1027 *stream = NULL;
1028 pm_descriptors[outputDevice].pm_internal = NULL;
1029 /* free portMidi data */
1030 pm_free(midi);
1031 } else {
1032 /* portMidi input open successful */
1033 pm_descriptors[outputDevice].pub.opened = TRUE;
1034 }
1035error_return:
1036 /* note: system-dependent code must set pm_hosterror and
1037 * pm_hosterror_text if a pmHostError occurs
1038 */
1039 return pm_errmsg(err);
1040}
1041
1042
1043static PmError create_virtual_device(const char *name, const char *interf,
1044 void *device_info, int is_input)
1045{
1046 PmError err = pmNoError;
1047 int i;
1048 pm_hosterror = FALSE;
1049
1050 /* arg checking */
1051 if (!name) {
1052 err = pmInvalidDeviceId;
1053 goto error_return;
1054 }
1055
1056 Pm_Initialize(); /* just in case */
1057
1058 /* create the virtual device */
1059 if (pm_interf_list_len == 0) {
1060 return pmNotImplemented;
1061 }
1062 if (!interf) {
1063 /* default interface is the first one */
1064 interf = pm_interf_list[0].interf;
1065 }
1066 /* look up and call the create_fn for interf(ace), e.g. "CoreMIDI" */
1067 for (i = 0; i < pm_interf_list_len; i++) {
1068 if (strcmp(pm_interf_list[i].interf, interf) == 0) {
1069 int id = (*pm_interf_list[i].create_fn)(is_input,
1070 name, device_info);
1071 /* id could be pmNameConflict or an actual descriptor index */
1072 if (id >= 0) {
1073 pm_descriptors[id].pub.is_virtual = TRUE;
1074 }
1075 err = id;
1076 goto error_return;
1077 }
1078 }
1079 err = pmInterfaceNotSupported;
1080
1081error_return:
1082 /* note: if there is a pmHostError, it is the responsibility
1083 * of the system-dependent code (*midi->dictionary->open)()
1084 * to set pm_hosterror and pm_hosterror_text
1085 */
1086 return pm_errmsg(err);
1087}
1088
1089
1090PMEXPORT PmError Pm_CreateVirtualInput(const char *name,
1091 const char *interf,
1092 void *deviceInfo)
1093{
1094 return create_virtual_device(name, interf, deviceInfo, TRUE);
1095}
1096
1097PMEXPORT PmError Pm_CreateVirtualOutput(const char *name, const char *interf,
1098 void *deviceInfo)
1099{
1100 return create_virtual_device(name, interf, deviceInfo, FALSE);
1101}
1102
1103PmError Pm_DeleteVirtualDevice(PmDeviceID id)
1104{
1105 int i;
1106 const char *interf = pm_descriptors[id].pub.interf;
1107 PmError err = pmBadData; /* returned if we cannot find the interface-
1108 * specific delete function */
1109 /* arg checking */
1110 if (id < 0 || id >= pm_descriptor_len ||
1111 pm_descriptors[id].pub.opened || pm_descriptors[id].deleted) {
1112 return pmInvalidDeviceId;
1113 }
1114 /* delete function pointer is in interfaces list */
1115 for (i = 0; i < pm_interf_list_len; i++) {
1116 if (strcmp(pm_interf_list[i].interf, interf) == 0) {
1117 err = (*pm_interf_list[i].delete_fn)(id);
1118 break;
1119 }
1120 }
1121 pm_descriptors[id].deleted = TRUE;
1122 /* (pm_internal should already be NULL because !pub.opened) */
1123 pm_descriptors[id].pm_internal = NULL;
1124 pm_descriptors[id].descriptor = NULL;
1125 return err;
1126}
1127
1128PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
1129{
1130 PmInternal *midi = (PmInternal *) stream;
1131 PmError err = pmNoError;
1132
1133 if (midi == NULL)
1134 err = pmBadPtr;
1135 else
1136 midi->channel_mask = mask;
1137
1138 return pm_errmsg(err);
1139}
1140
1141
1142PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters)
1143{
1144 PmInternal *midi = (PmInternal *) stream;
1145 PmError err = pmNoError;
1146
1147 /* arg checking */
1148 if (midi == NULL)
1149 err = pmBadPtr;
1150 else if (!pm_descriptors[midi->device_id].pub.opened)
1151 err = pmBadPtr;
1152 else
1153 midi->filters = filters;
1154 return pm_errmsg(err);
1155}
1156
1157
1158PMEXPORT PmError Pm_Close(PortMidiStream *stream)
1159{
1160 PmInternal *midi = (PmInternal *) stream;
1161 PmError err = pmNoError;
1162
1163 pm_hosterror = FALSE;
1164 /* arg checking */
1165 if (midi == NULL) /* midi must point to something */
1166 err = pmBadPtr;
1167 /* if it is an open device, the device_id will be valid */
1168 else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_len)
1169 err = pmBadPtr;
1170 /* and the device should be in the opened state */
1171 else if (!pm_descriptors[midi->device_id].pub.opened)
1172 err = pmBadPtr;
1173
1174 if (err != pmNoError)
1175 goto error_return;
1176
1177 /* close the device */
1178 err = (*midi->dictionary->close)(midi);
1179 /* even if an error occurred, continue with cleanup */
1180 pm_descriptors[midi->device_id].pm_internal = NULL;
1181 pm_descriptors[midi->device_id].pub.opened = FALSE;
1182 if (midi->queue) Pm_QueueDestroy(midi->queue);
1183 pm_free(midi);
1184error_return:
1185 /* system dependent code must set pm_hosterror and
1186 * pm_hosterror_text if a pmHostError occurs.
1187 */
1188 return pm_errmsg(err);
1189}
1190
1191PmError Pm_Synchronize(PortMidiStream* stream)
1192{
1193 PmInternal *midi = (PmInternal *) stream;
1194 PmError err = pmNoError;
1195 if (midi == NULL)
1196 err = pmBadPtr;
1197 else if (!pm_descriptors[midi->device_id].pub.output)
1198 err = pmBadPtr;
1199 else if (!pm_descriptors[midi->device_id].pub.opened)
1200 err = pmBadPtr;
1201 else
1202 midi->first_message = TRUE;
1203 return err;
1204}
1205
1206PMEXPORT PmError Pm_Abort(PortMidiStream* stream)
1207{
1208 PmInternal *midi = (PmInternal *) stream;
1209 PmError err;
1210 /* arg checking */
1211 if (midi == NULL)
1212 err = pmBadPtr;
1213 else if (!pm_descriptors[midi->device_id].pub.output)
1214 err = pmBadPtr;
1215 else if (!pm_descriptors[midi->device_id].pub.opened)
1216 err = pmBadPtr;
1217 else
1218 err = (*midi->dictionary->abort)(midi);
1219
1220 if (err == pmHostError) {
1221 midi->dictionary->check_host_error(midi);
1222 }
1223 return pm_errmsg(err);
1224}
1225
1226
1227
1228/* pm_channel_filtered returns non-zero if the channel mask is
1229 blocking the current channel */
1230#define pm_channel_filtered(status, mask) \
1231 ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
1232
1233
1234/* The following two functions will checks to see if a MIDI message
1235 matches the filtering criteria. Since the sysex routines only want
1236 to filter realtime messages, we need to have separate routines.
1237 */
1238
1239
1240/* pm_realtime_filtered returns non-zero if the filter will kill the
1241 current message. Note that only realtime messages are checked here.
1242 */
1243#define pm_realtime_filtered(status, filters) \
1244 ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
1245
1246/*
1247 return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
1248 || ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
1249 || ((status == MIDI_START) && (filters & PM_FILT_PLAY))
1250 || ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
1251 || ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
1252 || ((status == MIDI_F9) && (filters & PM_FILT_F9))
1253 || ((status == MIDI_FD) && (filters & PM_FILT_FD))
1254 || ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
1255 || ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
1256 || ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
1257 || ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
1258 || ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
1259}*/
1260
1261
1262/* pm_status_filtered returns non-zero if a filter will kill the
1263 current message, based on status. Note that sysex and real time are
1264 not checked. It is up to the subsystem (winmm, core midi, alsa) to
1265 filter sysex, as it is handled more easily and efficiently at that
1266 level. Realtime message are filtered in pm_realtime_filtered.
1267 */
1268#define pm_status_filtered(status, filters) \
1269 ((1 << (16 + ((status) >> 4))) & (filters))
1270
1271
1272/*
1273 return ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
1274 || ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
1275 || ((status == MIDI_CHANNEL_AT) &&
1276 (filters & PM_FILT_CHANNEL_AFTERTOUCH))
1277 || ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
1278 || ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
1279 || ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
1280 || ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
1281
1282}
1283*/
1284
1285static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
1286{
1287 PmEvent event;
1288
1289 /* there may be nothing in the buffer */
1290 if (midi->message_count == 0) return; /* nothing to flush */
1291
1292 event.message = midi->message;
1293 event.timestamp = timestamp;
1294 /* copied from pm_read_short, avoids filtering */
1295 if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
1296 midi->sysex_in_progress = FALSE;
1297 }
1298 midi->message_count = 0;
1299 midi->message = 0;
1300}
1301
1302
1303/* pm_read_short and pm_read_bytes
1304 are the interface between system-dependent MIDI input handlers
1305 and the system-independent PortMIDI code.
1306 The input handler MUST obey these rules:
1307 1) all short input messages must be sent to pm_read_short, which
1308 enqueues them to a FIFO for the application.
1309 2) each buffer of sysex bytes should be reported by calling pm_read_bytes
1310 (which sets midi->sysex_in_progress). After the eox byte,
1311 pm_read_bytes will clear sysex_in_progress
1312 */
1313
1314/* pm_read_short is the place where all input messages arrive from
1315 system-dependent code such as pmwinmm.c. Here, the messages
1316 are entered into the PortMidi input buffer.
1317 */
1318void pm_read_short(PmInternal *midi, PmEvent *event)
1319{
1320 int status;
1321 /* arg checking */
1322 assert(midi != NULL);
1323 /* midi filtering is applied here */
1324 status = Pm_MessageStatus(event->message);
1325 if (!pm_status_filtered(status, midi->filters)
1326 && (!is_real_time(status) ||
1327 !pm_realtime_filtered(status, midi->filters))
1328 && !pm_channel_filtered(status, midi->channel_mask)) {
1329 /* if sysex is in progress and we get a status byte, it had
1330 better be a realtime message or the starting SYSEX byte;
1331 otherwise, we exit the sysex_in_progress state
1332 */
1333 if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
1334 /* two choices: real-time or not. If it's real-time, then
1335 * this should be delivered as a sysex byte because it is
1336 * embedded in a sysex message
1337 */
1338 if (is_real_time(status)) {
1339 midi->message |= (status << (8 * midi->message_count++));
1340 if (midi->message_count == 4) {
1341 pm_flush_sysex(midi, event->timestamp);
1342 }
1343 } else { /* otherwise, it's not real-time. This interrupts
1344 * a sysex message in progress */
1345 midi->sysex_in_progress = FALSE;
1346 }
1347 } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
1348 midi->sysex_in_progress = FALSE;
1349 }
1350 }
1351}
1352
1353
1354/* pm_read_bytes -- a sequence of bytes has been read from a device.
1355 * parse the bytes into PmEvents and put them in the queue.
1356 * midi - the midi device
1357 * data - the bytes
1358 * len - the number of bytes
1359 * timestamp - when were the bytes received?
1360 *
1361 * returns how many bytes processed, which is always the len parameter
1362 */
1363unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data,
1364 int len, PmTimestamp timestamp)
1365{
1366 int i = 0; /* index into data, must not be unsigned (!) */
1367 PmEvent event;
1368 event.timestamp = timestamp;
1369 assert(midi);
1370
1371 /* Since sysex messages may have embedded real-time messages, we
1372 * cannot simply send every consecutive group of 4 bytes as sysex
1373 * data. Instead, we insert each data byte into midi->message and
1374 * keep count using midi->message_count. If we encounter a
1375 * real-time message, it is sent immediately as a 1-byte PmEvent,
1376 * while sysex bytes are sent as PmEvents in groups of 4 bytes
1377 * until the sysex is either terminated by EOX (F7) or a
1378 * non-real-time message is encountered, indicating that the EOX
1379 * was dropped.
1380 */
1381
1382 /* This is a finite state machine so that we can accept any number
1383 * of bytes, even if they contain partial messages.
1384 *
1385 * midi->sysex_in_progress says we are expecting sysex message bytes
1386 * (otherwise, expect a short message or real-time message)
1387 * midi->message accumulates bytes to enqueue for application
1388 * midi->message_count is the number of bytes accumulated
1389 * midi->short_message_count is how many bytes we need in midi->message,
1390 * therefore midi->message_count, before we have a complete message
1391 * midi->running_status is running status or 0 if there is none
1392 *
1393 * Set running status when: A status byte < F0 is received.
1394 * Clear running status when: A status byte from F0 through F7 is
1395 * received.
1396 * Ignore (drop) data bytes when running status is 0.
1397 *
1398 * Our output buffer (the application input buffer) can overflow
1399 * at any time. If that occurs, we have to clear sysex_in_progress
1400 * (otherwise, the buffer could be flushed and we could resume
1401 * inserting sysex bytes into the buffer, resulting in a continuation
1402 * of a sysex message even though a buffer full of bytes was dropped.)
1403 *
1404 * Since we have to parse everything and form <=4-byte PmMessages,
1405 * we send all messages via pm_read_short, which filters messages
1406 * according to midi->filters and clears sysex_in_progress on
1407 * buffer overflow. This also provides a "short cut" for short
1408 * messages that are already parsed, allowing API-specific code
1409 * to bypass this more expensive state machine. What if we are
1410 * getting a sysex message, but it is interrupted by a short
1411 * message (status 80-EF) and a direct call to pm_read_short?
1412 * Without some care, the state machine would still be in
1413 * sysex_in_progress mode, and subsequent data bytes would be
1414 * accumulated as more sysex data, which is wrong since you
1415 * cannot have a short message in the middle of a sysex message.
1416 * To avoid this problem, pm_read_short clears sysex_in_progress
1417 * when a non-real-time short message arrives.
1418 */
1419
1420 while (i < len) {
1421 unsigned char byte = data[i++];
1422 if (is_real_time(byte)) {
1423 event.message = byte;
1424 pm_read_short(midi, &event);
1425 } else if (byte & MIDI_STATUS_MASK && byte != MIDI_EOX) {
1426 midi->message = byte;
1427 midi->message_count = 1;
1428 if (byte == MIDI_SYSEX) {
1429 midi->sysex_in_progress = TRUE;
1430 } else {
1431 midi->sysex_in_progress = FALSE;
1432 midi->short_message_count = pm_midi_length(midi->message);
1433 /* maybe we're done already with a 1-byte message: */
1434 if (midi->short_message_count == 1) {
1435 pm_read_short(midi, &event);
1436 midi->message_count = 0;
1437 }
1438 }
1439 } else if (midi->sysex_in_progress) { /* sysex data byte */
1440 /* accumulate sysex message data or EOX */
1441 midi->message |= (byte << (8 * midi->message_count++));
1442 if (midi->message_count == 4 || byte == MIDI_EOX) {
1443 event.message = midi->message;
1444 /* enqueue if not filtered, and then if there is overflow,
1445 stop sysex_in_progress */
1446 if (!(midi->filters & PM_FILT_SYSEX) &&
1447 Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
1448 midi->sysex_in_progress = FALSE;
1449 } else if (byte == MIDI_EOX) { /* continue unless EOX */
1450 midi->sysex_in_progress = FALSE;
1451 }
1452 midi->message_count = 0;
1453 midi->message = 0;
1454 }
1455 } else { /* no sysex in progress, must be short message */
1456 if (midi->message_count == 0) { /* need a running status */
1457 if (midi->running_status) {
1458 midi->message = midi->running_status;
1459 midi->message_count = 1;
1460 } else { /* drop data byte - not sysex and no status byte */
1461 continue;
1462 }
1463 }
1464 midi->message |= (byte << (8 * midi->message_count++));
1465 if (midi->message_count == midi->short_message_count) {
1466 event.message = midi->message;
1467 pm_read_short(midi, &event);
1468 }
1469 }
1470 }
1471 return i;
1472}