~ubuntu-branches/ubuntu/precise/puredata/precise

« back to all changes in this revision

Viewing changes to portmidi/pm_win/pmwinmm.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Brossier
  • Date: 2009-12-22 21:29:31 UTC
  • mfrom: (1.2.6 upstream) (4.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091222212931-nhwkzapjwsmjao1l
Tags: 0.42.5-3
* debian/control:
  - add community site to homepage field
  - improve long description
  - remove Replaces and Conflicts fields
  - add Suggests on pd-csound, pd-pdp, pd-zexy, pd-aubio
* debian/rules: add per-arch configuration flags
* debian/patches/02_kfreebsd.diff:
  - also define pd_tilde_dllextent on FreeBSD
  - fix typo (really closing #414414 this time)
  - also add hurd glue
* debian/patches/04_hurd.diff:
  - add hurd glue and s_midi_dummy.c

Show diffs side-by-side

added added

removed removed

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