/*      dsmnsnd.c
 *
 * Mixing No Sound Sound Device
 *
 * $Id: dsmnsnd.c,v 1.1 1996/07/29 19:35:39 pekangas Exp $
 *
 * Copyright 1996 Petteri Kangaslampi and Jarno Paananen
 *
 * This file is part of the MIDAS Sound System, and may only be
 * used, modified and distributed under the terms of the MIDAS
 * Sound System license, LICENSE.TXT. By continuing to use,
 * modify or distribute this file you indicate that you have
 * read the license and understand and accept it fully.
*/

/* None of these functions can fail and practically none of them does
   anything. */

#include "lang.h"

#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#include "mtypes.h"
#include "errors.h"
#include "sdevice.h"
#include "dsm.h"

RCSID(const char *dsmnsnd_rcsid = "$Id: dsmnsnd.c,v 1.1 1996/07/29 19:35:39 pekangas Exp $";)

#define MIXRATE 4000
#define MIXMODE dsmMixMono
#define OUTPUTMODE sd16bit | sdMono
#define MAXTIME 500
#define MINTIME 10


    /* A lot of functions do not use their arguments: */
//#ifdef __WATCOMC__
//#pragma off (unreferenced)
//#endif




/* Names and stuff: */
static char     *nsndCard = "No Sound";


/* Variables: */
static DWORD    prevPlayTime;
static DWORD    playElemsLeft;
static unsigned nsndMasterVolume;
static unsigned updateMix;              /* number of elements to mix between
                                           two updates */
static unsigned mixLeft;                /* number of elements to mix before
                                           next update */


/* Local prototypes: */
int CALLING nsndSetUpdRate(unsigned updRate);


enum nsndFunctIDs
{
    ID_nsndDetect = ID_nsnd,
    ID_nsndInit,
    ID_nsndClose,
    ID_nsndGetMixRate,
    ID_nsndGetMode,
    ID_nsndOpenChans,
    ID_nsndCloseChans,
    ID_nsndClearChans,
    ID_nsndMute,
    ID_nsndPause,
    ID_nsndSetMaster,
    ID_nsndPlaySound,
    ID_nsndStopSound,
    ID_nsndSetRate,
    ID_nsndGetRate,
    ID_nsndSetVol,
    ID_nsndSetInst,
    ID_nsndSetPos,
    ID_nsndGetPos,
    ID_nsndSetPanning,
    ID_nsndGetPanning,
    ID_nsndMuteChannel,
    ID_nsndAddInst,
    ID_nsndRemInst,
    ID_nsndSetUpdRate,
    ID_nsndPlay,
    ID_nsndGetMasterVolume,
    ID_nsndGetVolume,
    ID_nsndGetInstrument,
    ID_nsndStartPlay,
    ID_nsndSetAmplification,
    ID_nsndGetAmplification
};




static int CALLING nsndDetect(int *result)
{
    /* No Sound is always there */
    *result = 1;
    return OK;
}


static int CALLING nsndInit(unsigned mixRate, unsigned mode)
{
    int         error;

    /* Initialize DSM - we'll be mixing the data: */
    if ( (error = dsmInit(MIXRATE, MIXMODE, 16)) != OK )
        PASSERROR(ID_nsndInit);

    /* Set update rate to 50Hz: */
    if ( (error = nsndSetUpdRate(5000)) != OK )
        PASSERROR(ID_nsndInit);

    /* Set real DSM master volume to 0 to speed up mixing: */
    if ( (error = dsmSetMasterVolume(0)) != OK )
        PASSERROR(ID_nsndInit);

    /* Initialize "previous" playing tick count: */
#ifdef __WIN32__
    prevPlayTime = GetTickCount();
#endif

    return OK;
}


static int CALLING nsndClose(void)
{
    int         error;

    /* Just uninitialize DSM: */
    if ( (error = dsmClose()) != OK )
        PASSERROR(ID_nsndClose);

    return OK;
}


int CALLING nsndGetMode(unsigned *mode)
{
    /* Return our default mode: */
    *mode = OUTPUTMODE;
    return OK;
}


