Пример #1
0
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;
}
Пример #2
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--;
}
Пример #3
0
/* 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;
    }
}