void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp) { PmEvent event; /* there may be nothing in the buffer */ if (midi->sysex_message_count == 0) return; /* nothing to flush */ event.message = midi->sysex_message; event.timestamp = timestamp; pm_read_short(midi, &event); midi->sysex_message_count = 0; midi->sysex_message = 0; }
/* Callback function executed via midiInput SW interrupt (via midiInOpen). */ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ WORD wMsg, /* midi msg */ DWORD dwInstance, /* application data */ DWORD dwParam1, /* MIDI data */ DWORD dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (++entry > 1) { assert(FALSE); } /* for simplicity, this logic perhaps overly conservative */ /* note also that this might leak memory if buffers are being returned as a result of midiInReset */ if (m->callback_error) { entry--; return; } switch (wMsg) { case MIM_DATA: { /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of message LOB; dwParam2 is time message received by input device driver, specified in [ms] from when midiInStart called. each message is expanded to include the status byte */ long new_driver_time = dwParam2; if ((dwParam1 & 0x80) == 0) { /* not a status byte -- ignore it. This happens running the sysex.c test under Win2K with MidiMan USB 1x1 interface. Is it a driver bug or a Win32 bug? If not, there's a bug here somewhere. -RBD */ } else { /* data to process */ PmEvent event; if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); event.timestamp = dwParam2; event.message = dwParam1; pm_read_short(midi, &event); } break; } case MIM_LONGDATA: { MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1; unsigned char *data = lpMidiHdr->lpData; unsigned int i = 0; long size = sizeof(MIDIHDR) + lpMidiHdr->dwBufferLength; /* ignore sysex data, but free returned buffers */ if (lpMidiHdr->dwBytesRecorded > 0 && midi->filters & PM_FILT_SYSEX) { m->callback_error = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); break; } if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); while (i < lpMidiHdr->dwBytesRecorded) { /* collect bytes from *data into a word */ pm_read_byte(midi, *data, dwParam2); data++; i++; } /* when a device is closed, the pending MIM_LONGDATA buffers are returned to this callback with dwBytesRecorded == 0. In this case, we do not want to send them back to the interface (if we do, the interface will not close, and Windows OS may hang). */ if (lpMidiHdr->dwBytesRecorded > 0) { m->callback_error = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); } else { pm_free(lpMidiHdr); } break; } case MIM_OPEN: /* fall thru */ case MIM_CLOSE: case MIM_ERROR: case MIM_LONGERROR: default: break; } entry--; }
/* Callback function executed via midiInput SW interrupt (via midiInOpen). */ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ UINT wMsg, /* midi msg */ DWORD_PTR dwInstance, /* application data */ DWORD_PTR dwParam1, /* MIDI data */ DWORD_PTR dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; /* NOTE: we do not just EnterCriticalSection() here because an * MIM_CLOSE message arrives when the port is closed, but then * the m->lock has been destroyed. */ switch (wMsg) { case MIM_DATA: { /* if this callback is reentered with data, we're in trouble. * It's hard to imagine that Microsoft would allow callbacks * to be reentrant -- isn't the model that this is like a * hardware interrupt? -- but I've seen reentrant behavior * using a debugger, so it happens. */ EnterCriticalSection(&m->lock); /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of message LOB; dwParam2 is time message received by input device driver, specified in [ms] from when midiInStart called. each message is expanded to include the status byte */ if ((dwParam1 & 0x80) == 0) { /* not a status byte -- ignore it. This happened running the sysex.c test under Win2K with MidiMan USB 1x1 interface, but I can't reproduce it. -RBD */ /* printf("non-status byte found\n"); */ } else { /* data to process */ PmEvent event; if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); event.timestamp = (PmTimestamp)dwParam2; event.message = (PmMessage)dwParam1; pm_read_short(midi, &event); } LeaveCriticalSection(&m->lock); break; } case MIM_LONGDATA: { MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1; unsigned char *data = (unsigned char *) lpMidiHdr->lpData; unsigned int processed = 0; int remaining = lpMidiHdr->dwBytesRecorded; EnterCriticalSection(&m->lock); /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */ if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); /* can there be more than one message in one buffer? */ /* assume yes and iterate through them */ while (remaining > 0) { unsigned int amt = pm_read_bytes(midi, data + processed, remaining, (PmTimestamp)dwParam2); remaining -= amt; processed += amt; } /* when a device is closed, the pending MIM_LONGDATA buffers are returned to this callback with dwBytesRecorded == 0. In this case, we do not want to send them back to the interface (if we do, the interface will not close, and Windows OS may hang). */ if (lpMidiHdr->dwBytesRecorded > 0) { MMRESULT rslt; lpMidiHdr->dwBytesRecorded = 0; lpMidiHdr->dwFlags = 0; /* note: no error checking -- can this actually fail? */ rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); /* note: I don't think this can fail except possibly for * MMSYSERR_NOMEM, but the pain of reporting this * unlikely but probably catastrophic error does not seem * worth it. */ rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); LeaveCriticalSection(&m->lock); } else { midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR)); LeaveCriticalSection(&m->lock); pm_free(lpMidiHdr); } break; } case MIM_OPEN: break; case MIM_CLOSE: break; case MIM_ERROR: /* printf("MIM_ERROR\n"); */ break; case MIM_LONGERROR: /* printf("MIM_LONGERROR\n"); */ break; default: break; } }