511c3c652e22eb2fc83b49b095c9f5aa95458255
[ardour.git] / libs / backends / wavesaudio / portmidi / src / pm_win / pmwinmm.c
1 /* pmwinmm.c -- system specific definitions */
2
3 #ifdef _MSC_VER
4  #pragma warning(disable: 4133) // stop warnings about implicit typecasts
5
6 #define max(a,b) __max(a,b)
7 #endif
8
9 #ifndef _WIN32_WINNT
10     /* without this define, InitializeCriticalSectionAndSpinCount is
11      * undefined. This version level means "Windows 2000 and higher"
12      */
13     #define _WIN32_WINNT 0x0500
14 #endif
15
16 #include "windows.h"
17 #include "mmsystem.h"
18 #include "portmidi.h"
19 #include "pmutil.h"
20 #include "pminternal.h"
21 #include "pmwinmm.h"
22 #include <string.h>
23 #include "porttime.h"
24
25 /* asserts used to verify portMidi code logic is sound; later may want
26     something more graceful */
27 #include <assert.h>
28 #ifdef DEBUG
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 */
32 #define STRING_MAX 80
33 #include "stdio.h"
34 #endif
35
36 #define streql(x, y) (strcmp(x, y) == 0)
37
38 #define MIDI_SYSEX      0xf0
39 #define MIDI_EOX        0xf7
40
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,
47                                               DWORD dwParam2);
48 #ifdef USE_SYSEX_BUFFERS
49 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
50                                         DWORD dwInstance, DWORD dwParam1,
51                                         DWORD dwParam2);
52 #endif
53
54 extern pm_fns_node pm_winmm_in_dictionary;
55 extern pm_fns_node pm_winmm_out_dictionary;
56
57 static void winmm_out_delete(PmInternal *midi); /* forward reference */
58
59 /*
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.
65
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.
69
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.
72
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.
75
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.
80
81 The following constants help to represent these design parameters:
82 */
83 #define NUM_SIMPLE_SYSEX_BUFFERS 3
84 #define MIN_SIMPLE_SYSEX_LEN 256
85
86 #define MIN_STREAM_BUFFERS 16
87 #define STREAM_BUFFER_LEN 24
88
89 #define INPUT_SYSEX_LEN 64
90 #define MIN_INPUT_BUFFERS 16
91
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
94  */
95 #define NUM_EXPANSION_BUFFERS 128
96 #define EXPANSION_BUFFER_LEN 1024
97
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))
105 #endif
106
107 /*
108 ==============================================================================
109 win32 mmedia system specific structure passed to midi callbacks
110 ==============================================================================
111 */
112
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;
120
121 /* per device info */
122 typedef struct midiwinmm_struct {
123     union {
124         HMIDISTRM stream;   /* windows handle for stream */
125         HMIDIOUT out;       /* windows handle for out calls */
126         HMIDIIN in;         /* windows handle for in calls */
127     } handle;
128
129     /* midi output messages are sent in these buffers, which are allocated
130      * in a round-robin fashion, using next_buffer as an index
131      */
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.
141      */
142     LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */
143     int next_sysex_buffer;      /* index of next sysexbuffer to send */
144 #endif
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
153                                        real time */
154     int error;                  /* host error from doing port midi call */
155     CRITICAL_SECTION lock;      /* prevents reentrant callbacks (input only) */
156 } midiwinmm_node, *midiwinmm_type;
157
158
159 /*
160 =============================================================================
161 general MIDI device queries
162 =============================================================================
163 */
164 static void pm_winmm_general_inputs()
165 {
166     UINT i;
167     WORD wRtn;
168     midi_num_inputs = midiInGetNumDevs();
169     midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) *
170                                            midi_num_inputs);
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.
175          */
176         return;
177     }
178
179     for (i = 0; i < midi_num_inputs; i++) {
180         wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],
181                                 sizeof(MIDIINCAPS));
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);
187         }
188     }
189 }
190
191
192 static void pm_winmm_mapper_input()
193 {
194     WORD wRtn;
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
198         setup info. */
199     wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,
200                             (LPMIDIINCAPS) & midi_in_mapper_caps,
201                             sizeof(MIDIINCAPS));
202     if (wRtn == MMSYSERR_NOERROR) {
203         pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE,
204                       (void *) MIDIMAPPER, &pm_winmm_in_dictionary);
205     }
206 }
207
208
209 static void pm_winmm_general_outputs()
210 {
211     UINT i;
212     DWORD wRtn;
213     midi_num_outputs = midiOutGetNumDevs();
214     midi_out_caps = (MIDIOUTCAPS*)pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs );
215
216     if (midi_out_caps == NULL) {
217         /* no error is reported -- see pm_winmm_general_inputs */
218         return ;
219     }
220
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);
227         }
228     }
229 }
230
231
232 static void pm_winmm_mapper_output()
233 {
234     WORD wRtn;
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);
243     }
244 }
245
246
247 /*
248 =========================================================================================
249 host error handling
250 =========================================================================================
251 */
252 static unsigned int winmm_has_host_error(PmInternal * midi)
253 {
254     midiwinmm_type m = (midiwinmm_type)midi->descriptor;
255     return m->error;
256 }
257
258
259 /* str_copy_len -- like strcat, but won't overrun the destination string */
260 /*
261  * returns length of resulting string
262  */
263 static int str_copy_len(char *dst, char *src, int len)
264 {
265     strncpy(dst, src, len);
266     /* just in case suffex is greater then len, terminate with zero */
267     dst[len - 1] = 0;
268     return strlen(dst);
269 }
270
271
272 static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len)
273 {
274     /* precondition: midi != NULL */
275     midiwinmm_node * m = (midiwinmm_node *) midi->descriptor;
276     char *hdr1 = "Host error: ";
277     char *hdr2 = "Host callback error: ";
278
279     msg[0] = 0; /* initialize result string to empty */
280
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;
290             }
291         }
292     } else { /* output port */
293         if (m) {
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;
299             }
300         }
301     }
302 }
303
304
305 /*
306 =============================================================================
307 buffer handling
308 =============================================================================
309 */
310 static MIDIHDR *allocate_buffer(long data_size)
311 {
312     LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
313     MIDIEVENT *evt;
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;
319     hdr->dwFlags = 0;
320     hdr->dwUser = hdr->dwBufferLength;
321     return hdr;
322 }
323
324 #ifdef USE_SYSEX_BUFFERS
325 static MIDIHDR *allocate_sysex_buffer(long data_size)
326 {
327     /* we're actually allocating more than data_size because the buffer
328      * will include the MIDIEVENT header in addition to the data
329      */
330     LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
331     MIDIEVENT *evt;
332     if (!hdr) return NULL;
333     evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
334     hdr->lpData = (LPSTR) evt;
335     hdr->dwFlags = 0;
336     hdr->dwUser = 0;
337     return hdr;
338 }
339 #endif
340
341 static PmError allocate_buffers(midiwinmm_type m, long data_size, long count)
342 {
343     int i;
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]);
353             pm_free(m->buffers);
354             m->max_buffers = 0;
355             return pmInsufficientMemory;
356         }
357         m->buffers[i] = hdr; /* this may be NULL if allocation fails */
358     }
359     m->num_buffers = count;
360     return pmNoError;
361 }
362
363 #ifdef USE_SYSEX_BUFFERS
364 static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size)
365 {
366     PmError rslt = pmNoError;
367     /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
368     int i;
369     for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
370         LPMIDIHDR hdr = allocate_sysex_buffer(data_size);
371
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 */
375     }
376     return rslt;
377 }
378 #endif
379
380 #ifdef USE_SYSEX_BUFFERS
381 static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi)
382 {
383     LPMIDIHDR r = NULL;
384     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
385     if (!m->sysex_buffers[0]) {
386         if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) {
387             return NULL;
388         }
389     }
390     /* busy wait until we find a free buffer */
391     while (TRUE) {
392         int i;
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;
399         }
400         /* after scanning every buffer and not finding anything, block */
401         if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
402 #ifdef DEBUG
403             printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n");
404 #endif
405         }
406     }
407 found_sysex_buffer:
408     r->dwBytesRecorded = 0;
409     r->dwBufferLength = 0; /* changed to correct value later */
410     return r;
411 }
412 #endif
413
414 static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
415 {
416     LPMIDIHDR r = NULL;
417     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
418     while (TRUE) {
419         int i;
420         for (i = 0; i < m->num_buffers; i++) {
421             /* cycle through buffers, modulo m->num_buffers */
422             m->next_buffer++;
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;
426         }
427         /* after scanning every buffer and not finding anything, block */
428         if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
429 #ifdef DEBUG
430             printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n");
431 #endif
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.
435              */
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) *
440                         sizeof(LPMIDIHDR));
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.
445                  */
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));
450                 pm_free(m->buffers);
451                 m->buffers = new_buffers;
452                 m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS;
453                 m->buffers_expanded = TRUE;
454             }
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 */
461                 if (!r) continue;
462                 m->buffers[m->num_buffers++] = r;
463                 goto found_buffer; /* break out of 2 loops */
464             }
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.
468              */
469         }
470     }
471 found_buffer:
472     r->dwBytesRecorded = 0;
473     /* actual buffer length is saved in dwUser field */
474     r->dwBufferLength = (DWORD) r->dwUser;
475     return r;
476 }
477
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)
482 {
483     LPMIDIHDR big;
484     int i;
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;
490         else
491             new_size = 65520;
492     }
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));
498     if (m->error) {
499         pm_free(big);
500         return pmHostError;
501     }
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;
513             pm_free(m->hdr);
514             m->hdr = big;
515             break;
516         }
517     }
518     assert(i != NUM_SYSEX_BUFFERS);
519
520     return pmNoError;
521 }
522 #endif
523
524 /*
525 =========================================================================================
526 begin midi input implementation
527 =========================================================================================
528 */
529
530
531 static PmError allocate_input_buffer(HMIDIIN h, long buffer_len)
532 {
533     LPMIDIHDR hdr = allocate_buffer(buffer_len);
534     if (!hdr) return pmInsufficientMemory;
535     pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));
536     if (pm_hosterror) {
537         pm_free(hdr);
538         return (PmError) pm_hosterror;
539     }
540     pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));
541     return (PmError) pm_hosterror;
542 }
543
544
545 static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
546 {
547     DWORD dwDevice;
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;
551     midiwinmm_type m;
552
553     dwDevice = (DWORD) descriptors[i].descriptor;
554
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;
559     m->handle.in = NULL;
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 */
570 #endif
571     m->last_time = 0;
572     m->first_message = TRUE; /* not used for input */
573     m->sysex_mode = FALSE;
574     m->sysex_word = 0;
575     m->sysex_byte_count = 0;
576     m->hdr = NULL; /* not used for input */
577     m->sync_time = 0;
578     m->delta = 0;
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
582        if it's not optimal.
583      */
584     InitializeCriticalSectionAndSpinCount(&m->lock, 4000);
585     /* open device */
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;
593
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 */
600             goto close_device;
601         }
602     }
603     /* start device */
604     pm_hosterror = midiInStart(m->handle.in);
605     if (pm_hosterror) goto reset_device;
606     return pmNoError;
607
608     /* undo steps leading up to the detected error */
609 reset_device:
610     /* ignore return code (we already have an error to report) */
611     midiInReset(m->handle.in);
612 close_device:
613     midiInClose(m->handle.in); /* ignore return code */
614 free_descriptor:
615     midi->descriptor = NULL;
616     pm_free(m);
617 no_memory:
618     if (pm_hosterror) {
619         int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
620                                      PM_HOST_ERROR_MSG_LEN);
621         assert(err == MMSYSERR_NOERROR);
622         return pmHostError;
623     }
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 */
629 }
630
631 static PmError winmm_in_poll(PmInternal *midi) {
632     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
633     return (PmError) m->error;
634 }
635
636
637
638 /* winmm_in_close -- close an open midi input device */
639 /*
640  * assume midi is non-null (checked by caller)
641  */
642 static PmError winmm_in_close(PmInternal *midi)
643 {
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 */
652     } else {
653         pm_hosterror = midiInClose(m->handle.in);
654     }
655     midi->descriptor = NULL;
656     DeleteCriticalSection(&m->lock);
657     pm_free(m); /* delete */
658     if (pm_hosterror) {
659         int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
660                                      PM_HOST_ERROR_MSG_LEN);
661         assert(err == MMSYSERR_NOERROR);
662         return pmHostError;
663     }
664     return pmNoError;
665 }
666
667
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) */
675 {
676     static int entry = 0;
677     PmInternal *midi = (PmInternal *) dwInstance;
678     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
679
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.
683      */
684
685     switch (wMsg) {
686     case MIM_DATA: {
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.
692          */
693         long new_driver_time;
694         EnterCriticalSection(&m->lock);
695
696         /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
697                 message LOB;
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 */
701
702         new_driver_time = dwParam2;
703
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
708              */
709             /* printf("non-status byte found\n"); */
710         } else { /* data to process */
711             PmEvent event;
712             if (midi->time_proc)
713                 dwParam2 = (*midi->time_proc)(midi->time_info);
714             event.timestamp = dwParam2;
715             event.message = dwParam1;
716             pm_read_short(midi, &event);
717         }
718         LeaveCriticalSection(&m->lock);
719         break;
720     }
721     case MIM_LONGDATA: {
722         MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
723         unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
724         unsigned int processed = 0;
725         int remaining = lpMidiHdr->dwBytesRecorded;
726
727         EnterCriticalSection(&m->lock);
728         /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n",
729                 lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
730         if (midi->time_proc)
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);
737             remaining -= amt;
738             processed += amt;
739         }
740
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) {
746             MMRESULT rslt;
747             lpMidiHdr->dwBytesRecorded = 0;
748             lpMidiHdr->dwFlags = 0;
749                         
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
756              * worth it.
757              */
758             rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
759             assert(rslt == MMSYSERR_NOERROR);
760             LeaveCriticalSection(&m->lock);
761         } else {
762             midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
763             LeaveCriticalSection(&m->lock);
764             pm_free(lpMidiHdr);
765         }
766         break;
767     }
768     case MIM_OPEN:
769         break;
770     case MIM_CLOSE:
771         break;
772     case MIM_ERROR:
773         /* printf("MIM_ERROR\n"); */
774         break;
775     case MIM_LONGERROR:
776         /* printf("MIM_LONGERROR\n"); */
777         break;
778     default:
779         break;
780     }
781 }
782
783 /*
784 =========================================================================================
785 begin midi output implementation
786 =========================================================================================
787 */
788
789 /* begin helper routines used by midiOutStream interface */
790
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)
794 {
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)
803      */
804     return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;
805 }
806
807
808 static PmTimestamp pm_time_get(midiwinmm_type m)
809 {
810     MMTIME mmtime;
811     MMRESULT wRtn;
812     mmtime.wType = TIME_TICKS;
813     mmtime.u.ticks = 0;
814     wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime));
815     assert(wRtn == MMSYSERR_NOERROR);
816     return mmtime.u.ticks;
817 }
818
819
820 /* end helper routines used by midiOutStream interface */
821
822
823 static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
824 {
825     DWORD dwDevice;
826     int i = midi->device_id;
827     midiwinmm_type m;
828     MIDIPROPTEMPO propdata;
829     MIDIPROPTIMEDIV divdata;
830     int max_sysex_len = midi->buffer_len * 4;
831     int output_buffer_len;
832     int num_buffers;
833     dwDevice = (DWORD) descriptors[i].descriptor;
834
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;
840     m->buffers = NULL;
841     m->num_buffers = 0;
842     m->max_buffers = 0;
843     m->buffers_expanded = FALSE;
844     m->next_buffer = 0;
845 #ifdef USE_SYSEX_BUFFERS
846     m->sysex_buffers[0] = NULL;
847     m->sysex_buffers[1] = NULL;
848     m->next_sysex_buffer = 0;
849 #endif
850     m->last_time = 0;
851     m->first_message = TRUE; /* we treat first message as special case */
852     m->sysex_mode = FALSE;
853     m->sysex_word = 0;
854     m->sysex_byte_count = 0;
855     m->hdr = NULL;
856     m->sync_time = 0;
857     m->delta = 0;
858     m->error = MMSYSERR_NOERROR;
859
860     /* create a signal */
861     m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);
862
863     /* this should only fail when there are very serious problems */
864     assert(m->buffer_signal);
865
866     /* open device */
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 */
876     } else {
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 */
884                 CALLBACK_FUNCTION);
885     }
886     if (pm_hosterror != MMSYSERR_NOERROR) {
887         goto free_descriptor;
888     }
889
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;
895     } else {
896         long dur = 0;
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;
901
902         propdata.cbStruct = sizeof(MIDIPROPTEMPO);
903         propdata.dwTempo = 480000; /* microseconds per quarter */
904         pm_hosterror = midiStreamProperty(m->handle.stream,
905                                           (LPBYTE) & propdata,
906                                           MIDIPROP_SET | MIDIPROP_TEMPO);
907         if (pm_hosterror) goto close_device;
908
909         divdata.cbStruct = sizeof(MIDIPROPTEMPO);
910         divdata.dwTimeDiv = 480;   /* divisions per quarter */
911         pm_hosterror = midiStreamProperty(m->handle.stream,
912                                           (LPBYTE) & divdata,
913                                           MIDIPROP_SET | MIDIPROP_TIMEDIV);
914         if (pm_hosterror) goto close_device;
915     }
916     /* allocate buffers */
917     if (allocate_buffers(m, output_buffer_len, num_buffers))
918         goto free_buffers;
919     /* start device */
920     if (midi->latency != 0) {
921         pm_hosterror = midiStreamRestart(m->handle.stream);
922         if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;
923     }
924     return pmNoError;
925
926 free_buffers:
927     /* buffers are freed below by winmm_out_delete */
928 close_device:
929     midiOutClose(m->handle.out);
930 free_descriptor:
931     midi->descriptor = NULL;
932     winmm_out_delete(midi); /* frees buffers and m */
933 no_memory:
934     if (pm_hosterror) {
935         int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
936                                       PM_HOST_ERROR_MSG_LEN);
937         assert(err == MMSYSERR_NOERROR);
938         return pmHostError;
939     }
940     return pmInsufficientMemory;
941 }
942
943
944 /* winmm_out_delete -- carefully free data associated with midi */
945 /**/
946 static void winmm_out_delete(PmInternal *midi)
947 {
948     int i;
949     /* delete system dependent device data */
950     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
951     if (m) {
952         if (m->buffer_signal) {
953             /* don't report errors -- better not to stop cleanup */
954             CloseHandle(m->buffer_signal);
955         }
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]);
959         }
960         m->num_buffers = 0;
961         pm_free(m->buffers);
962         m->max_buffers = 0;
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]);
967         }
968 #endif
969     }
970     midi->descriptor = NULL;
971     pm_free(m); /* delete */
972 }
973
974
975 /* see comments for winmm_in_close */
976 static PmError winmm_out_close(PmInternal *midi)
977 {
978     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
979     if (m->handle.out) {
980         /* device to close */
981         if (midi->latency == 0) {
982             pm_hosterror = midiOutClose(m->handle.out);
983         } else {
984             pm_hosterror = midiStreamClose(m->handle.stream);
985         }
986         /* regardless of outcome, free memory */
987         winmm_out_delete(midi);
988     }
989     if (pm_hosterror) {
990         int err = midiOutGetErrorText(pm_hosterror,
991                                       (char *) pm_hosterror_text,
992                                       PM_HOST_ERROR_MSG_LEN);
993         assert(err == MMSYSERR_NOERROR);
994         return pmHostError;
995     }
996     return pmNoError;
997 }
998
999
1000 static PmError winmm_out_abort(PmInternal *midi)
1001 {
1002     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1003     m->error = MMSYSERR_NOERROR;
1004
1005     /* only stop output streams */
1006     if (midi->latency > 0) {
1007         m->error = midiStreamStop(m->handle.stream);
1008     }
1009     return m->error ? pmHostError : pmNoError;
1010 }
1011
1012
1013 static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)
1014 {
1015     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1016     assert(m);
1017     if (m->hdr) {
1018         m->error = midiOutPrepareHeader(m->handle.out, m->hdr,
1019                                         sizeof(MIDIHDR));
1020         if (m->error) {
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));
1030         } else {
1031             m->error = midiStreamOut(m->handle.stream, m->hdr,
1032                                      sizeof(MIDIHDR));
1033         }
1034         midi->fill_base = NULL;
1035         m->hdr = NULL;
1036         if (m->error) {
1037             m->hdr->dwFlags = 0; /* release the buffer */
1038             return pmHostError;
1039         }
1040     }
1041     return pmNoError;
1042 }
1043
1044
1045
1046 #ifdef GARBAGE
1047 static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte)
1048 {
1049     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1050     unsigned char *msg_buffer;
1051
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;
1057     }
1058     /* figure out where to write byte */
1059     msg_buffer = (unsigned char *) (m->hdr->lpData);
1060     assert(m->hdr->lpData == (char *) (m->hdr + 1));
1061
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,
1069                                         sizeof(MIDIHDR));
1070         if (m->error) {
1071             m->hdr = NULL;
1072             return pmHostError;
1073         }
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;
1078             pm_free(m->hdr);
1079             /* printf("freed m->hdr\n"); */
1080         } else if (m->buffers[1] == m->hdr) {
1081             m->buffers[1] = big;
1082             pm_free(m->hdr);
1083             /* printf("freed m->hdr\n"); */
1084         }
1085         m->hdr = big;
1086     }
1087
1088     /* append byte to message */
1089     msg_buffer[m->sysex_byte_count++] = byte;
1090
1091     /* see if we have a complete message */
1092     if (byte == MIDI_EOX) {
1093         m->hdr->dwBytesRecorded = m->sysex_byte_count;
1094         /*
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]);
1099           }
1100         }
1101         */
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;
1105     }
1106     return pmNoError;
1107 }
1108 #endif
1109
1110
1111 static PmError winmm_write_short(PmInternal *midi, PmEvent *event)
1112 {
1113     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1114     PmError rslt = pmNoError;
1115     assert(m);
1116
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;
1123         int full;
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);
1135         }
1136         full = add_to_buffer(m, m->hdr, delta, event->message);
1137         if (full) rslt = winmm_write_flush(midi, when);
1138     }
1139     return rslt;
1140 }
1141
1142 #define winmm_begin_sysex winmm_write_flush
1143 #ifndef winmm_begin_sysex
1144 static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)
1145 {
1146     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1147     PmError rslt = pmNoError;
1148
1149     if (midi->latency == 0) {
1150         /* do nothing -- it's handled in winmm_write_byte */
1151     } else {
1152         /* sysex expects an empty sysex buffer, so send whatever is here */
1153         rslt = winmm_write_flush(midi);
1154     }
1155     return rslt;
1156 }
1157 #endif
1158
1159 static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)
1160 {
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
1163      * and clean up
1164      */
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
1176         /* DEBUG CODE: */
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]));
1181           }
1182         }
1183 #endif
1184     } else {
1185         /* Using stream interface. There are accumulated bytes in m->hdr
1186            to send using midiStreamOut
1187          */
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;
1194     }
1195     rslt = winmm_write_flush(midi, timestamp);
1196     return rslt;
1197 }
1198
1199
1200 static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
1201                                 PmTimestamp timestamp)
1202 {
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;
1208     assert(m);
1209     if (!hdr) {
1210         m->hdr = hdr = get_free_output_buffer(midi);
1211         assert(hdr);
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;
1223             unsigned long *ptr;
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;
1231
1232             ptr = (unsigned long *) hdr->lpData;
1233             *ptr++ = delta;
1234             *ptr++ = 0;
1235             *ptr = MEVT_F_LONG;
1236             hdr->dwBytesRecorded = 3 * sizeof(long);
1237             /* data will be added at an offset of dwBytesRecorded ... */
1238         }
1239     }
1240     /* add the data byte */
1241     msg_buffer = (unsigned char *) (hdr->lpData);
1242     msg_buffer[hdr->dwBytesRecorded++] = byte;
1243
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);
1248     }
1249     return rslt;
1250 }
1251
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.
1258
1259             rslt = resize_sysex_buffer(midi, m->sysex_byte_count,
1260                                        m->sysex_byte_count * 2);
1261
1262             if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */
1263 #endif
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;
1268
1269             if (rslt == pmBufferMaxSize) /* if buffer can't be resized */
1270 #endif
1271
1272
1273
1274 static PmTimestamp winmm_synchronize(PmInternal *midi)
1275 {
1276     midiwinmm_type m;
1277     unsigned long pm_stream_time_2;
1278     unsigned long real_time;
1279     unsigned long pm_stream_time;
1280
1281     /* only synchronize if we are using stream interface */
1282     if (midi->latency == 0) return 0;
1283
1284     /* figure out the time */
1285     m = (midiwinmm_type) midi->descriptor;
1286     pm_stream_time_2 = pm_time_get(m);
1287
1288     do {
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;
1297     return real_time;
1298 }
1299
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,
1304                                         DWORD dwParam2)
1305 {
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 */
1310
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
1315      */
1316     /*
1317     printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n",
1318            hdr, wMsg, MOM_DONE);
1319     */
1320     if (wMsg == MOM_DONE) {
1321         MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr,
1322                                               sizeof(MIDIHDR));
1323         assert(ret == MMSYSERR_NOERROR);
1324     }
1325     /* notify waiting sender that a buffer is available */
1326     err = SetEvent(m->buffer_signal);
1327     assert(err); /* false -> error */
1328 }
1329 #endif
1330
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)
1334 {
1335     PmInternal *midi = (PmInternal *) dwInstance;
1336     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1337     LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
1338     int err;
1339
1340     /* Even if an error is pending, I think we should unprepare msgs and
1341        signal their arrival
1342      */
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,
1347                                               sizeof(MIDIHDR));
1348         assert(ret == MMSYSERR_NOERROR);
1349     }
1350     /* signal client in case it is blocked waiting for buffer */
1351     err = SetEvent(m->buffer_signal);
1352     assert(err); /* false -> error */
1353 }
1354
1355
1356 /*
1357 =========================================================================================
1358 begin exported functions
1359 =========================================================================================
1360 */
1361
1362 #define winmm_in_abort pm_fail_fn
1363 pm_fns_node pm_winmm_in_dictionary = {
1364                                          none_write_short,
1365                                          none_sysex,
1366                                          none_sysex,
1367                                          none_write_byte,
1368                                          none_write_short,
1369                                          none_write_flush,
1370                                          winmm_synchronize,
1371                                          winmm_in_open,
1372                                          winmm_in_abort,
1373                                          winmm_in_close,
1374                                          winmm_in_poll,
1375                                          winmm_has_host_error,
1376                                          winmm_get_host_error
1377                                      };
1378
1379 pm_fns_node pm_winmm_out_dictionary = {
1380                                           winmm_write_short,
1381                                           winmm_begin_sysex,
1382                                           winmm_end_sysex,
1383                                           winmm_write_byte,
1384                                           winmm_write_short,  /* short realtime message */
1385                                           winmm_write_flush,
1386                                           winmm_synchronize,
1387                                           winmm_out_open,
1388                                           winmm_out_abort,
1389                                           winmm_out_close,
1390                                           none_poll,
1391                                           winmm_has_host_error,
1392                                           winmm_get_host_error
1393                                       };
1394
1395
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.
1404  */
1405 void pm_winmm_init( void )
1406 {
1407     pm_winmm_mapper_input();
1408     pm_winmm_mapper_output();
1409     pm_winmm_general_inputs();
1410     pm_winmm_general_outputs();
1411 }
1412
1413
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
1416    to retry.
1417  */
1418 void pm_winmm_term( void )
1419 {
1420     int i;
1421 #ifdef DEBUG
1422     char msg[PM_HOST_ERROR_MSG_LEN];
1423 #endif
1424     int doneAny = 0;
1425 #ifdef DEBUG
1426     printf("pm_winmm_term called\n");
1427 #endif
1428     for (i = 0; i < pm_descriptor_index; i++) {
1429         PmInternal * midi = (PmInternal*) descriptors[i].internalDescriptor;
1430         if (midi) {
1431             midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1432             if (m->handle.out) {
1433                 /* close next open device*/
1434 #ifdef DEBUG
1435                 if (doneAny == 0) {
1436                     printf("begin closing open devices...\n");
1437                     doneAny = 1;
1438                 }
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);
1444                 }
1445 #endif
1446                 /* close all open ports */
1447                 (*midi->dictionary->close)(midi);
1448             }
1449         }
1450     }
1451     if (midi_in_caps) {
1452         pm_free(midi_in_caps);
1453         midi_in_caps = NULL;
1454     }
1455     if (midi_out_caps) {
1456         pm_free(midi_out_caps);
1457         midi_out_caps = NULL;
1458     }
1459 #ifdef DEBUG
1460     if (doneAny) {
1461         printf("warning: devices were left open. They have been closed.\n");
1462     }
1463     printf("pm_winmm_term exiting\n");
1464 #endif
1465     pm_descriptor_index = 0;
1466 }