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

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

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

extern BYTE gfWaveOutPaused;        /* wavefix.c */

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

    internal function prototypes

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

static void NEAR PASCAL wodFreeQ(void);
static void NEAR PASCAL wodGetDevCaps(LPBYTE lpCaps, WORD wSize);

/****************************************************************************
 * @doc INTERNAL
 *
 * @api void | wodFreeQ | Free all buffers.
 *
 * @rdesc There is no return value.
 ***************************************************************************/ 
static void NEAR PASCAL wodFreeQ(void)
{
extern void FAR PASCAL wodPostAllHeaders( void );
LPWAVEHDR lpH, lpN;

    AssertF(!gfDMABusy);         /* DMA better not be going!! */

    /* first free the lpDeadHeads... */
    wodPostAllHeaders();

    if (lpLoopStart)
       lpH = lpLoopStart;
    else
       lpH = glpWOQueue;           /* point to top of the queue */

    glpWOQueue = NULL;             /* mark the queue as empty */
    lpLoopStart = NULL;
    hpCurData = NULL;
    dwCurCount = 0L;
    dwLoopCount = 0L;
    gfDMABusy = 0;

    while (lpH) {
        lpN = lpH->lpNext;
        wodBlockFinished(lpH);
        lpH = lpN;
    }
}

/****************************************************************************
 * @doc INTERNAL
 *
 * @api void | wodGetDevCaps | Get the device capabilities.
 *
 * @parm LPBYTE | lpCaps | Far pointer to a WAVEOUTCAPS structure to
 *      receive the information.
 *
 * @parm WORD | wSize | Size of the WAVEOUTCAPS structure.
 *
 * @rdesc There is no return value.
 ***************************************************************************/
static void NEAR PASCAL wodGetDevCaps(LPBYTE lpCaps, WORD wSize)
{
WAVEOUTCAPS wc;

    wc.wMid = MM_MICROSOFT;
    wc.wPid = MM_SNDBLST_WAVEOUT;
    wc.vDriverVersion = DRIVER_VERSION;
    wc.dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08;
    wc.wChannels = 1;
    wc.dwSupport = 0;
    LoadString(ghModule, IDS_SNDBLSTWAVEOUT, wc.szPname, MAXPNAMELEN);

    MemCopy(lpCaps, &wc, min(wSize, sizeof(wc)));
}

/****************************************************************************
 * @doc INTERNAL
 *
 * @api DWORD | waveGetPos | Get the stream position in samples.
 *
 * @parm DWORD | dwUser | The DWORD passed to the driver from the open call.
 *
 * @parm LPBYTE | lpInfo | Far pointer to an MMTIME structure.
 *
 * @parm WORD | wSize | Size of the MMTIME structure.
 *
 * @rdesc The return value is zero if successful.
 ***************************************************************************/
DWORD NEAR PASCAL waveGetPos(DWORD dwUser, LPMMTIME lpmmt, WORD wSize)
{
NPWAVEALLOC pClient;

    if (wSize < sizeof(MMTIME))
        return MMSYSERR_ERROR;

    pClient = (NPWAVEALLOC)LOWORD(dwUser);

    if (lpmmt->wType == TIME_BYTES) {
        lpmmt->u.cb = pClient->dwByteCount;
    }

    /* default is samples - the sndblst card only supports 8 bit mono, */
    /* so the sample count is equal to the byte count */
    else {
        lpmmt->wType = TIME_SAMPLES;
        lpmmt->u.sample = pClient->dwByteCount;
        D2("POS: #DX#AX");
    }

    return 0L;
}

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

    This function conforms to the standard Wave output driver message proc

