update wavesaudio backend, now supports Windows (ASIO) as well as OS X (CoreAudio)
[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 #endif
6
7 #ifndef _WIN32_WINNT
8     /* without this define, InitializeCriticalSectionAndSpinCount is 
9      * undefined. This version level means "Windows 2000 and higher" 
10      */
11     #define _WIN32_WINNT 0x0500
12 #endif
13
14 #include "windows.h"
15 #include "mmsystem.h"
16 #include "portmidi.h"
17 #include "pmutil.h"
18 #include "pminternal.h"
19 #include "pmwinmm.h"
20 #include <string.h>
21 #include "porttime.h"
22
23 /* asserts used to verify portMidi code logic is sound; later may want
24     something more graceful */
25 #include <assert.h>
26 #ifdef DEBUG
27 /* this printf stuff really important for debugging client app w/host errors.
28     probably want to do something else besides read/write from/to console
29     for portability, however */
30 #define STRING_MAX 80
31 #include "stdio.h"
32 #endif
33
34 #define streql(x, y) (strcmp(x, y) == 0)
35
36 #define MIDI_SYSEX      0xf0
37 #define MIDI_EOX        0xf7
38
39 /* callback routines */
40 static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,
41                                        WORD wMsg, DWORD dwInstance, 
42                                        DWORD dwParam1, DWORD dwParam2);
43 static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
44                                               DWORD dwInstance, DWORD dwParam1, 
45                                               DWORD dwParam2);
46 #ifdef USE_SYSEX_BUFFERS
47 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
48                                         DWORD dwInstance, DWORD dwParam1, 
49                                         DWORD dwParam2);
50 #endif
51
52 extern pm_fns_node pm_winmm_in_dictionary;
53 extern pm_fns_node pm_winmm_out_dictionary;
54
55 static void winmm_out_delete(PmInternal *midi); /* forward reference */
56
57 /*
58 A note about buffers: WinMM seems to hold onto buffers longer than
59 one would expect, e.g. when I tried using 2 small buffers to send
60 long sysex messages, at some point WinMM held both buffers. This problem
61 was fixed by making buffers bigger. Therefore, it seems that there should 
62 be enough buffer space to hold a whole sysex message. 
63
64 The bufferSize passed into Pm_OpenInput (passed into here as buffer_len)
65 will be used to estimate the largest sysex message (= buffer_len * 4 bytes).
66 Call that the max_sysex_len = buffer_len * 4.
67
68 For simple midi output (latency == 0), allocate 3 buffers, each with half
69 the size of max_sysex_len, but each at least 256 bytes.
70
71 For stream output, there will already be enough space in very short
72 buffers, so use them, but make sure there are at least 16.
73
74 For input, use many small buffers rather than 2 large ones so that when 
75 there are short sysex messages arriving frequently (as in control surfaces)
76 there will be more free buffers to fill. Use max_sysex_len / 64 buffers,
77 but at least 16, of size 64 bytes each.
78
79 The following constants help to represent these design parameters:
80 */
81 #define NUM_SIMPLE_SYSEX_BUFFERS 3
82 #define MIN_SIMPLE_SYSEX_LEN 256
83
84 #define MIN_STREAM_BUFFERS 16
85 #define STREAM_BUFFER_LEN 24
86
87 #define INPUT_SYSEX_LEN 64
88 #define MIN_INPUT_BUFFERS 16
89
90 /* if we run out of space for output (assume this is due to a sysex msg,
91    expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN
92  */
93 #define NUM_EXPANSION_BUFFERS 128
94 #define EXPANSION_BUFFER_LEN 1024
95
96 /* A sysex buffer has 3 DWORDS as a header plus the actual message size */
97 #define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3)
98 /* A MIDIHDR with a sysex message is the buffer length plus the header size */
99 #define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR))
100 #ifdef USE_SYSEX_BUFFERS
101 /* Size of a MIDIHDR with a buffer contaning multiple MIDIEVENT structures */
102 #define MIDIHDR_SIZE(x) ((x) + sizeof(MIDIHDR))
103 #endif
104
105 /*
106 ==============================================================================
107 win32 mmedia system specific structure passed to midi callbacks
108 ==============================================================================
109 */
110
111 /* global winmm device info */
112 MIDIINCAPS *midi_in_caps = NULL;
113 MIDIINCAPS midi_in_mapper_caps;
114 UINT midi_num_inputs = 0;
115 MIDIOUTCAPS *midi_out_caps = NULL;
116 MIDIOUTCAPS midi_out_mapper_caps;
117 UINT midi_num_outputs = 0;
118
119 /* per device info */
120 typedef struct midiwinmm_struct {
121     union {
122         HMIDISTRM stream;   /* windows handle for stream */
123         HMIDIOUT out;       /* windows handle for out calls */
124         HMIDIIN in;         /* windows handle for in calls */
125     } handle;
126
127     /* midi output messages are sent in these buffers, which are allocated
128      * in a round-robin fashion, using next_buffer as an index
129      */
130     LPMIDIHDR *buffers;     /* pool of buffers for midi in or out data */
131     int max_buffers;        /* length of buffers array */
132     int buffers_expanded;   /* buffers array expanded for extra msgs? */
133     int num_buffers;        /* how many buffers allocated in buffers array */
134     int next_buffer;        /* index of next buffer to send */
135     HANDLE buffer_signal;   /* used to wait for buffer to become free */
136 #ifdef USE_SYSEX_BUFFERS
137     /* sysex buffers will be allocated only when
138      * a sysex message is sent. The size of the buffer is fixed.
139      */
140     LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */
141     int next_sysex_buffer;      /* index of next sysexbuffer to send */
142 #endif
143     unsigned long last_time;    /* last output time */
144     int first_message;          /* flag: treat first message differently */
145     int sysex_mode;             /* middle of sending sysex */
146     unsigned long sysex_word;   /* accumulate data when receiving sysex */
147     unsigned int sysex_byte_count; /* count how many received */
148     LPMIDIHDR hdr;              /* the message accumulating sysex to send */
149     unsigned long sync_time;    /* when did we last determine delta? */
150     long delta;                 /* difference between stream time and
151                                        real time */
152     int error;                  /* host error from doing port midi call */
153     CRITICAL_SECTION lock;      /* prevents reentrant callbacks (input only) */
154 } midiwinmm_node, *midiwinmm_type;
155
156
157 /*
158 =============================================================================
159 general MIDI device queries
160 =============================================================================
161 */
162 static void pm_winmm_general_inputs()
163 {
164     UINT i;
165     WORD wRtn;
166     midi_num_inputs = midiInGetNumDevs();
167     midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) * 
168                                            midi_num_inputs);
169     if (midi_in_caps == NULL) {
170         /* if you can't open a particular system-level midi interface
171          * (such as winmm), we just consider that system or API to be
172          * unavailable and move on without reporting an error.
173          */
174         return;
175     }
176
177     for (i = 0; i < midi_num_inputs; i++) {
178         wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],
179                                 sizeof(MIDIINCAPS));
180         if (wRtn == MMSYSERR_NOERROR) {
181             /* ignore errors here -- if pm_descriptor_max is exceeded, some
182                devices will not be accessible. */
183             pm_add_device("MMSystem", midi_in_caps[i].szPname, TRUE,
184                           (void *) i, &pm_winmm_in_dictionary);
185         }
186     }
187 }
188
189
190 static void pm_winmm_mapper_input()
191 {
192     WORD wRtn;
193     /* Note: if MIDIMAPPER opened as input (documentation implies you
194         can, but current system fails to retrieve input mapper
195         capabilities) then you still should retrieve some formof
196         setup info. */
197     wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,
198                             (LPMIDIINCAPS) & midi_in_mapper_caps, 
199                             sizeof(MIDIINCAPS));
200     if (wRtn == MMSYSERR_NOERROR) {
201         pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE,
202                       (void *) MIDIMAPPER, &pm_winmm_in_dictionary);
203     }
204 }
205
206
207 static void pm_winmm_general_outputs()
208 {
209     UINT i;
210     DWORD wRtn;
211     midi_num_outputs = midiOutGetNumDevs();
212     midi_out_caps = pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs );
213
214     if (midi_out_caps == NULL) {
215         /* no error is reported -- see pm_winmm_general_inputs */
216         return ;
217     }
218
219     for (i = 0; i < midi_num_outputs; i++) {
220         wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i],
221                                  sizeof(MIDIOUTCAPS));
222         if (wRtn == MMSYSERR_NOERROR) {
223             pm_add_device("MMSystem", midi_out_caps[i].szPname, FALSE,
224                           (void *) i, &pm_winmm_out_dictionary);
225         }
226     }
227 }
228
229
230 static void pm_winmm_mapper_output()
231 {
232     WORD wRtn;
233     /* Note: if MIDIMAPPER opened as output (pseudo MIDI device
234         maps device independent messages into device dependant ones,
235         via NT midimapper program) you still should get some setup info */
236     wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS)
237                              & midi_out_mapper_caps, sizeof(MIDIOUTCAPS));
238     if (wRtn == MMSYSERR_NOERROR) {
239         pm_add_device("MMSystem", midi_out_mapper_caps.szPname, FALSE,
240                       (void *) MIDIMAPPER, &pm_winmm_out_dictionary);
241     }
242 }
243
244
245 /*
246 =========================================================================================
247 host error handling
248 =========================================================================================
249 */
250 static unsigned int winmm_has_host_error(PmInternal * midi)
251 {
252     midiwinmm_type m = (midiwinmm_type)midi->descriptor;
253     return m->error;
254 }
255
256
257 /* str_copy_len -- like strcat, but won't overrun the destination string */
258 /*
259  * returns length of resulting string
260  */
261 static int str_copy_len(char *dst, char *src, int len)
262 {
263     strncpy(dst, src, len);
264     /* just in case suffex is greater then len, terminate with zero */
265     dst[len - 1] = 0;
266     return strlen(dst);
267 }
268
269
270 static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len)
271 {
272     /* precondition: midi != NULL */
273     midiwinmm_node * m = (midiwinmm_node *) midi->descriptor;
274     char *hdr1 = "Host error: ";
275     char *hdr2 = "Host callback error: ";
276
277     msg[0] = 0; /* initialize result string to empty */
278
279     if (descriptors[midi->device_id].pub.input) {
280         /* input and output use different winmm API calls */
281         if (m) { /* make sure there is an open device to examine */
282             if (m->error != MMSYSERR_NOERROR) {
283                 int n = str_copy_len(msg, hdr1, len);
284                 /* read and record host error */
285                 int err = midiInGetErrorText(m->error, msg + n, len - n);
286                 assert(err == MMSYSERR_NOERROR);
287                 m->error = MMSYSERR_NOERROR;
288             }
289         }
290     } else { /* output port */
291         if (m) {
292             if (m->error != MMSYSERR_NOERROR) {
293                 int n = str_copy_len(msg, hdr1, len);
294                 int err = midiOutGetErrorText(m->error, msg + n, len - n);
295                 assert(err == MMSYSERR_NOERROR);
296                 m->error = MMSYSERR_NOERROR;
297             }
298         }
299     }
300 }
301
302
303 /*
304 =============================================================================
305 buffer handling
306 =============================================================================
307 */
308 static MIDIHDR *allocate_buffer(long data_size)
309 {
310     LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
311     MIDIEVENT *evt;
312     if (!hdr) return NULL;
313     evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
314     hdr->lpData = (LPSTR) evt;
315     hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size);
316     hdr->dwBytesRecorded = 0;
317     hdr->dwFlags = 0;
318     hdr->dwUser = hdr->dwBufferLength;
319     return hdr;
320 }
321
322 #ifdef USE_SYSEX_BUFFERS
323 static MIDIHDR *allocate_sysex_buffer(long data_size)
324 {
325     /* we're actually allocating more than data_size because the buffer 
326      * will include the MIDIEVENT header in addition to the data 
327      */
328     LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
329     MIDIEVENT *evt;
330     if (!hdr) return NULL;
331     evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
332     hdr->lpData = (LPSTR) evt;
333     hdr->dwFlags = 0;
334     hdr->dwUser = 0;
335     return hdr;
336 }
337 #endif
338
339 static PmError allocate_buffers(midiwinmm_type m, long data_size, long count)
340 {
341     int i;
342     /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
343     m->num_buffers = 0; /* in case no memory can be allocated */
344     m->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count);
345     if (!m->buffers) return pmInsufficientMemory;
346     m->max_buffers = count;
347     for (i = 0; i < count; i++) {
348         LPMIDIHDR hdr = allocate_buffer(data_size);
349         if (!hdr) { /* free everything allocated so far and return */
350             for (i = i - 1; i >= 0; i--) pm_free(m->buffers[i]);
351             pm_free(m->buffers);
352             m->max_buffers = 0;
353             return pmInsufficientMemory;
354         }
355         m->buffers[i] = hdr; /* this may be NULL if allocation fails */
356     }
357     m->num_buffers = count;
358     return pmNoError;
359 }
360
361 #ifdef USE_SYSEX_BUFFERS
362 static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size)
363 {
364     PmError rslt = pmNoError;
365     /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
366     int i;
367     for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
368         LPMIDIHDR hdr = allocate_sysex_buffer(data_size);
369
370         if (!hdr) rslt = pmInsufficientMemory;
371         m->sysex_buffers[i] = hdr; /* this may be NULL if allocation fails */
372         hdr->dwFlags = 0; /* mark as free */
373     }
374     return rslt;
375 }
376 #endif
377
378 #ifdef USE_SYSEX_BUFFERS
379 static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi)
380 {
381     LPMIDIHDR r = NULL;
382     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
383     if (!m->sysex_buffers[0]) {
384         if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) {
385             return NULL;
386         }
387     }
388     /* busy wait until we find a free buffer */
389     while (TRUE) {
390         int i;
391         for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
392             /* cycle through buffers, modulo NUM_SYSEX_BUFFERS */
393             m->next_sysex_buffer++;
394             if (m->next_sysex_buffer >= NUM_SYSEX_BUFFERS) m->next_sysex_buffer = 0;
395             r = m->sysex_buffers[m->next_sysex_buffer];
396             if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_sysex_buffer;
397         }
398         /* after scanning every buffer and not finding anything, block */
399         if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
400 #ifdef DEBUG
401             printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n");
402 #endif
403         }
404     }
405 found_sysex_buffer:
406     r->dwBytesRecorded = 0;
407     r->dwBufferLength = 0; /* changed to correct value later */
408     return r;
409 }
410 #endif
411
412 static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
413 {
414     LPMIDIHDR r = NULL;
415     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
416     while (TRUE) {
417         int i;
418         for (i = 0; i < m->num_buffers; i++) {
419             /* cycle through buffers, modulo m->num_buffers */
420             m->next_buffer++;
421             if (m->next_buffer >= m->num_buffers) m->next_buffer = 0;
422             r = m->buffers[m->next_buffer];
423             if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;
424         }
425         /* after scanning every buffer and not finding anything, block */
426         if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
427 #ifdef DEBUG
428             printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n");
429 #endif
430             /* if we're trying to send a sysex message, maybe the 
431              * message is too big and we need more message buffers.
432              * Expand the buffer pool by 128KB using 1024-byte buffers.
433              */
434             /* first, expand the buffers array if necessary */
435             if (!m->buffers_expanded) {
436                 LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc(
437                         (m->num_buffers + NUM_EXPANSION_BUFFERS) * 
438                         sizeof(LPMIDIHDR));
439                 /* if no memory, we could return a no-memory error, but user
440                  * probably will be unprepared to deal with it. Maybe the
441                  * MIDI driver is temporarily hung so we should just wait.
442                  * I don't know the right answer, but waiting is easier.
443                  */
444                 if (!new_buffers) continue;
445                 /* copy buffers to new_buffers and replace buffers */
446                 memcpy(new_buffers, m->buffers, 
447                        m->num_buffers * sizeof(LPMIDIHDR));
448                 pm_free(m->buffers);
449                 m->buffers = new_buffers;
450                 m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS;
451                 m->buffers_expanded = TRUE;
452             }
453             /* next, add one buffer and return it */
454             if (m->num_buffers < m->max_buffers) {
455                 r = allocate_buffer(EXPANSION_BUFFER_LEN);
456                 /* again, if there's no memory, we may not really be 
457                  * dead -- maybe the system is temporarily hung and
458                  * we can just wait longer for a message buffer */
459                 if (!r) continue;
460                 m->buffers[m->num_buffers++] = r;
461                 goto found_buffer; /* break out of 2 loops */
462             }
463             /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers,
464              * and we have no free buffers to send. We'll just keep
465              * polling to see if any buffers show up.
466              */
467         }
468     }
469 found_buffer:
470     r->dwBytesRecorded = 0;
471     /* actual buffer length is saved in dwUser field */
472     r->dwBufferLength = (DWORD) r->dwUser;
473     return r;
474 }
475
476 #ifdef EXPANDING_SYSEX_BUFFERS
477 note: this is not working code, but might be useful if you want
478       to grow sysex buffers.
479 static PmError resize_sysex_buffer(PmInternal *midi, long old_size, long new_size)
480 {
481     LPMIDIHDR big;
482     int i;
483     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
484     /* buffer must be smaller than 64k, but be also a multiple of 4 */
485     if (new_size > 65520) {
486         if (old_size >= 65520)
487             return pmBufferMaxSize;
488         else
489             new_size = 65520;
490     }
491     /* allocate a bigger message  */
492     big = allocate_sysex_buffer(new_size);
493     /* printf("expand to %d bytes\n", new_size);*/
494     if (!big) return pmInsufficientMemory;
495     m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR));
496     if (m->error) {
497         pm_free(big);
498         return pmHostError;
499     }
500     /* make sure we're not going to overwrite any memory */
501     assert(old_size <= new_size);
502     memcpy(big->lpData, m->hdr->lpData, old_size);
503     /* keep track of how many sysex bytes are in message so far */
504     big->dwBytesRecorded = m->hdr->dwBytesRecorded;
505     big->dwBufferLength = new_size;
506     /* find which buffer this was, and replace it */
507     for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
508         if (m->sysex_buffers[i] == m->hdr) {
509             m->sysex_buffers[i] = big;
510             m->sysex_buffer_size[i] = new_size;
511             pm_free(m->hdr);
512             m->hdr = big;
513             break;
514         }
515     }
516     assert(i != NUM_SYSEX_BUFFERS);
517
518     return pmNoError;
519 }
520 #endif
521
522 /*
523 =========================================================================================
524 begin midi input implementation
525 =========================================================================================
526 */
527
528
529 static PmError allocate_input_buffer(HMIDIIN h, long buffer_len)
530 {
531     LPMIDIHDR hdr = allocate_buffer(buffer_len);
532     if (!hdr) return pmInsufficientMemory;
533     pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));
534     if (pm_hosterror) {
535         pm_free(hdr);
536         return pm_hosterror;
537     }
538     pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));
539     return pm_hosterror;
540 }
541
542
543 static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
544 {
545     DWORD dwDevice;
546     int i = midi->device_id;
547     int max_sysex_len = midi->buffer_len * 4;
548     int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN;
549     midiwinmm_type m;
550
551     dwDevice = (DWORD) descriptors[i].descriptor;
552
553     /* create system dependent device data */
554     m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
555     midi->descriptor = m;
556     if (!m) goto no_memory;
557     m->handle.in = NULL;
558     m->buffers = NULL; /* not used for input */
559     m->num_buffers = 0; /* not used for input */
560     m->max_buffers = FALSE; /* not used for input */
561     m->buffers_expanded = 0; /* not used for input */
562     m->next_buffer = 0; /* not used for input */
563     m->buffer_signal = 0; /* not used for input */
564 #ifdef USE_SYSEX_BUFFERS
565     for (i = 0; i < NUM_SYSEX_BUFFERS; i++) 
566         m->sysex_buffers[i] = NULL; /* not used for input */
567     m->next_sysex_buffer = 0; /* not used for input */
568 #endif
569     m->last_time = 0;
570     m->first_message = TRUE; /* not used for input */
571     m->sysex_mode = FALSE;
572     m->sysex_word = 0;
573     m->sysex_byte_count = 0;
574     m->hdr = NULL; /* not used for input */
575     m->sync_time = 0;
576     m->delta = 0;
577     m->error = MMSYSERR_NOERROR;
578     /* 4000 is based on Windows documentation -- that's the value used in the
579        memory manager. It's small enough that it should not hurt performance even
580        if it's not optimal.
581      */
582     InitializeCriticalSectionAndSpinCount(&m->lock, 4000);
583     /* open device */
584     pm_hosterror = midiInOpen(
585             &(m->handle.in),  /* input device handle */
586             dwDevice,  /* device ID */
587             (DWORD_PTR) winmm_in_callback,  /* callback address */
588             (DWORD_PTR) midi,  /* callback instance data */
589             CALLBACK_FUNCTION); /* callback is a procedure */
590     if (pm_hosterror) goto free_descriptor;
591
592     if (num_input_buffers < MIN_INPUT_BUFFERS)
593         num_input_buffers = MIN_INPUT_BUFFERS;
594     for (i = 0; i < num_input_buffers; i++) {
595         if (allocate_input_buffer(m->handle.in, INPUT_SYSEX_LEN)) {
596             /* either pm_hosterror was set, or the proper return code
597                is pmInsufficientMemory */
598             goto close_device;
599         }
600     }
601     /* start device */
602     pm_hosterror = midiInStart(m->handle.in);
603     if (pm_hosterror) goto reset_device;
604     return pmNoError;
605
606     /* undo steps leading up to the detected error */
607 reset_device:
608     /* ignore return code (we already have an error to report) */
609     midiInReset(m->handle.in);
610 close_device:
611     midiInClose(m->handle.in); /* ignore return code */
612 free_descriptor:
613     midi->descriptor = NULL;
614     pm_free(m);
615 no_memory:
616     if (pm_hosterror) {
617         int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
618                                      PM_HOST_ERROR_MSG_LEN);
619         assert(err == MMSYSERR_NOERROR);
620         return pmHostError;
621     }
622     /* if !pm_hosterror, then the error must be pmInsufficientMemory */
623     return pmInsufficientMemory;
624     /* note: if we return an error code, the device will be
625        closed and memory will be freed. It's up to the caller
626        to free the parameter midi */
627 }
628
629 static PmError winmm_in_poll(PmInternal *midi) {
630     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
631     return m->error;
632 }
633
634
635
636 /* winmm_in_close -- close an open midi input device */
637 /*
638  * assume midi is non-null (checked by caller)
639  */
640 static PmError winmm_in_close(PmInternal *midi)
641 {
642     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
643     if (!m) return pmBadPtr;
644     /* device to close */
645     if (pm_hosterror = midiInStop(m->handle.in)) {
646         midiInReset(m->handle.in); /* try to reset and close port */
647         midiInClose(m->handle.in);
648     } else if (pm_hosterror = midiInReset(m->handle.in)) {
649         midiInClose(m->handle.in); /* best effort to close midi port */
650     } else {
651         pm_hosterror = midiInClose(m->handle.in);
652     }
653     midi->descriptor = NULL;
654     DeleteCriticalSection(&m->lock);
655     pm_free(m); /* delete */
656     if (pm_hosterror) {
657         int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
658                                      PM_HOST_ERROR_MSG_LEN);
659         assert(err == MMSYSERR_NOERROR);
660         return pmHostError;
661     }
662     return pmNoError;
663 }
664
665
666 /* Callback function executed via midiInput SW interrupt (via midiInOpen). */
667 static void FAR PASCAL winmm_in_callback(
668     HMIDIIN hMidiIn,    /* midiInput device Handle */
669     WORD wMsg,          /* midi msg */
670     DWORD dwInstance,   /* application data */
671     DWORD dwParam1,     /* MIDI data */
672     DWORD dwParam2)    /* device timestamp (wrt most recent midiInStart) */
673 {
674     static int entry = 0;
675     PmInternal *midi = (PmInternal *) dwInstance;
676     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
677
678     /* NOTE: we do not just EnterCriticalSection() here because an
679      * MIM_CLOSE message arrives when the port is closed, but then
680      * the m->lock has been destroyed.
681      */
682
683     switch (wMsg) {
684     case MIM_DATA: {
685         /* if this callback is reentered with data, we're in trouble. 
686          * It's hard to imagine that Microsoft would allow callbacks 
687          * to be reentrant -- isn't the model that this is like a 
688          * hardware interrupt? -- but I've seen reentrant behavior 
689          * using a debugger, so it happens.
690          */
691         long new_driver_time;
692         EnterCriticalSection(&m->lock);
693
694         /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
695                 message LOB;
696            dwParam2 is time message received by input device driver, specified
697             in [ms] from when midiInStart called.
698            each message is expanded to include the status byte */
699
700         new_driver_time = dwParam2;
701
702         if ((dwParam1 & 0x80) == 0) {
703             /* not a status byte -- ignore it. This happened running the
704                sysex.c test under Win2K with MidiMan USB 1x1 interface,
705                but I can't reproduce it. -RBD
706              */
707             /* printf("non-status byte found\n"); */
708         } else { /* data to process */
709             PmEvent event;
710             if (midi->time_proc)
711                 dwParam2 = (*midi->time_proc)(midi->time_info);
712             event.timestamp = dwParam2;
713             event.message = dwParam1;
714             pm_read_short(midi, &event);
715         }
716         LeaveCriticalSection(&m->lock);
717         break;
718     }
719     case MIM_LONGDATA: {
720         MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
721         unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
722         unsigned int processed = 0;
723         int remaining = lpMidiHdr->dwBytesRecorded;
724
725         EnterCriticalSection(&m->lock);
726         /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", 
727                 lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
728         if (midi->time_proc)
729             dwParam2 = (*midi->time_proc)(midi->time_info);
730         /* can there be more than one message in one buffer? */
731         /* assume yes and iterate through them */
732         while (remaining > 0) {
733             unsigned int amt = pm_read_bytes(midi, data + processed, 
734                                              remaining, dwParam2);
735             remaining -= amt;
736             processed += amt;
737         }
738
739         /* when a device is closed, the pending MIM_LONGDATA buffers are
740            returned to this callback with dwBytesRecorded == 0. In this
741            case, we do not want to send them back to the interface (if
742            we do, the interface will not close, and Windows OS may hang). */
743         if (lpMidiHdr->dwBytesRecorded > 0) {
744             MMRESULT rslt;
745             lpMidiHdr->dwBytesRecorded = 0;
746             lpMidiHdr->dwFlags = 0;
747                         
748             /* note: no error checking -- can this actually fail? */
749             rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
750             assert(rslt == MMSYSERR_NOERROR);
751             /* note: I don't think this can fail except possibly for
752              * MMSYSERR_NOMEM, but the pain of reporting this
753              * unlikely but probably catastrophic error does not seem
754              * worth it.
755              */
756             rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
757             assert(rslt == MMSYSERR_NOERROR);
758             LeaveCriticalSection(&m->lock);
759         } else {
760             midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
761             LeaveCriticalSection(&m->lock);
762             pm_free(lpMidiHdr);
763         }
764         break;
765     }
766     case MIM_OPEN:
767         break;
768     case MIM_CLOSE:
769         break;
770     case MIM_ERROR:
771         /* printf("MIM_ERROR\n"); */
772         break;
773     case MIM_LONGERROR:
774         /* printf("MIM_LONGERROR\n"); */
775         break;
776     default:
777         break;
778     }
779 }
780
781 /*
782 =========================================================================================
783 begin midi output implementation
784 =========================================================================================
785 */
786
787 /* begin helper routines used by midiOutStream interface */
788
789 /* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */
790 static int add_to_buffer(midiwinmm_type m, LPMIDIHDR hdr,
791                          unsigned long delta, unsigned long msg)
792 {
793     unsigned long *ptr = (unsigned long *)
794                          (hdr->lpData + hdr->dwBytesRecorded);
795     *ptr++ = delta; /* dwDeltaTime */
796     *ptr++ = 0;     /* dwStream */
797     *ptr++ = msg;   /* dwEvent */
798     hdr->dwBytesRecorded += 3 * sizeof(long);
799     /* if the addition of three more words (a message) would extend beyond
800        the buffer length, then return TRUE (full)
801      */
802     return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;
803 }
804
805
806 static PmTimestamp pm_time_get(midiwinmm_type m)
807 {
808     MMTIME mmtime;
809     MMRESULT wRtn;
810     mmtime.wType = TIME_TICKS;
811     mmtime.u.ticks = 0;
812     wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime));
813     assert(wRtn == MMSYSERR_NOERROR);
814     return mmtime.u.ticks;
815 }
816
817
818 /* end helper routines used by midiOutStream interface */
819
820
821 static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
822 {
823     DWORD dwDevice;
824     int i = midi->device_id;
825     midiwinmm_type m;
826     MIDIPROPTEMPO propdata;
827     MIDIPROPTIMEDIV divdata;
828     int max_sysex_len = midi->buffer_len * 4;
829     int output_buffer_len;
830     int num_buffers;
831     dwDevice = (DWORD) descriptors[i].descriptor;
832
833     /* create system dependent device data */
834     m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
835     midi->descriptor = m;
836     if (!m) goto no_memory;
837     m->handle.out = NULL;
838     m->buffers = NULL;
839     m->num_buffers = 0;
840     m->max_buffers = 0;
841     m->buffers_expanded = FALSE;
842     m->next_buffer = 0;
843 #ifdef USE_SYSEX_BUFFERS
844     m->sysex_buffers[0] = NULL;
845     m->sysex_buffers[1] = NULL;
846     m->next_sysex_buffer = 0;
847 #endif
848     m->last_time = 0;
849     m->first_message = TRUE; /* we treat first message as special case */
850     m->sysex_mode = FALSE;
851     m->sysex_word = 0;
852     m->sysex_byte_count = 0;
853     m->hdr = NULL;
854     m->sync_time = 0;
855     m->delta = 0;
856     m->error = MMSYSERR_NOERROR;
857
858     /* create a signal */
859     m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);
860
861     /* this should only fail when there are very serious problems */
862     assert(m->buffer_signal);
863
864     /* open device */
865     if (midi->latency == 0) {
866         /* use simple midi out calls */
867         pm_hosterror = midiOutOpen(
868                 (LPHMIDIOUT) & m->handle.out,  /* device Handle */
869                 dwDevice,  /* device ID  */
870                 /* note: same callback fn as for StreamOpen: */
871                 (DWORD_PTR) winmm_streamout_callback, /* callback fn */
872                 (DWORD_PTR) midi,  /* callback instance data */
873                 CALLBACK_FUNCTION); /* callback type */
874     } else {
875         /* use stream-based midi output (schedulable in future) */
876         pm_hosterror = midiStreamOpen(
877                 &m->handle.stream,  /* device Handle */
878                 (LPUINT) & dwDevice,  /* device ID pointer */
879                 1,  /* reserved, must be 1 */
880                 (DWORD_PTR) winmm_streamout_callback,
881                 (DWORD_PTR) midi,  /* callback instance data */
882                 CALLBACK_FUNCTION);
883     }
884     if (pm_hosterror != MMSYSERR_NOERROR) {
885         goto free_descriptor;
886     }
887
888     if (midi->latency == 0) {
889         num_buffers = NUM_SIMPLE_SYSEX_BUFFERS;
890         output_buffer_len = max_sysex_len / num_buffers;
891         if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN)
892             output_buffer_len = MIN_SIMPLE_SYSEX_LEN;
893     } else {
894         long dur = 0;
895         num_buffers = max(midi->buffer_len, midi->latency / 2);
896         if (num_buffers < MIN_STREAM_BUFFERS)
897             num_buffers = MIN_STREAM_BUFFERS;
898         output_buffer_len = STREAM_BUFFER_LEN;
899
900         propdata.cbStruct = sizeof(MIDIPROPTEMPO);
901         propdata.dwTempo = 480000; /* microseconds per quarter */
902         pm_hosterror = midiStreamProperty(m->handle.stream,
903                                           (LPBYTE) & propdata,
904                                           MIDIPROP_SET | MIDIPROP_TEMPO);
905         if (pm_hosterror) goto close_device;
906
907         divdata.cbStruct = sizeof(MIDIPROPTEMPO);
908         divdata.dwTimeDiv = 480;   /* divisions per quarter */
909         pm_hosterror = midiStreamProperty(m->handle.stream,
910                                           (LPBYTE) & divdata,
911                                           MIDIPROP_SET | MIDIPROP_TIMEDIV);
912         if (pm_hosterror) goto close_device;
913     }
914     /* allocate buffers */
915     if (allocate_buffers(m, output_buffer_len, num_buffers)) 
916         goto free_buffers;
917     /* start device */
918     if (midi->latency != 0) {
919         pm_hosterror = midiStreamRestart(m->handle.stream);
920         if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;
921     }
922     return pmNoError;
923
924 free_buffers:
925     /* buffers are freed below by winmm_out_delete */
926 close_device:
927     midiOutClose(m->handle.out);
928 free_descriptor:
929     midi->descriptor = NULL;
930     winmm_out_delete(midi); /* frees buffers and m */
931 no_memory:
932     if (pm_hosterror) {
933         int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
934                                       PM_HOST_ERROR_MSG_LEN);
935         assert(err == MMSYSERR_NOERROR);
936         return pmHostError;
937     }
938     return pmInsufficientMemory;
939 }
940
941
942 /* winmm_out_delete -- carefully free data associated with midi */
943 /**/
944 static void winmm_out_delete(PmInternal *midi)
945 {
946     int i;
947     /* delete system dependent device data */
948     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
949     if (m) {
950         if (m->buffer_signal) {
951             /* don't report errors -- better not to stop cleanup */
952             CloseHandle(m->buffer_signal);
953         }
954         /* if using stream output, free buffers */
955         for (i = 0; i < m->num_buffers; i++) {
956             if (m->buffers[i]) pm_free(m->buffers[i]);
957         }
958         m->num_buffers = 0;
959         pm_free(m->buffers);
960         m->max_buffers = 0;
961 #ifdef USE_SYSEX_BUFFERS
962         /* free sysex buffers */
963         for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
964             if (m->sysex_buffers[i]) pm_free(m->sysex_buffers[i]);
965         }
966 #endif
967     }
968     midi->descriptor = NULL;
969     pm_free(m); /* delete */
970 }
971
972
973 /* see comments for winmm_in_close */
974 static PmError winmm_out_close(PmInternal *midi)
975 {
976     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
977     if (m->handle.out) {
978         /* device to close */
979         if (midi->latency == 0) {
980             pm_hosterror = midiOutClose(m->handle.out);
981         } else {
982             pm_hosterror = midiStreamClose(m->handle.stream);
983         }
984         /* regardless of outcome, free memory */
985         winmm_out_delete(midi);
986     }
987     if (pm_hosterror) {
988         int err = midiOutGetErrorText(pm_hosterror,
989                                       (char *) pm_hosterror_text,
990                                       PM_HOST_ERROR_MSG_LEN);
991         assert(err == MMSYSERR_NOERROR);
992         return pmHostError;
993     }
994     return pmNoError;
995 }
996
997
998 static PmError winmm_out_abort(PmInternal *midi)
999 {
1000     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1001     m->error = MMSYSERR_NOERROR;
1002
1003     /* only stop output streams */
1004     if (midi->latency > 0) {
1005         m->error = midiStreamStop(m->handle.stream);
1006     }
1007     return m->error ? pmHostError : pmNoError;
1008 }
1009
1010
1011 static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)
1012 {
1013     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1014     assert(m);
1015     if (m->hdr) {
1016         m->error = midiOutPrepareHeader(m->handle.out, m->hdr, 
1017                                         sizeof(MIDIHDR));
1018         if (m->error) {
1019             /* do not send message */
1020         } else if (midi->latency == 0) {
1021             /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded
1022              * should be zero. This is set in get_free_sysex_buffer(). 
1023              * The msg length goes in dwBufferLength in spite of what
1024              * Microsoft documentation says (or doesn't say). */
1025             m->hdr->dwBufferLength = m->hdr->dwBytesRecorded;
1026             m->hdr->dwBytesRecorded = 0;
1027             m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
1028         } else {
1029             m->error = midiStreamOut(m->handle.stream, m->hdr, 
1030                                      sizeof(MIDIHDR));
1031         }
1032         midi->fill_base = NULL;
1033         m->hdr = NULL;
1034         if (m->error) {
1035             m->hdr->dwFlags = 0; /* release the buffer */
1036             return pmHostError;
1037         }
1038     }
1039     return pmNoError;
1040 }
1041
1042
1043
1044 #ifdef GARBAGE
1045 static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte)
1046 {
1047     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1048     unsigned char *msg_buffer;
1049
1050     /* at the beginning of sysex, m->hdr is NULL */
1051     if (!m->hdr) { /* allocate a buffer if none allocated yet */
1052         m->hdr = get_free_output_buffer(midi);
1053         if (!m->hdr) return pmInsufficientMemory;
1054         m->sysex_byte_count = 0;
1055     }
1056     /* figure out where to write byte */
1057     msg_buffer = (unsigned char *) (m->hdr->lpData);
1058     assert(m->hdr->lpData == (char *) (m->hdr + 1));
1059
1060     /* check for overflow */
1061     if (m->sysex_byte_count >= m->hdr->dwBufferLength) {
1062         /* allocate a bigger message -- double it every time */
1063         LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2);
1064         /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */
1065         if (!big) return pmInsufficientMemory;
1066         m->error = midiOutPrepareHeader(m->handle.out, big,
1067                                         sizeof(MIDIHDR));
1068         if (m->error) {
1069             m->hdr = NULL;
1070             return pmHostError;
1071         }
1072         memcpy(big->lpData, msg_buffer, m->sysex_byte_count);
1073         msg_buffer = (unsigned char *) (big->lpData);
1074         if (m->buffers[0] == m->hdr) {
1075             m->buffers[0] = big;
1076             pm_free(m->hdr);
1077             /* printf("freed m->hdr\n"); */
1078         } else if (m->buffers[1] == m->hdr) {
1079             m->buffers[1] = big;
1080             pm_free(m->hdr);
1081             /* printf("freed m->hdr\n"); */
1082         }
1083         m->hdr = big;
1084     }
1085
1086     /* append byte to message */
1087     msg_buffer[m->sysex_byte_count++] = byte;
1088
1089     /* see if we have a complete message */
1090     if (byte == MIDI_EOX) {
1091         m->hdr->dwBytesRecorded = m->sysex_byte_count;
1092         /*
1093         { int i; int len = m->hdr->dwBytesRecorded;
1094           printf("OutLongMsg %d ", len);
1095           for (i = 0; i < len; i++) {
1096               printf("%2x ", msg_buffer[i]);
1097           }
1098         }
1099         */
1100         m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
1101         m->hdr = NULL; /* stop using this message buffer */
1102         if (m->error) return pmHostError;
1103     }
1104     return pmNoError;
1105 }
1106 #endif
1107
1108
1109 static PmError winmm_write_short(PmInternal *midi, PmEvent *event)
1110 {
1111     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1112     PmError rslt = pmNoError;
1113     assert(m);
1114
1115     if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */
1116         m->error = midiOutShortMsg(m->handle.out, event->message);
1117         if (m->error) rslt = pmHostError;
1118     } else {  /* use midiStream interface -- pass data through buffers */
1119         unsigned long when = event->timestamp;
1120         unsigned long delta;
1121         int full;
1122         if (when == 0) when = midi->now;
1123         /* when is in real_time; translate to intended stream time */
1124         when = when + m->delta + midi->latency;
1125         /* make sure we don't go backward in time */
1126         if (when < m->last_time) when = m->last_time;
1127         delta = when - m->last_time;
1128         m->last_time = when;
1129         /* before we insert any data, we must have a buffer */
1130         if (m->hdr == NULL) {
1131             /* stream interface: buffers allocated when stream is opened */
1132             m->hdr = get_free_output_buffer(midi);
1133         }
1134         full = add_to_buffer(m, m->hdr, delta, event->message);
1135         if (full) rslt = winmm_write_flush(midi, when);
1136     }
1137     return rslt;
1138 }
1139
1140 #define winmm_begin_sysex winmm_write_flush
1141 #ifndef winmm_begin_sysex
1142 static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)
1143 {
1144     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1145     PmError rslt = pmNoError;
1146
1147     if (midi->latency == 0) {
1148         /* do nothing -- it's handled in winmm_write_byte */
1149     } else {
1150         /* sysex expects an empty sysex buffer, so send whatever is here */
1151         rslt = winmm_write_flush(midi);
1152     }
1153     return rslt;
1154 }
1155 #endif
1156
1157 static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)
1158 {
1159     /* could check for callback_error here, but I haven't checked
1160      * what happens if we exit early and don't finish the sysex msg
1161      * and clean up
1162      */
1163     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1164     PmError rslt = pmNoError;
1165     LPMIDIHDR hdr = m->hdr;
1166     if (!hdr) return rslt; /* something bad happened earlier,
1167             do not report an error because it would have been 
1168             reported (at least) once already */
1169     /* a(n old) version of MIDI YOKE requires a zero byte after
1170      * the sysex message, but do not increment dwBytesRecorded: */
1171     hdr->lpData[hdr->dwBytesRecorded] = 0;
1172     if (midi->latency == 0) {
1173 #ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX
1174         /* DEBUG CODE: */
1175         { int i; int len = m->hdr->dwBufferLength;
1176           printf("OutLongMsg %d ", len);
1177           for (i = 0; i < len; i++) {
1178               printf("%2x ", (unsigned char) (m->hdr->lpData[i]));
1179           }
1180         }
1181 #endif
1182     } else {
1183         /* Using stream interface. There are accumulated bytes in m->hdr
1184            to send using midiStreamOut
1185          */
1186         /* add bytes recorded to MIDIEVENT length, but don't
1187            count the MIDIEVENT data (3 longs) */
1188         MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData);
1189         evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long);
1190         /* round up BytesRecorded to multiple of 4 */
1191         hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3;
1192     }
1193     rslt = winmm_write_flush(midi, timestamp);
1194     return rslt;
1195 }
1196
1197
1198 static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
1199                                 PmTimestamp timestamp)
1200 {
1201     /* write a sysex byte */
1202     PmError rslt = pmNoError;
1203     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1204     LPMIDIHDR hdr = m->hdr;
1205     unsigned char *msg_buffer;
1206     assert(m);
1207     if (!hdr) {
1208         m->hdr = hdr = get_free_output_buffer(midi);
1209         assert(hdr);
1210         midi->fill_base = (unsigned char *) m->hdr->lpData;
1211         midi->fill_offset_ptr = &(hdr->dwBytesRecorded);
1212         /* when buffer fills, Pm_WriteSysEx will revert to calling
1213          * pmwin_write_byte, which expect to have space, so leave
1214          * one byte free for pmwin_write_byte. Leave another byte
1215          * of space for zero after message to make early version of 
1216          * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */
1217         midi->fill_length = hdr->dwBufferLength - 2;
1218         if (midi->latency != 0) {
1219             unsigned long when = (unsigned long) timestamp;
1220             unsigned long delta;
1221             unsigned long *ptr;
1222             if (when == 0) when = midi->now;
1223             /* when is in real_time; translate to intended stream time */
1224             when = when + m->delta + midi->latency;
1225             /* make sure we don't go backward in time */
1226             if (when < m->last_time) when = m->last_time;
1227             delta = when - m->last_time;
1228             m->last_time = when;
1229
1230             ptr = (unsigned long *) hdr->lpData;
1231             *ptr++ = delta;
1232             *ptr++ = 0;
1233             *ptr = MEVT_F_LONG;
1234             hdr->dwBytesRecorded = 3 * sizeof(long);
1235             /* data will be added at an offset of dwBytesRecorded ... */
1236         }
1237     }
1238     /* add the data byte */
1239     msg_buffer = (unsigned char *) (hdr->lpData);
1240     msg_buffer[hdr->dwBytesRecorded++] = byte;
1241
1242     /* see if buffer is full, leave one byte extra for pad */
1243     if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) {
1244         /* write what we've got and continue */
1245         rslt = winmm_end_sysex(midi, timestamp); 
1246     }
1247     return rslt;
1248 }
1249
1250 #ifdef EXPANDING_SYSEX_BUFFERS
1251 note: this code is here as an aid in case you want sysex buffers
1252       to expand to hold large messages completely. If so, you
1253       will want to change SYSEX_BYTES_PER_BUFFER above to some
1254       variable that remembers the buffer size. A good place to 
1255       put this value would be in the hdr->dwUser field.
1256
1257             rslt = resize_sysex_buffer(midi, m->sysex_byte_count, 
1258                                        m->sysex_byte_count * 2);
1259
1260             if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */
1261 #endif
1262 #ifdef EXPANDING_SYSEX_BUFFERS
1263             int bytesRecorded = hdr->dwBytesRecorded; /* this field gets wiped out, so we'll save it */
1264             rslt = resize_sysex_buffer(midi, bytesRecorded, 2 * bytesRecorded);
1265             hdr->dwBytesRecorded = bytesRecorded;
1266
1267             if (rslt == pmBufferMaxSize) /* if buffer can't be resized */
1268 #endif
1269
1270
1271
1272 static PmTimestamp winmm_synchronize(PmInternal *midi)
1273 {
1274     midiwinmm_type m;
1275     unsigned long pm_stream_time_2;
1276     unsigned long real_time;
1277     unsigned long pm_stream_time;
1278
1279     /* only synchronize if we are using stream interface */
1280     if (midi->latency == 0) return 0;
1281
1282     /* figure out the time */
1283     m = (midiwinmm_type) midi->descriptor;
1284     pm_stream_time_2 = pm_time_get(m);
1285
1286     do {
1287         /* read real_time between two reads of stream time */
1288         pm_stream_time = pm_stream_time_2;
1289         real_time = (*midi->time_proc)(midi->time_info);
1290         pm_stream_time_2 = pm_time_get(m);
1291         /* repeat if more than 1ms elapsed */
1292     } while (pm_stream_time_2 > pm_stream_time + 1);
1293     m->delta = pm_stream_time - real_time;
1294     m->sync_time = real_time;
1295     return real_time;
1296 }
1297
1298 #ifdef USE_SYSEX_BUFFERS
1299 /* winmm_out_callback -- recycle sysex buffers */
1300 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
1301                                         DWORD dwInstance, DWORD dwParam1, 
1302                                         DWORD dwParam2)
1303 {
1304     PmInternal *midi = (PmInternal *) dwInstance;
1305     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1306     LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
1307     int err = 0;  /* set to 0 so that no buffer match will also be an error */
1308
1309     /* Future optimization: eliminate UnprepareHeader calls -- they aren't
1310        necessary; however, this code uses the prepared-flag to indicate which
1311        buffers are free, so we need to do something to flag empty buffers if
1312        we leave them prepared
1313      */
1314     /*
1315     printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
1316            hdr, wMsg, MOM_DONE);
1317     */
1318     if (wMsg == MOM_DONE) {
1319         MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
1320                                               sizeof(MIDIHDR));
1321         assert(ret == MMSYSERR_NOERROR);
1322     }
1323     /* notify waiting sender that a buffer is available */
1324     err = SetEvent(m->buffer_signal);
1325     assert(err); /* false -> error */
1326 }
1327 #endif
1328
1329 /* winmm_streamout_callback -- unprepare (free) buffer header */
1330 static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
1331         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
1332 {
1333     PmInternal *midi = (PmInternal *) dwInstance;
1334     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1335     LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
1336     int err;
1337
1338     /* Even if an error is pending, I think we should unprepare msgs and
1339        signal their arrival
1340      */
1341     /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
1342            hdr, wMsg, MOM_DONE); */
1343     if (wMsg == MOM_DONE) {
1344         MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
1345                                               sizeof(MIDIHDR));
1346         assert(ret == MMSYSERR_NOERROR);
1347     }
1348     /* signal client in case it is blocked waiting for buffer */
1349     err = SetEvent(m->buffer_signal);
1350     assert(err); /* false -> error */
1351 }
1352
1353
1354 /*
1355 =========================================================================================
1356 begin exported functions
1357 =========================================================================================
1358 */
1359
1360 #define winmm_in_abort pm_fail_fn
1361 pm_fns_node pm_winmm_in_dictionary = {
1362                                          none_write_short,
1363                                          none_sysex,
1364                                          none_sysex,
1365                                          none_write_byte,
1366                                          none_write_short,
1367                                          none_write_flush,
1368                                          winmm_synchronize,
1369                                          winmm_in_open,
1370                                          winmm_in_abort,
1371                                          winmm_in_close,
1372                                          winmm_in_poll,
1373                                          winmm_has_host_error,
1374                                          winmm_get_host_error
1375                                      };
1376
1377 pm_fns_node pm_winmm_out_dictionary = {
1378                                           winmm_write_short,
1379                                           winmm_begin_sysex,
1380                                           winmm_end_sysex,
1381                                           winmm_write_byte,
1382                                           winmm_write_short,  /* short realtime message */
1383                                           winmm_write_flush,
1384                                           winmm_synchronize,
1385                                           winmm_out_open,
1386                                           winmm_out_abort,
1387                                           winmm_out_close,
1388                                           none_poll,
1389                                           winmm_has_host_error,
1390                                           winmm_get_host_error
1391                                       };
1392
1393
1394 /* initialize winmm interface. Note that if there is something wrong
1395    with winmm (e.g. it is not supported or installed), it is not an
1396    error. We should simply return without having added any devices to
1397    the table. Hence, no error code is returned. Furthermore, this init
1398    code is called along with every other supported interface, so the
1399    user would have a very hard time figuring out what hardware and API
1400    generated the error. Finally, it would add complexity to pmwin.c to
1401    remember where the error code came from in order to convert to text.
1402  */
1403 void pm_winmm_init( void )
1404 {
1405     pm_winmm_mapper_input();
1406     pm_winmm_mapper_output();
1407     pm_winmm_general_inputs();
1408     pm_winmm_general_outputs();
1409 }
1410
1411
1412 /* no error codes are returned, even if errors are encountered, because
1413    there is probably nothing the user could do (e.g. it would be an error
1414    to retry.
1415  */
1416 void pm_winmm_term( void )
1417 {
1418     int i;
1419 #ifdef DEBUG
1420     char msg[PM_HOST_ERROR_MSG_LEN];
1421 #endif
1422     int doneAny = 0;
1423 #ifdef DEBUG
1424     printf("pm_winmm_term called\n");
1425 #endif
1426     for (i = 0; i < pm_descriptor_index; i++) {
1427         PmInternal * midi = descriptors[i].internalDescriptor;
1428         if (midi) {
1429             midiwinmm_type m = (midiwinmm_type) midi->descriptor;
1430             if (m->handle.out) {
1431                 /* close next open device*/
1432 #ifdef DEBUG
1433                 if (doneAny == 0) {
1434                     printf("begin closing open devices...\n");
1435                     doneAny = 1;
1436                 }
1437                 /* report any host errors; this EXTEREMELY useful when
1438                    trying to debug client app */
1439                 if (winmm_has_host_error(midi)) {
1440                     winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN);
1441                     printf("%s\n", msg);
1442                 }
1443 #endif
1444                 /* close all open ports */
1445                 (*midi->dictionary->close)(midi);
1446             }
1447         }
1448     }
1449     if (midi_in_caps) {
1450         pm_free(midi_in_caps);
1451         midi_in_caps = NULL;
1452     }
1453     if (midi_out_caps) {
1454         pm_free(midi_out_caps);
1455         midi_out_caps = NULL;
1456     }
1457 #ifdef DEBUG
1458     if (doneAny) {
1459         printf("warning: devices were left open. They have been closed.\n");
1460     }
1461     printf("pm_winmm_term exiting\n");
1462 #endif
1463     pm_descriptor_index = 0;
1464 }