Source file: /~heha/argon/multimed.zip/SNDBLST/MIDIIN.C

/****************************************************************************
 *
 *   midiin.c
 *
 *   Copyright (c) 1991-1992 Microsoft Corporation.  All Rights Reserved.
 *
 ***************************************************************************/

#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include "sndblst.h"

extern MIDIINMSGCLIENT  gMIMC;          /* MIDI input msg client */

/*****************************************************************************

    internal function prototypes

 ****************************************************************************/ 

static void NEAR PASCAL midFreeQ(void);
static void NEAR PASCAL midGetDevCaps(LPBYTE lpCaps, WORD wSize);

/****************************************************************************
 * @doc INTERNAL
 *
 * @api void | midFreeQ | Free all buffers in the MIQueue.
 *
 * @comm Currently this is only called after sending off any partially filled
 *     buffers, so all buffers here are empty.  The timestamp value is 0 in
 *     this case.
 *
 * @rdesc There is no return value.
 ***************************************************************************/ 
static void NEAR PASCAL midFreeQ(void)
{
LPMIDIHDR   lpH, lpN;
DWORD       dwTime;

    lpH = gMIMC.lpmhQueue;              /* point to top of the queue */
    gMIMC.lpmhQueue = NULL;             /* mark the queue as empty */
    gMIMC.dwCurData = 0L;

    dwTime = timeGetTime() - gMIMC.dwRefTime;

    while (lpH) {
        lpN = lpH->lpNext;
        lpH->dwFlags |= MHDR_DONE;
        lpH->dwFlags &= ~MHDR_INQUEUE;
        lpH->dwBytesRecorded = 0;
        midiCallback(&gMidiInClient, MIM_LONGDATA, (DWORD)lpH, dwTime);
        lpH = lpN;
    }
}

/****************************************************************************
 * @doc INTERNAL
 *
 * @api void | midAddBuffer | This function adds a buffer to the list of
 *      wave input buffers.
 *
 * @parm LPWAVEHDR | lpWIHdr | Far pointer to a wave input data header.
 *
 * @rdesc The return value is an MMSYS error code (0L if success).
 *
 * @comm We assume that the header and block are both page locked when they
 *      get here.  That is, it has been 'prepared.'
 ***************************************************************************/ 
static DWORD NEAR PASCAL midAddBuffer( LPMIDIHDR lpmh )
{
LPMIDIHDR   lpN;

    /* check if it's been prepared */
    if (!(lpmh->dwFlags & MHDR_PREPARED))
        return MIDIERR_UNPREPARED;

    /* check if it's in our queue already */
    if (lpmh->dwFlags & MHDR_INQUEUE)
        return MIDIERR_STILLPLAYING;

    /* add the buffer to our queue */
    lpmh->dwFlags |= MHDR_INQUEUE;
    lpmh->dwFlags &= ~MHDR_DONE;

    /* sanity */
    lpmh->dwBytesRecorded = 0;
    lpmh->lpNext = NULL;

    CritEnter();
    {
        if ( lpN = gMIMC.lpmhQueue ) {
            while ( lpN->lpNext && (lpN = lpN->lpNext) )
                ;

            lpN->lpNext = lpmh;
        }

        else 
            gMIMC.lpmhQueue = lpmh;
    }
    CritLeave();

    /* return success */
    return ( 0L );
}

/****************************************************************************
 * @doc INTERNAL
 * 
 * @api WORD | midSendPartBuffer | This function is called from midStop().
 *     It looks at the buffer at the head of the queue and, if it contains
 *     any data, marks it as done as sends it back to the client.
 * 
 * @rdesc The return value is the number of bytes transfered. A value of zero
 *     indicates that there was no more data in the input queue.
 ***************************************************************************/ 
void NEAR PASCAL midSendPartBuffer(void)
{
LPMIDIHDR lpH;

    if ( gMIMC.lpmhQueue && gMIMC.dwCurData ) {
        lpH = gMIMC.lpmhQueue;
        gMIMC.lpmhQueue = gMIMC.lpmhQueue->lpNext;
        gMIMC.dwCurData = 0L;
        lpH->dwFlags |= MHDR_DONE;
        lpH->dwFlags &= ~MHDR_INQUEUE;
        midiCallback(&gMidiInClient, MIM_LONGERROR, (DWORD)lpH,gMIMC.dwMsgTime);
    }
}

/*****************************************************************************
 * @doc INTERNAL
 *
 * @api void | midGetDevCaps | Get the capabilities of the port.
 *
 * @parm LPBYTE | lpCaps | Far pointer to a MIDIINCAPS structure.
 *
 * @parm WORD | wSize | Size of the MIDIINCAPS structure.
 *
 * @rdesc There is no return value.
 ****************************************************************************/