****************************************************************************/
DWORD FAR PASCAL _loadds wodMessage(WORD id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
{
const WAVEFORMAT FAR *lpFmt;      /* pointer to passed format */
NPWAVEALLOC           pOutClient; /* pointer to client information structure */

    if (!gfEnabled) {
        if ( msg == WODM_INIT ) {
            D1("WODM_INIT");
            InitDisplayConfigErrors();
            return 0L;
        }

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

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

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

        case WODM_GETDEVCAPS:
            D1("WODM_GETDEVCAPS");
            wodGetDevCaps((LPBYTE)dwParam1, (WORD)dwParam2);
            return 0L;

        case WODM_OPEN:
            D1("WODM_OPEN");

            /*  dwParam1 contains a pointer to a WAVEOPENDESC
             *  dwParam2 contains wave driver specific flags in the LOWORD
             *  and generic driver flags in the HIWORD
             */

            /* make sure we can handle the format */
            lpFmt = ((LPWAVEOPENDESC)dwParam1)->lpFormat;
            if ((lpFmt->wFormatTag != WAVE_FORMAT_PCM) ||
                (lpFmt->nChannels != 1) ||
                (lpFmt->nSamplesPerSec < 4000) ||
                (lpFmt->nSamplesPerSec > 23000) ||
                (lpFmt->nAvgBytesPerSec != lpFmt->nSamplesPerSec) ||
                (lpFmt->nBlockAlign < 1) ||
                (((LPPCMWAVEFORMAT)lpFmt)->wBitsPerSample != 8))
            {
                return WAVERR_BADFORMAT;
            }

            /* did they just want format information? */
            if (dwParam2 & WAVE_FORMAT_QUERY)
                return 0L;

            /* attempt to 'acquire' the Wave output hardware */
            if ( wodAcquireHardware() ) {
                D1("Wave output hardware is not available!");
                return MMSYSERR_ALLOCATED;
            }

            /* allocate my per-client structure */
            pOutClient = (NPWAVEALLOC)LocalAlloc(LPTR, sizeof(WAVEALLOC));
            if (pOutClient == NULL) {
                wodReleaseHardware();
                return MMSYSERR_NOMEM;
            }

            /* and fill it with info */
            pOutClient->dwCallback  = ((LPWAVEOPENDESC)dwParam1)->dwCallback;
            pOutClient->dwInstance  = ((LPWAVEOPENDESC)dwParam1)->dwInstance;
            pOutClient->hWave       = ((LPWAVEOPENDESC)dwParam1)->hWave;
            pOutClient->dwFlags     = dwParam2;
            pOutClient->dwByteCount = 0L;
            pOutClient->pcmwf       = *((LPPCMWAVEFORMAT)lpFmt);

            /* give the client my driver dw */
            *((LPDWORD)dwUser) = MAKELONG(pOutClient, 0);

            /* set the sample rate */
            dspSetSampleRate((WORD)lpFmt->nSamplesPerSec);

            /* sent client his OPEN callback message */
            waveCallback(pOutClient, WOM_OPEN, 0L);

            return 0L;

        case WODM_CLOSE:
            D1("WODM_CLOSE");

            if (glpWOQueue)
                return WAVERR_STILLPLAYING;

            /* wait, in case there's one last 2K block being played */
            wodWaitForDMA();

            /* call client's callback */
            pOutClient = (NPWAVEALLOC)LOWORD(dwUser);
            waveCallback(pOutClient, WOM_CLOSE, 0L);

            /* free the allocated memory */
            LocalFree((LOCALHANDLE)pOutClient);

            /* now 'release' the Wave output hardware */
            if ( wodReleaseHardware() ) {
                D1("Wave output hardware could NOT be released!");
            }

            return 0L;

        case WODM_WRITE:
            D1("WODM_WRITE");
            AssertF(dwParam1 != NULL);
            AssertF(!(((LPWAVEHDR)dwParam1)->dwFlags & ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)));

            ((LPWAVEHDR)dwParam1)->dwFlags &= (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP);

            AssertF(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED);

            /* check if it's been prepared */
            if (!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED))
                return WAVERR_UNPREPARED;

            AssertF(!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE));

            /* if it is already in our Q, then we cannot do this */
            if ( ((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE )
                return ( WAVERR_STILLPLAYING );

            /* store the pointer to my WAVEALLOC structure in the wavehdr */
            pOutClient = (NPWAVEALLOC)LOWORD(dwUser);
            ((LPWAVEHDR)dwParam1)->reserved = (DWORD)(LPSTR)pOutClient;

            /* add the buffer to our queue */
            ((LPWAVEHDR)dwParam1)->dwFlags |= WHDR_INQUEUE;
            ((LPWAVEHDR)dwParam1)->dwFlags &= ~WHDR_DONE;
            wodWrite((LPWAVEHDR)dwParam1);

            return 0L;

        case WODM_PAUSE:
            D1("WODM_PAUSE");
            wodPause();
            AssertF(!gfDMABusy);
            return 0L;

        case WODM_RESTART:
            D1("WODM_RESTART");
            wodResume();
            return 0L;

        case WODM_RESET:
            D1("WODM_RESET");

            /* halt DMA immediately--will always set gfDMAbusy = FALSE */
            wodHaltDMA();
            wodFreeQ();          /* free all buffers */

            AssertF(!gfDMABusy);
            gfWaveOutPaused = 0;
            bBreakLoop = 0;

            /* reset byte count */
            pOutClient = (NPWAVEALLOC)LOWORD(dwUser);
            pOutClient->dwByteCount = 0L;

            return 0L;

        case WODM_BREAKLOOP:
            D1("WODM_BREAKLOOP");
            if (glpWOQueue)
                bBreakLoop = 1;
            return 0L;

        case WODM_GETPOS:
            D1("WODM_GETPOS");
            return waveGetPos(dwUser, (LPMMTIME)dwParam1, (WORD)dwParam2);

        default:
            return MMSYSERR_NOTSUPPORTED;
    }

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