1 /* pmwinmm.c -- system specific definitions */
4 #pragma warning(disable: 4133) // stop warnings about implicit typecasts
6 #define max(a,b) __max(a,b)
10 /* without this define, InitializeCriticalSectionAndSpinCount is
11 * undefined. This version level means "Windows 2000 and higher"
13 #define _WIN32_WINNT 0x0500
20 #include "pminternal.h"
25 /* asserts used to verify portMidi code logic is sound; later may want
26 something more graceful */
29 /* this printf stuff really important for debugging client app w/host errors.
30 probably want to do something else besides read/write from/to console
31 for portability, however */
36 #define streql(x, y) (strcmp(x, y) == 0)
38 #define MIDI_SYSEX 0xf0
41 /* callback routines */
42 static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,
43 WORD wMsg, DWORD dwInstance,
44 DWORD dwParam1, DWORD dwParam2);
45 static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
46 DWORD dwInstance, DWORD dwParam1,
48 #ifdef USE_SYSEX_BUFFERS
49 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
50 DWORD dwInstance, DWORD dwParam1,
54 extern pm_fns_node pm_winmm_in_dictionary;
55 extern pm_fns_node pm_winmm_out_dictionary;
57 static void winmm_out_delete(PmInternal *midi); /* forward reference */
60 A note about buffers: WinMM seems to hold onto buffers longer than
61 one would expect, e.g. when I tried using 2 small buffers to send
62 long sysex messages, at some point WinMM held both buffers. This problem
63 was fixed by making buffers bigger. Therefore, it seems that there should
64 be enough buffer space to hold a whole sysex message.
66 The bufferSize passed into Pm_OpenInput (passed into here as buffer_len)
67 will be used to estimate the largest sysex message (= buffer_len * 4 bytes).
68 Call that the max_sysex_len = buffer_len * 4.
70 For simple midi output (latency == 0), allocate 3 buffers, each with half
71 the size of max_sysex_len, but each at least 256 bytes.
73 For stream output, there will already be enough space in very short
74 buffers, so use them, but make sure there are at least 16.
76 For input, use many small buffers rather than 2 large ones so that when
77 there are short sysex messages arriving frequently (as in control surfaces)
78 there will be more free buffers to fill. Use max_sysex_len / 64 buffers,
79 but at least 16, of size 64 bytes each.
81 The following constants help to represent these design parameters:
83 #define NUM_SIMPLE_SYSEX_BUFFERS 3
84 #define MIN_SIMPLE_SYSEX_LEN 256
86 #define MIN_STREAM_BUFFERS 16
87 #define STREAM_BUFFER_LEN 24
89 #define INPUT_SYSEX_LEN 64
90 #define MIN_INPUT_BUFFERS 16
92 /* if we run out of space for output (assume this is due to a sysex msg,
93 expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN
95 #define NUM_EXPANSION_BUFFERS 128
96 #define EXPANSION_BUFFER_LEN 1024
98 /* A sysex buffer has 3 DWORDS as a header plus the actual message size */
99 #define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3)
100 /* A MIDIHDR with a sysex message is the buffer length plus the header size */
101 #define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR))
102 #ifdef USE_SYSEX_BUFFERS
103 /* Size of a MIDIHDR with a buffer contaning multiple MIDIEVENT structures */
104 #define MIDIHDR_SIZE(x) ((x) + sizeof(MIDIHDR))
108 ==============================================================================
109 win32 mmedia system specific structure passed to midi callbacks
110 ==============================================================================
113 /* global winmm device info */
114 MIDIINCAPS *midi_in_caps = NULL;
115 MIDIINCAPS midi_in_mapper_caps;
116 UINT midi_num_inputs = 0;
117 MIDIOUTCAPS *midi_out_caps = NULL;
118 MIDIOUTCAPS midi_out_mapper_caps;
119 UINT midi_num_outputs = 0;
121 /* per device info */
122 typedef struct midiwinmm_struct {
124 HMIDISTRM stream; /* windows handle for stream */
125 HMIDIOUT out; /* windows handle for out calls */
126 HMIDIIN in; /* windows handle for in calls */
129 /* midi output messages are sent in these buffers, which are allocated
130 * in a round-robin fashion, using next_buffer as an index
132 LPMIDIHDR *buffers; /* pool of buffers for midi in or out data */
133 int max_buffers; /* length of buffers array */
134 int buffers_expanded; /* buffers array expanded for extra msgs? */
135 int num_buffers; /* how many buffers allocated in buffers array */
136 int next_buffer; /* index of next buffer to send */
137 HANDLE buffer_signal; /* used to wait for buffer to become free */
138 #ifdef USE_SYSEX_BUFFERS
139 /* sysex buffers will be allocated only when
140 * a sysex message is sent. The size of the buffer is fixed.
142 LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */
143 int next_sysex_buffer; /* index of next sysexbuffer to send */
145 unsigned long last_time; /* last output time */
146 int first_message; /* flag: treat first message differently */
147 int sysex_mode; /* middle of sending sysex */
148 unsigned long sysex_word; /* accumulate data when receiving sysex */
149 unsigned int sysex_byte_count; /* count how many received */
150 LPMIDIHDR hdr; /* the message accumulating sysex to send */
151 unsigned long sync_time; /* when did we last determine delta? */
152 long delta; /* difference between stream time and
154 int error; /* host error from doing port midi call */
155 CRITICAL_SECTION lock; /* prevents reentrant callbacks (input only) */
156 } midiwinmm_node, *midiwinmm_type;
160 =============================================================================
161 general MIDI device queries
162 =============================================================================
164 static void pm_winmm_general_inputs()
168 midi_num_inputs = midiInGetNumDevs();
169 midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) *
171 if (midi_in_caps == NULL) {
172 /* if you can't open a particular system-level midi interface
173 * (such as winmm), we just consider that system or API to be
174 * unavailable and move on without reporting an error.
179 for (i = 0; i < midi_num_inputs; i++) {
180 wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],
182 if (wRtn == MMSYSERR_NOERROR) {
183 /* ignore errors here -- if pm_descriptor_max is exceeded, some
184 devices will not be accessible. */
185 pm_add_device("MMSystem", midi_in_caps[i].szPname, TRUE,
186 (void *) i, &pm_winmm_in_dictionary);
192 static void pm_winmm_mapper_input()
195 /* Note: if MIDIMAPPER opened as input (documentation implies you
196 can, but current system fails to retrieve input mapper
197 capabilities) then you still should retrieve some formof
199 wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,
200 (LPMIDIINCAPS) & midi_in_mapper_caps,
202 if (wRtn == MMSYSERR_NOERROR) {
203 pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE,
204 (void *) MIDIMAPPER, &pm_winmm_in_dictionary);
209 static void pm_winmm_general_outputs()
213 midi_num_outputs = midiOutGetNumDevs();
214 midi_out_caps = (MIDIOUTCAPS*)pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs );
216 if (midi_out_caps == NULL) {
217 /* no error is reported -- see pm_winmm_general_inputs */
221 for (i = 0; i < midi_num_outputs; i++) {
222 wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i],
223 sizeof(MIDIOUTCAPS));
224 if (wRtn == MMSYSERR_NOERROR) {
225 pm_add_device("MMSystem", midi_out_caps[i].szPname, FALSE,
226 (void *) i, &pm_winmm_out_dictionary);
232 static void pm_winmm_mapper_output()
235 /* Note: if MIDIMAPPER opened as output (pseudo MIDI device
236 maps device independent messages into device dependant ones,
237 via NT midimapper program) you still should get some setup info */
238 wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS)
239 & midi_out_mapper_caps, sizeof(MIDIOUTCAPS));
240 if (wRtn == MMSYSERR_NOERROR) {
241 pm_add_device("MMSystem", midi_out_mapper_caps.szPname, FALSE,
242 (void *) MIDIMAPPER, &pm_winmm_out_dictionary);
248 =========================================================================================
250 =========================================================================================
252 static unsigned int winmm_has_host_error(PmInternal * midi)
254 midiwinmm_type m = (midiwinmm_type)midi->descriptor;
259 /* str_copy_len -- like strcat, but won't overrun the destination string */
261 * returns length of resulting string
263 static int str_copy_len(char *dst, char *src, int len)
265 strncpy(dst, src, len);
266 /* just in case suffex is greater then len, terminate with zero */
272 static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len)
274 /* precondition: midi != NULL */
275 midiwinmm_node * m = (midiwinmm_node *) midi->descriptor;
276 char *hdr1 = "Host error: ";
277 char *hdr2 = "Host callback error: ";
279 msg[0] = 0; /* initialize result string to empty */
281 if (descriptors[midi->device_id].pub.input) {
282 /* input and output use different winmm API calls */
283 if (m) { /* make sure there is an open device to examine */
284 if (m->error != MMSYSERR_NOERROR) {
285 int n = str_copy_len(msg, hdr1, len);
286 /* read and record host error */
287 int err = midiInGetErrorText(m->error, msg + n, len - n);
288 assert(err == MMSYSERR_NOERROR);
289 m->error = MMSYSERR_NOERROR;
292 } else { /* output port */
294 if (m->error != MMSYSERR_NOERROR) {
295 int n = str_copy_len(msg, hdr1, len);
296 int err = midiOutGetErrorText(m->error, msg + n, len - n);
297 assert(err == MMSYSERR_NOERROR);
298 m->error = MMSYSERR_NOERROR;
306 =============================================================================
308 =============================================================================
310 static MIDIHDR *allocate_buffer(long data_size)
312 LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
314 if (!hdr) return NULL;
315 evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
316 hdr->lpData = (LPSTR) evt;
317 hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size);
318 hdr->dwBytesRecorded = 0;
320 hdr->dwUser = hdr->dwBufferLength;
324 #ifdef USE_SYSEX_BUFFERS
325 static MIDIHDR *allocate_sysex_buffer(long data_size)
327 /* we're actually allocating more than data_size because the buffer
328 * will include the MIDIEVENT header in addition to the data
330 LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
332 if (!hdr) return NULL;
333 evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
334 hdr->lpData = (LPSTR) evt;
341 static PmError allocate_buffers(midiwinmm_type m, long data_size, long count)
344 /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
345 m->num_buffers = 0; /* in case no memory can be allocated */
346 m->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count);
347 if (!m->buffers) return pmInsufficientMemory;
348 m->max_buffers = count;
349 for (i = 0; i < count; i++) {
350 LPMIDIHDR hdr = allocate_buffer(data_size);
351 if (!hdr) { /* free everything allocated so far and return */
352 for (i = i - 1; i >= 0; i--) pm_free(m->buffers[i]);
355 return pmInsufficientMemory;
357 m->buffers[i] = hdr; /* this may be NULL if allocation fails */
359 m->num_buffers = count;
363 #ifdef USE_SYSEX_BUFFERS
364 static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size)
366 PmError rslt = pmNoError;
367 /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
369 for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
370 LPMIDIHDR hdr = allocate_sysex_buffer(data_size);
372 if (!hdr) rslt = pmInsufficientMemory;
373 m->sysex_buffers[i] = hdr; /* this may be NULL if allocation fails */
374 hdr->dwFlags = 0; /* mark as free */
380 #ifdef USE_SYSEX_BUFFERS
381 static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi)
384 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
385 if (!m->sysex_buffers[0]) {
386 if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) {
390 /* busy wait until we find a free buffer */
393 for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
394 /* cycle through buffers, modulo NUM_SYSEX_BUFFERS */
395 m->next_sysex_buffer++;
396 if (m->next_sysex_buffer >= NUM_SYSEX_BUFFERS) m->next_sysex_buffer = 0;
397 r = m->sysex_buffers[m->next_sysex_buffer];
398 if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_sysex_buffer;
400 /* after scanning every buffer and not finding anything, block */
401 if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
403 printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n");
408 r->dwBytesRecorded = 0;
409 r->dwBufferLength = 0; /* changed to correct value later */
414 static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
417 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
420 for (i = 0; i < m->num_buffers; i++) {
421 /* cycle through buffers, modulo m->num_buffers */
423 if (m->next_buffer >= m->num_buffers) m->next_buffer = 0;
424 r = m->buffers[m->next_buffer];
425 if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;
427 /* after scanning every buffer and not finding anything, block */
428 if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
430 printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n");
432 /* if we're trying to send a sysex message, maybe the
433 * message is too big and we need more message buffers.
434 * Expand the buffer pool by 128KB using 1024-byte buffers.
436 /* first, expand the buffers array if necessary */
437 if (!m->buffers_expanded) {
438 LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc(
439 (m->num_buffers + NUM_EXPANSION_BUFFERS) *
441 /* if no memory, we could return a no-memory error, but user
442 * probably will be unprepared to deal with it. Maybe the
443 * MIDI driver is temporarily hung so we should just wait.
444 * I don't know the right answer, but waiting is easier.
446 if (!new_buffers) continue;
447 /* copy buffers to new_buffers and replace buffers */
448 memcpy(new_buffers, m->buffers,
449 m->num_buffers * sizeof(LPMIDIHDR));
451 m->buffers = new_buffers;
452 m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS;
453 m->buffers_expanded = TRUE;
455 /* next, add one buffer and return it */
456 if (m->num_buffers < m->max_buffers) {
457 r = allocate_buffer(EXPANSION_BUFFER_LEN);
458 /* again, if there's no memory, we may not really be
459 * dead -- maybe the system is temporarily hung and
460 * we can just wait longer for a message buffer */
462 m->buffers[m->num_buffers++] = r;
463 goto found_buffer; /* break out of 2 loops */
465 /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers,
466 * and we have no free buffers to send. We'll just keep
467 * polling to see if any buffers show up.
472 r->dwBytesRecorded = 0;
473 /* actual buffer length is saved in dwUser field */
474 r->dwBufferLength = (DWORD) r->dwUser;
478 #ifdef EXPANDING_SYSEX_BUFFERS
479 note: this is not working code, but might be useful if you want
480 to grow sysex buffers.
481 static PmError resize_sysex_buffer(PmInternal *midi, long old_size, long new_size)
485 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
486 /* buffer must be smaller than 64k, but be also a multiple of 4 */
487 if (new_size > 65520) {
488 if (old_size >= 65520)
489 return pmBufferMaxSize;
493 /* allocate a bigger message */
494 big = allocate_sysex_buffer(new_size);
495 /* printf("expand to %d bytes\n", new_size);*/
496 if (!big) return pmInsufficientMemory;
497 m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR));
502 /* make sure we're not going to overwrite any memory */
503 assert(old_size <= new_size);
504 memcpy(big->lpData, m->hdr->lpData, old_size);
505 /* keep track of how many sysex bytes are in message so far */
506 big->dwBytesRecorded = m->hdr->dwBytesRecorded;
507 big->dwBufferLength = new_size;
508 /* find which buffer this was, and replace it */
509 for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
510 if (m->sysex_buffers[i] == m->hdr) {
511 m->sysex_buffers[i] = big;
512 m->sysex_buffer_size[i] = new_size;
518 assert(i != NUM_SYSEX_BUFFERS);
525 =========================================================================================
526 begin midi input implementation
527 =========================================================================================
531 static PmError allocate_input_buffer(HMIDIIN h, long buffer_len)
533 LPMIDIHDR hdr = allocate_buffer(buffer_len);
534 if (!hdr) return pmInsufficientMemory;
535 pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));
538 return (PmError) pm_hosterror;
540 pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));
541 return (PmError) pm_hosterror;
545 static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
548 int i = midi->device_id;
549 int max_sysex_len = midi->buffer_len * 4;
550 int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN;
553 dwDevice = (DWORD) descriptors[i].descriptor;
555 /* create system dependent device data */
556 m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
557 midi->descriptor = m;
558 if (!m) goto no_memory;
560 m->buffers = NULL; /* not used for input */
561 m->num_buffers = 0; /* not used for input */
562 m->max_buffers = FALSE; /* not used for input */
563 m->buffers_expanded = 0; /* not used for input */
564 m->next_buffer = 0; /* not used for input */
565 m->buffer_signal = 0; /* not used for input */
566 #ifdef USE_SYSEX_BUFFERS
567 for (i = 0; i < NUM_SYSEX_BUFFERS; i++)
568 m->sysex_buffers[i] = NULL; /* not used for input */
569 m->next_sysex_buffer = 0; /* not used for input */
572 m->first_message = TRUE; /* not used for input */
573 m->sysex_mode = FALSE;
575 m->sysex_byte_count = 0;
576 m->hdr = NULL; /* not used for input */
579 m->error = MMSYSERR_NOERROR;
580 /* 4000 is based on Windows documentation -- that's the value used in the
581 memory manager. It's small enough that it should not hurt performance even
584 InitializeCriticalSectionAndSpinCount(&m->lock, 4000);
586 pm_hosterror = midiInOpen(
587 &(m->handle.in), /* input device handle */
588 dwDevice, /* device ID */
589 (DWORD_PTR) winmm_in_callback, /* callback address */
590 (DWORD_PTR) midi, /* callback instance data */
591 CALLBACK_FUNCTION); /* callback is a procedure */
592 if (pm_hosterror) goto free_descriptor;
594 if (num_input_buffers < MIN_INPUT_BUFFERS)
595 num_input_buffers = MIN_INPUT_BUFFERS;
596 for (i = 0; i < num_input_buffers; i++) {
597 if (allocate_input_buffer(m->handle.in, INPUT_SYSEX_LEN)) {
598 /* either pm_hosterror was set, or the proper return code
599 is pmInsufficientMemory */
604 pm_hosterror = midiInStart(m->handle.in);
605 if (pm_hosterror) goto reset_device;
608 /* undo steps leading up to the detected error */
610 /* ignore return code (we already have an error to report) */
611 midiInReset(m->handle.in);
613 midiInClose(m->handle.in); /* ignore return code */
615 midi->descriptor = NULL;
619 int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
620 PM_HOST_ERROR_MSG_LEN);
621 assert(err == MMSYSERR_NOERROR);
624 /* if !pm_hosterror, then the error must be pmInsufficientMemory */
625 return pmInsufficientMemory;
626 /* note: if we return an error code, the device will be
627 closed and memory will be freed. It's up to the caller
628 to free the parameter midi */
631 static PmError winmm_in_poll(PmInternal *midi) {
632 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
633 return (PmError) m->error;
638 /* winmm_in_close -- close an open midi input device */
640 * assume midi is non-null (checked by caller)
642 static PmError winmm_in_close(PmInternal *midi)
644 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
645 if (!m) return pmBadPtr;
646 /* device to close */
647 if (pm_hosterror = midiInStop(m->handle.in)) {
648 midiInReset(m->handle.in); /* try to reset and close port */
649 midiInClose(m->handle.in);
650 } else if (pm_hosterror = midiInReset(m->handle.in)) {
651 midiInClose(m->handle.in); /* best effort to close midi port */
653 pm_hosterror = midiInClose(m->handle.in);
655 midi->descriptor = NULL;
656 DeleteCriticalSection(&m->lock);
657 pm_free(m); /* delete */
659 int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
660 PM_HOST_ERROR_MSG_LEN);
661 assert(err == MMSYSERR_NOERROR);
668 /* Callback function executed via midiInput SW interrupt (via midiInOpen). */
669 static void FAR PASCAL winmm_in_callback(
670 HMIDIIN hMidiIn, /* midiInput device Handle */
671 WORD wMsg, /* midi msg */
672 DWORD dwInstance, /* application data */
673 DWORD dwParam1, /* MIDI data */
674 DWORD dwParam2) /* device timestamp (wrt most recent midiInStart) */
676 static int entry = 0;
677 PmInternal *midi = (PmInternal *) dwInstance;
678 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
680 /* NOTE: we do not just EnterCriticalSection() here because an
681 * MIM_CLOSE message arrives when the port is closed, but then
682 * the m->lock has been destroyed.
687 /* if this callback is reentered with data, we're in trouble.
688 * It's hard to imagine that Microsoft would allow callbacks
689 * to be reentrant -- isn't the model that this is like a
690 * hardware interrupt? -- but I've seen reentrant behavior
691 * using a debugger, so it happens.
693 long new_driver_time;
694 EnterCriticalSection(&m->lock);
696 /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
698 dwParam2 is time message received by input device driver, specified
699 in [ms] from when midiInStart called.
700 each message is expanded to include the status byte */
702 new_driver_time = dwParam2;
704 if ((dwParam1 & 0x80) == 0) {
705 /* not a status byte -- ignore it. This happened running the
706 sysex.c test under Win2K with MidiMan USB 1x1 interface,
707 but I can't reproduce it. -RBD
709 /* printf("non-status byte found\n"); */
710 } else { /* data to process */
713 dwParam2 = (*midi->time_proc)(midi->time_info);
714 event.timestamp = dwParam2;
715 event.message = dwParam1;
716 pm_read_short(midi, &event);
718 LeaveCriticalSection(&m->lock);
722 MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
723 unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
724 unsigned int processed = 0;
725 int remaining = lpMidiHdr->dwBytesRecorded;
727 EnterCriticalSection(&m->lock);
728 /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n",
729 lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
731 dwParam2 = (*midi->time_proc)(midi->time_info);
732 /* can there be more than one message in one buffer? */
733 /* assume yes and iterate through them */
734 while (remaining > 0) {
735 unsigned int amt = pm_read_bytes(midi, data + processed,
736 remaining, dwParam2);
741 /* when a device is closed, the pending MIM_LONGDATA buffers are
742 returned to this callback with dwBytesRecorded == 0. In this
743 case, we do not want to send them back to the interface (if
744 we do, the interface will not close, and Windows OS may hang). */
745 if (lpMidiHdr->dwBytesRecorded > 0) {
747 lpMidiHdr->dwBytesRecorded = 0;
748 lpMidiHdr->dwFlags = 0;
750 /* note: no error checking -- can this actually fail? */
751 rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
752 assert(rslt == MMSYSERR_NOERROR);
753 /* note: I don't think this can fail except possibly for
754 * MMSYSERR_NOMEM, but the pain of reporting this
755 * unlikely but probably catastrophic error does not seem
758 rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
759 assert(rslt == MMSYSERR_NOERROR);
760 LeaveCriticalSection(&m->lock);
762 midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
763 LeaveCriticalSection(&m->lock);
773 /* printf("MIM_ERROR\n"); */
776 /* printf("MIM_LONGERROR\n"); */
784 =========================================================================================
785 begin midi output implementation
786 =========================================================================================
789 /* begin helper routines used by midiOutStream interface */
791 /* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */
792 static int add_to_buffer(midiwinmm_type m, LPMIDIHDR hdr,
793 unsigned long delta, unsigned long msg)
795 unsigned long *ptr = (unsigned long *)
796 (hdr->lpData + hdr->dwBytesRecorded);
797 *ptr++ = delta; /* dwDeltaTime */
798 *ptr++ = 0; /* dwStream */
799 *ptr++ = msg; /* dwEvent */
800 hdr->dwBytesRecorded += 3 * sizeof(long);
801 /* if the addition of three more words (a message) would extend beyond
802 the buffer length, then return TRUE (full)
804 return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;
808 static PmTimestamp pm_time_get(midiwinmm_type m)
812 mmtime.wType = TIME_TICKS;
814 wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime));
815 assert(wRtn == MMSYSERR_NOERROR);
816 return mmtime.u.ticks;
820 /* end helper routines used by midiOutStream interface */
823 static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
826 int i = midi->device_id;
828 MIDIPROPTEMPO propdata;
829 MIDIPROPTIMEDIV divdata;
830 int max_sysex_len = midi->buffer_len * 4;
831 int output_buffer_len;
833 dwDevice = (DWORD) descriptors[i].descriptor;
835 /* create system dependent device data */
836 m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
837 midi->descriptor = m;
838 if (!m) goto no_memory;
839 m->handle.out = NULL;
843 m->buffers_expanded = FALSE;
845 #ifdef USE_SYSEX_BUFFERS
846 m->sysex_buffers[0] = NULL;
847 m->sysex_buffers[1] = NULL;
848 m->next_sysex_buffer = 0;
851 m->first_message = TRUE; /* we treat first message as special case */
852 m->sysex_mode = FALSE;
854 m->sysex_byte_count = 0;
858 m->error = MMSYSERR_NOERROR;
860 /* create a signal */
861 m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);
863 /* this should only fail when there are very serious problems */
864 assert(m->buffer_signal);
867 if (midi->latency == 0) {
868 /* use simple midi out calls */
869 pm_hosterror = midiOutOpen(
870 (LPHMIDIOUT) & m->handle.out, /* device Handle */
871 dwDevice, /* device ID */
872 /* note: same callback fn as for StreamOpen: */
873 (DWORD_PTR) winmm_streamout_callback, /* callback fn */
874 (DWORD_PTR) midi, /* callback instance data */
875 CALLBACK_FUNCTION); /* callback type */
877 /* use stream-based midi output (schedulable in future) */
878 pm_hosterror = midiStreamOpen(
879 &m->handle.stream, /* device Handle */
880 (LPUINT) & dwDevice, /* device ID pointer */
881 1, /* reserved, must be 1 */
882 (DWORD_PTR) winmm_streamout_callback,
883 (DWORD_PTR) midi, /* callback instance data */
886 if (pm_hosterror != MMSYSERR_NOERROR) {
887 goto free_descriptor;
890 if (midi->latency == 0) {
891 num_buffers = NUM_SIMPLE_SYSEX_BUFFERS;
892 output_buffer_len = max_sysex_len / num_buffers;
893 if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN)
894 output_buffer_len = MIN_SIMPLE_SYSEX_LEN;
897 num_buffers = max(midi->buffer_len, midi->latency / 2);
898 if (num_buffers < MIN_STREAM_BUFFERS)
899 num_buffers = MIN_STREAM_BUFFERS;
900 output_buffer_len = STREAM_BUFFER_LEN;
902 propdata.cbStruct = sizeof(MIDIPROPTEMPO);
903 propdata.dwTempo = 480000; /* microseconds per quarter */
904 pm_hosterror = midiStreamProperty(m->handle.stream,
906 MIDIPROP_SET | MIDIPROP_TEMPO);
907 if (pm_hosterror) goto close_device;
909 divdata.cbStruct = sizeof(MIDIPROPTEMPO);
910 divdata.dwTimeDiv = 480; /* divisions per quarter */
911 pm_hosterror = midiStreamProperty(m->handle.stream,
913 MIDIPROP_SET | MIDIPROP_TIMEDIV);
914 if (pm_hosterror) goto close_device;
916 /* allocate buffers */
917 if (allocate_buffers(m, output_buffer_len, num_buffers))
920 if (midi->latency != 0) {
921 pm_hosterror = midiStreamRestart(m->handle.stream);
922 if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;
927 /* buffers are freed below by winmm_out_delete */
929 midiOutClose(m->handle.out);
931 midi->descriptor = NULL;
932 winmm_out_delete(midi); /* frees buffers and m */
935 int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
936 PM_HOST_ERROR_MSG_LEN);
937 assert(err == MMSYSERR_NOERROR);
940 return pmInsufficientMemory;
944 /* winmm_out_delete -- carefully free data associated with midi */
946 static void winmm_out_delete(PmInternal *midi)
949 /* delete system dependent device data */
950 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
952 if (m->buffer_signal) {
953 /* don't report errors -- better not to stop cleanup */
954 CloseHandle(m->buffer_signal);
956 /* if using stream output, free buffers */
957 for (i = 0; i < m->num_buffers; i++) {
958 if (m->buffers[i]) pm_free(m->buffers[i]);
963 #ifdef USE_SYSEX_BUFFERS
964 /* free sysex buffers */
965 for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
966 if (m->sysex_buffers[i]) pm_free(m->sysex_buffers[i]);
970 midi->descriptor = NULL;
971 pm_free(m); /* delete */
975 /* see comments for winmm_in_close */
976 static PmError winmm_out_close(PmInternal *midi)
978 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
980 /* device to close */
981 if (midi->latency == 0) {
982 pm_hosterror = midiOutClose(m->handle.out);
984 pm_hosterror = midiStreamClose(m->handle.stream);
986 /* regardless of outcome, free memory */
987 winmm_out_delete(midi);
990 int err = midiOutGetErrorText(pm_hosterror,
991 (char *) pm_hosterror_text,
992 PM_HOST_ERROR_MSG_LEN);
993 assert(err == MMSYSERR_NOERROR);
1000 static PmError winmm_out_abort(PmInternal *midi)
1002 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1003 m->error = MMSYSERR_NOERROR;
1005 /* only stop output streams */
1006 if (midi->latency > 0) {
1007 m->error = midiStreamStop(m->handle.stream);
1009 return m->error ? pmHostError : pmNoError;
1013 static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)
1015 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1018 m->error = midiOutPrepareHeader(m->handle.out, m->hdr,
1021 /* do not send message */
1022 } else if (midi->latency == 0) {
1023 /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded
1024 * should be zero. This is set in get_free_sysex_buffer().
1025 * The msg length goes in dwBufferLength in spite of what
1026 * Microsoft documentation says (or doesn't say). */
1027 m->hdr->dwBufferLength = m->hdr->dwBytesRecorded;
1028 m->hdr->dwBytesRecorded = 0;
1029 m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
1031 m->error = midiStreamOut(m->handle.stream, m->hdr,
1034 midi->fill_base = NULL;
1037 m->hdr->dwFlags = 0; /* release the buffer */
1047 static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte)
1049 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1050 unsigned char *msg_buffer;
1052 /* at the beginning of sysex, m->hdr is NULL */
1053 if (!m->hdr) { /* allocate a buffer if none allocated yet */
1054 m->hdr = get_free_output_buffer(midi);
1055 if (!m->hdr) return pmInsufficientMemory;
1056 m->sysex_byte_count = 0;
1058 /* figure out where to write byte */
1059 msg_buffer = (unsigned char *) (m->hdr->lpData);
1060 assert(m->hdr->lpData == (char *) (m->hdr + 1));
1062 /* check for overflow */
1063 if (m->sysex_byte_count >= m->hdr->dwBufferLength) {
1064 /* allocate a bigger message -- double it every time */
1065 LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2);
1066 /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */
1067 if (!big) return pmInsufficientMemory;
1068 m->error = midiOutPrepareHeader(m->handle.out, big,
1074 memcpy(big->lpData, msg_buffer, m->sysex_byte_count);
1075 msg_buffer = (unsigned char *) (big->lpData);
1076 if (m->buffers[0] == m->hdr) {
1077 m->buffers[0] = big;
1079 /* printf("freed m->hdr\n"); */
1080 } else if (m->buffers[1] == m->hdr) {
1081 m->buffers[1] = big;
1083 /* printf("freed m->hdr\n"); */
1088 /* append byte to message */
1089 msg_buffer[m->sysex_byte_count++] = byte;
1091 /* see if we have a complete message */
1092 if (byte == MIDI_EOX) {
1093 m->hdr->dwBytesRecorded = m->sysex_byte_count;
1095 { int i; int len = m->hdr->dwBytesRecorded;
1096 printf("OutLongMsg %d ", len);
1097 for (i = 0; i < len; i++) {
1098 printf("%2x ", msg_buffer[i]);
1102 m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
1103 m->hdr = NULL; /* stop using this message buffer */
1104 if (m->error) return pmHostError;
1111 static PmError winmm_write_short(PmInternal *midi, PmEvent *event)
1113 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1114 PmError rslt = pmNoError;
1117 if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */
1118 m->error = midiOutShortMsg(m->handle.out, event->message);
1119 if (m->error) rslt = pmHostError;
1120 } else { /* use midiStream interface -- pass data through buffers */
1121 unsigned long when = event->timestamp;
1122 unsigned long delta;
1124 if (when == 0) when = midi->now;
1125 /* when is in real_time; translate to intended stream time */
1126 when = when + m->delta + midi->latency;
1127 /* make sure we don't go backward in time */
1128 if (when < m->last_time) when = m->last_time;
1129 delta = when - m->last_time;
1130 m->last_time = when;
1131 /* before we insert any data, we must have a buffer */
1132 if (m->hdr == NULL) {
1133 /* stream interface: buffers allocated when stream is opened */
1134 m->hdr = get_free_output_buffer(midi);
1136 full = add_to_buffer(m, m->hdr, delta, event->message);
1137 if (full) rslt = winmm_write_flush(midi, when);
1142 #define winmm_begin_sysex winmm_write_flush
1143 #ifndef winmm_begin_sysex
1144 static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)
1146 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1147 PmError rslt = pmNoError;
1149 if (midi->latency == 0) {
1150 /* do nothing -- it's handled in winmm_write_byte */
1152 /* sysex expects an empty sysex buffer, so send whatever is here */
1153 rslt = winmm_write_flush(midi);
1159 static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)
1161 /* could check for callback_error here, but I haven't checked
1162 * what happens if we exit early and don't finish the sysex msg
1165 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1166 PmError rslt = pmNoError;
1167 LPMIDIHDR hdr = m->hdr;
1168 if (!hdr) return rslt; /* something bad happened earlier,
1169 do not report an error because it would have been
1170 reported (at least) once already */
1171 /* a(n old) version of MIDI YOKE requires a zero byte after
1172 * the sysex message, but do not increment dwBytesRecorded: */
1173 hdr->lpData[hdr->dwBytesRecorded] = 0;
1174 if (midi->latency == 0) {
1175 #ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX
1177 { int i; int len = m->hdr->dwBufferLength;
1178 printf("OutLongMsg %d ", len);
1179 for (i = 0; i < len; i++) {
1180 printf("%2x ", (unsigned char) (m->hdr->lpData[i]));
1185 /* Using stream interface. There are accumulated bytes in m->hdr
1186 to send using midiStreamOut
1188 /* add bytes recorded to MIDIEVENT length, but don't
1189 count the MIDIEVENT data (3 longs) */
1190 MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData);
1191 evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long);
1192 /* round up BytesRecorded to multiple of 4 */
1193 hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3;
1195 rslt = winmm_write_flush(midi, timestamp);
1200 static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
1201 PmTimestamp timestamp)
1203 /* write a sysex byte */
1204 PmError rslt = pmNoError;
1205 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1206 LPMIDIHDR hdr = m->hdr;
1207 unsigned char *msg_buffer;
1210 m->hdr = hdr = get_free_output_buffer(midi);
1212 midi->fill_base = (unsigned char *) m->hdr->lpData;
1213 midi->fill_offset_ptr = (uint32_t*) &(hdr->dwBytesRecorded);
1214 /* when buffer fills, Pm_WriteSysEx will revert to calling
1215 * pmwin_write_byte, which expect to have space, so leave
1216 * one byte free for pmwin_write_byte. Leave another byte
1217 * of space for zero after message to make early version of
1218 * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */
1219 midi->fill_length = hdr->dwBufferLength - 2;
1220 if (midi->latency != 0) {
1221 unsigned long when = (unsigned long) timestamp;
1222 unsigned long delta;
1224 if (when == 0) when = midi->now;
1225 /* when is in real_time; translate to intended stream time */
1226 when = when + m->delta + midi->latency;
1227 /* make sure we don't go backward in time */
1228 if (when < m->last_time) when = m->last_time;
1229 delta = when - m->last_time;
1230 m->last_time = when;
1232 ptr = (unsigned long *) hdr->lpData;
1236 hdr->dwBytesRecorded = 3 * sizeof(long);
1237 /* data will be added at an offset of dwBytesRecorded ... */
1240 /* add the data byte */
1241 msg_buffer = (unsigned char *) (hdr->lpData);
1242 msg_buffer[hdr->dwBytesRecorded++] = byte;
1244 /* see if buffer is full, leave one byte extra for pad */
1245 if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) {
1246 /* write what we've got and continue */
1247 rslt = winmm_end_sysex(midi, timestamp);
1252 #ifdef EXPANDING_SYSEX_BUFFERS
1253 note: this code is here as an aid in case you want sysex buffers
1254 to expand to hold large messages completely. If so, you
1255 will want to change SYSEX_BYTES_PER_BUFFER above to some
1256 variable that remembers the buffer size. A good place to
1257 put this value would be in the hdr->dwUser field.
1259 rslt = resize_sysex_buffer(midi, m->sysex_byte_count,
1260 m->sysex_byte_count * 2);
1262 if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */
1264 #ifdef EXPANDING_SYSEX_BUFFERS
1265 int bytesRecorded = hdr->dwBytesRecorded; /* this field gets wiped out, so we'll save it */
1266 rslt = resize_sysex_buffer(midi, bytesRecorded, 2 * bytesRecorded);
1267 hdr->dwBytesRecorded = bytesRecorded;
1269 if (rslt == pmBufferMaxSize) /* if buffer can't be resized */
1274 static PmTimestamp winmm_synchronize(PmInternal *midi)
1277 unsigned long pm_stream_time_2;
1278 unsigned long real_time;
1279 unsigned long pm_stream_time;
1281 /* only synchronize if we are using stream interface */
1282 if (midi->latency == 0) return 0;
1284 /* figure out the time */
1285 m = (midiwinmm_type) midi->descriptor;
1286 pm_stream_time_2 = pm_time_get(m);
1289 /* read real_time between two reads of stream time */
1290 pm_stream_time = pm_stream_time_2;
1291 real_time = (*midi->time_proc)(midi->time_info);
1292 pm_stream_time_2 = pm_time_get(m);
1293 /* repeat if more than 1ms elapsed */
1294 } while (pm_stream_time_2 > pm_stream_time + 1);
1295 m->delta = pm_stream_time - real_time;
1296 m->sync_time = real_time;
1300 #ifdef USE_SYSEX_BUFFERS
1301 /* winmm_out_callback -- recycle sysex buffers */
1302 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
1303 DWORD dwInstance, DWORD dwParam1,
1306 PmInternal *midi = (PmInternal *) dwInstance;
1307 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1308 LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
1309 int err = 0; /* set to 0 so that no buffer match will also be an error */
1311 /* Future optimization: eliminate UnprepareHeader calls -- they aren't
1312 necessary; however, this code uses the prepared-flag to indicate which
1313 buffers are free, so we need to do something to flag empty buffers if
1314 we leave them prepared
1317 printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n",
1318 hdr, wMsg, MOM_DONE);
1320 if (wMsg == MOM_DONE) {
1321 MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr,
1323 assert(ret == MMSYSERR_NOERROR);
1325 /* notify waiting sender that a buffer is available */
1326 err = SetEvent(m->buffer_signal);
1327 assert(err); /* false -> error */
1331 /* winmm_streamout_callback -- unprepare (free) buffer header */
1332 static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
1333 DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
1335 PmInternal *midi = (PmInternal *) dwInstance;
1336 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1337 LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
1340 /* Even if an error is pending, I think we should unprepare msgs and
1341 signal their arrival
1343 /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n",
1344 hdr, wMsg, MOM_DONE); */
1345 if (wMsg == MOM_DONE) {
1346 MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr,
1348 assert(ret == MMSYSERR_NOERROR);
1350 /* signal client in case it is blocked waiting for buffer */
1351 err = SetEvent(m->buffer_signal);
1352 assert(err); /* false -> error */
1357 =========================================================================================
1358 begin exported functions
1359 =========================================================================================
1362 #define winmm_in_abort pm_fail_fn
1363 pm_fns_node pm_winmm_in_dictionary = {
1375 winmm_has_host_error,
1376 winmm_get_host_error
1379 pm_fns_node pm_winmm_out_dictionary = {
1384 winmm_write_short, /* short realtime message */
1391 winmm_has_host_error,
1392 winmm_get_host_error
1396 /* initialize winmm interface. Note that if there is something wrong
1397 with winmm (e.g. it is not supported or installed), it is not an
1398 error. We should simply return without having added any devices to
1399 the table. Hence, no error code is returned. Furthermore, this init
1400 code is called along with every other supported interface, so the
1401 user would have a very hard time figuring out what hardware and API
1402 generated the error. Finally, it would add complexity to pmwin.c to
1403 remember where the error code came from in order to convert to text.
1405 void pm_winmm_init( void )
1407 pm_winmm_mapper_input();
1408 pm_winmm_mapper_output();
1409 pm_winmm_general_inputs();
1410 pm_winmm_general_outputs();
1414 /* no error codes are returned, even if errors are encountered, because
1415 there is probably nothing the user could do (e.g. it would be an error
1418 void pm_winmm_term( void )
1422 char msg[PM_HOST_ERROR_MSG_LEN];
1426 printf("pm_winmm_term called\n");
1428 for (i = 0; i < pm_descriptor_index; i++) {
1429 PmInternal * midi = (PmInternal*) descriptors[i].internalDescriptor;
1431 midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1432 if (m->handle.out) {
1433 /* close next open device*/
1436 printf("begin closing open devices...\n");
1439 /* report any host errors; this EXTEREMELY useful when
1440 trying to debug client app */
1441 if (winmm_has_host_error(midi)) {
1442 winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN);
1443 printf("%s\n", msg);
1446 /* close all open ports */
1447 (*midi->dictionary->close)(midi);
1452 pm_free(midi_in_caps);
1453 midi_in_caps = NULL;
1455 if (midi_out_caps) {
1456 pm_free(midi_out_caps);
1457 midi_out_caps = NULL;
1461 printf("warning: devices were left open. They have been closed.\n");
1463 printf("pm_winmm_term exiting\n");
1465 pm_descriptor_index = 0;