int CALLING nsndSetMasterVolume(unsigned masterVolume)
{
    /* Just store the master volume, don't set it to DSM: */
    nsndMasterVolume = masterVolume;

    return OK;
}


int CALLING nsndGetMasterVolume(unsigned *masterVolume)
{
    /* Return our stored master vol: */
    *masterVolume = nsndMasterVolume;

    return OK;
}


int CALLING nsndSetUpdRate(unsigned updRate)
{
    /* Calculate number of elements to mix between two updates: (even) */
    mixLeft = updateMix = ((unsigned) ((100L * (ulong) MIXRATE) /
        ((ulong) updRate)) + 1) & 0xFFFFFFFE;

    return OK;
}


int CALLING nsndStartPlay(void)
{
    DWORD       time, timeDiff;;

    /* Get the time in milliseconds since last nsndStartPlay(): */
#ifdef __WIN32__
    time = GetTickCount();
#endif
    timeDiff = time - prevPlayTime;
    prevPlayTime = time;

    /* Restrict the time difference to reasonable values: */
    if ( timeDiff > MAXTIME )
        timeDiff = MAXTIME;
    if ( timeDiff < MINTIME )
        timeDiff = 0;

    /* Calculate the number of elements that fits into this time - it is the
       amount we'll mix this polling time: */
    playElemsLeft = (timeDiff * MIXRATE) / 1000;

    return OK;
}


int CALLING nsndPlay(int *callMP)
{
    int         error;
    unsigned    dsmBufSize;
    unsigned    numElems, doNow;

    if ( !playElemsLeft )
    {
        *callMP = 0;
        return OK;
    }

#ifdef __32__
    dsmBufSize = dsmMixBufferSize >> 2;
#else
    dsmBufSize = dsmMixBufferSize >> 1;
#endif
#if MIXMODE == dsmMixStereo
    dsmBufSize >>= 1;
#endif

    if ( playElemsLeft > mixLeft )
        numElems = mixLeft;
    else
        numElems = playElemsLeft;
    mixLeft -= numElems;
    playElemsLeft -= numElems;

    while ( numElems )
    {
        if ( numElems > dsmBufSize )
            doNow = dsmBufSize;
        else
            doNow = numElems;
        numElems -= doNow;

        if ( (error = dsmMixData(doNow)) != OK )
            PASSERROR(ID_nsndPlay)
    }

    /* Check if the music player should be called: */
    if ( mixLeft == 0 )
    {
        mixLeft = updateMix;
        *callMP = 1;
    }
    else
    {
        *callMP = 0;
    }

    return OK;
}


/* And the struct: */

SoundDevice MixNoSound = {
    0,                                  /* Poll to tempo */
    sdUseDSM,
    0,
    0,
    0,
    1,
    1,
    sdMono | sd16bit,
    "Mixing No Sound Sound Device",
    &nsndCard,
    0,
    NULL,
    &nsndDetect,
    &nsndInit,
    &nsndClose,
    &dsmGetMixRate,
    &nsndGetMode,
    &dsmOpenChannels,
    &dsmCloseChannels,
    &dsmClearChannels,
    &dsmMute,
    &dsmPause,
    &dsmSetMasterVolume,
    &dsmGetMasterVolume,
    &dsmSetAmplification,
    &dsmGetAmplification,
    &dsmPlaySound,
    &dsmReleaseSound,
    &dsmStopSound,
    &dsmSetRate,
    &dsmGetRate,
    &dsmSetVolume,
    &dsmGetVolume,
    &dsmSetSample,
    &dsmGetSample,
    &dsmSetPosition,
    &dsmGetPosition,
    &dsmGetDirection,
    &dsmSetPanning,
    &dsmGetPanning,
    &dsmMuteChannel,
    &dsmAddSample,
    &dsmRemoveSample,
    &nsndSetUpdRate,
    &nsndStartPlay,
    &nsndPlay
#ifdef SUPPORTSTREAMS
    ,
    &dsmStartStream,
    &dsmStopStream
#endif
};


/*
 * $Log: dsmnsnd.c,v $
 * Revision 1.1  1996/07/29 19:35:39  pekangas
 * Initial revision
 *
 * Revision 1.1  1996/05/22 20:49:33  pekangas
 * Initial revision
 *
*/