static void NEAR PASCAL midGetDevCaps(LPBYTE lpCaps, WORD wSize)
{
MIDIINCAPS mc;

    mc.wMid = MM_MICROSOFT;
    mc.wPid = MM_SNDBLST_MIDIIN;
    mc.vDriverVersion = DRIVER_VERSION;
    LoadString(ghModule, IDS_SNDBLSTMIDIIN, mc.szPname, MAXPNAMELEN);

    MemCopy(lpCaps, &mc, min(wSize, sizeof(MIDIINCAPS)));
}

/****************************************************************************

    This function conforms to the standard MIDI input driver message proc

****************************************************************************/
DWORD FAR PASCAL _loadds midMessage(WORD id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
{
    if ( !gfEnabled ) {
        if ( msg == MIDM_INIT ) {
            D1("MIDM_INIT");
            InitDisplayConfigErrors();
            return 0L;
        }

        D1("midMessage called while disabled");
        return ( (msg == MIDM_GETNUMDEVS) ? 0L : MMSYSERR_NOTENABLED );
    }

    /* this driver only supports one device */
    if ( id != 0 ) {
        D1("invalid midi device id");
        return MMSYSERR_BADDEVICEID;
    }

    switch ( msg ) {
        case MIDM_GETNUMDEVS:
            D1("MIDM_GETNUMDEVS");
            return 1L;

        case MIDM_GETDEVCAPS:
            D1("MIDM_GETDEVCAPS");
            midGetDevCaps((LPBYTE)dwParam1, (WORD)dwParam2);
            return 0L;

        case MIDM_OPEN:
            D1("MIDM_OPEN");

            /* now attempt to 'acquire' the MIDI input hardware */
            if ( midAcquireHardware() ) {
                D1("MIDI input hardware is unavailable!");
                return MMSYSERR_ALLOCATED;
            }

            /* allocate my structure containing info about my client (global */
            /* because I only allow one client to access midi input). */
            gMidiInClient.dwCallback = ((LPMIDIOPENDESC)dwParam1)->dwCallback;
            gMidiInClient.dwInstance = ((LPMIDIOPENDESC)dwParam1)->dwInstance;
            gMidiInClient.hMidi      = ((LPMIDIOPENDESC)dwParam1)->hMidi;
            gMidiInClient.dwFlags    = dwParam2;
            
            /* initialize queue stuff */
            gMIMC.dwCurData = 0;
            gMIMC.lpmhQueue = 0;

            /*  NOTE: we must initialize reference time in case someone adds */
            /*  longdata buffers after opening, then resets the midi stream */
            /*  without starting midi input.  Otherwise, midFreeQ would give */
            /*  inconsistent timestamps */
            gMIMC.dwRefTime = timeGetTime();

            /* notify client */
            midiCallback(&gMidiInClient, MIM_OPEN, 0L, 0L);

            return 0L;

        case MIDM_CLOSE:
            D1("MIDM_CLOSE");

            if ( gMIMC.lpmhQueue )
                return MIDIERR_STILLPLAYING;

            /* just in case they started input without adding buffers */
            midStop();

            /* now 'release' the MIDI input hardware */
            if ( midReleaseHardware() ) {
                D1("MIDI input hardware could NOT be released!");
            }

            /* notify client */
            midiCallback(&gMidiInClient, MIM_CLOSE, 0L, 0L);

            return 0L;

        case MIDM_ADDBUFFER:
            D1("MIDM_ADDBUFFER");

            /* attempt to add the buffer */
            return midAddBuffer((LPMIDIHDR)dwParam1);

        case MIDM_START:
            D1("MIDM_START");

            /* initialize all the parsing status variables */
            gMIMC.fSysEx = 0;
            gMIMC.bStatus = 0;
            gMIMC.bBytesLeft = 0;
            gMIMC.bBytePos = 0;
            gMIMC.dwShortMsg = 0;
            gMIMC.dwMsgTime = 0;
            gMIMC.dwRefTime = 0;
            gMIMC.dwCurData = 0;

            /* get a new reference time */
            gMIMC.dwRefTime = timeGetTime();

            midStart();
            return 0L;

        case MIDM_STOP:
            D1("MIDM_STOP");
            midStop();
            return 0L;

        case MIDM_RESET:
            D1("MIDM_RESET");

            /* stop if it is started and release all buffers */
            midStop();
            midFreeQ();
            return 0L;

        default:
            return MMSYSERR_NOTSUPPORTED;
    }

    /* should never get here */
    AssertF(0);
    return MMSYSERR_NOTSUPPORTED;
}
Detected encoding: ASCII (7 bit)2