/*

Name: GUS_DRV1.C

Description:
   GUS software mixer and streaming audio driver.  This driver has been de-
   signed to work in conjunction with the standard GUS hardware mixer dri-
   vers as a sound effects channel.

Portability:

MSDOS:  BC(y)   Watcom(y)       DJGPP(y)
Win95:  n
Os2:    n
Linux:  n

(y) - yes
(n) - no (not possible or not useful)
(?) - may be possible, but not tested

*/

#include "gus.h"
#include "mirq.h"
#include "mdma.h"


static DMAMEM *GUS_LEFTMEM = NULL, *GUS_RIGHTMEM = NULL;
static SBYTE  *GUS_LEFTBUF, *GUS_RIGHTBUF;
static SBYTE  *GUS_MIXBUF;
static UBYTE   gus_left, gus_right;    // sample-handles for gus memory


BOOL GUSMIX_Init(void)
{
    GUS_Common_Init();

    if(VC_Init()) return 1;

    GUS_LEFTMEM  = MDma_AllocMem(md_dmabufsize/2);
    GUS_RIGHTMEM = MDma_AllocMem(md_dmabufsize/2);
    GUS_MIXBUF   = _mm_malloc(md_dmabufsize);

    if(GUS_LEFTMEM==NULL || GUS_RIGHTMEM==NULL || GUS_MIXBUF==NULL)
    {   GUSMIX_Exit();
        return 1;
    }

    GUS_LEFTBUF  = (SBYTE *)MDma_GetPtr(GUS_LEFTMEM);
    GUS_RIGHTBUF = (SBYTE *)MDma_GetPtr(GUS_RIGHTMEM);

    return 0;
}

static void GUSMIX_Exit(void)
{
    MDma_FreeMem(GUS_LEFTMEM);
    MDma_FreeMem(GUS_RIGHTMEM);
    free(GUS_MIXBUF);
    VC_Exit();
}


BOOL GUSMIX_SetNumChannels(int hardware, int software)
{
    if(hardware > 32) hardware = 32;
    md_numchn = hardware;

    if(ghld!=NULL) free(ghld);
    if((ghld = _mm_calloc(sizeof(GHOLD),hardware)) == NULL) return 1;

    if(VC_SetNumChannels(0,software)) return 1;

    return 0;
}    


static void GUSMIX_PlayStart(void)
{
    VC_PlayStart();

    // clear the dma buffer

    VC_SilenceBytes(GUS_LEFTBUF,md_dmabufsize/2);
    MDma_Commit(GUS_LEFTMEM,0,md_dmabufsize);
    UltraDownloadDma(gus_right);
    if(!MDma_Start(GUS_DRAM_DMA,GUS_LEFTMEM,md_dmabufsize/2,WRITE_DMA)) return;

    VC_SilenceBytes(GUS_RIGHTBUF,md_dmabufsize/2);
    MDma_Commit(GUS_LEFTMEM,0,md_dmabufsize);
    UltraWaitDramDma(); UltraDownloadDma(gus_left);
    if(!MDma_Start(GUS_DRAM_DMA,GUS_RIGHTMEM,md_dmabufsize/2,WRITE_DMA)) return;
}


static UWORD last = 0;
static UWORD curr = 0;

void GUSMIX_Update(void)
{
    UWORD  todo,index;
    SWORD  *ww,*dw;
    UBYTE  *bb,*bw;
    int i;

    // The GUS software mixer streams audio just as the GUSDK says:
    // Allocate two sample spaces in GUS RAM, one for left and one for
    // right.  Now use DMA to stream audio into these buffers, cycling
    // constantly to avoid skips and pops.

    if(UltraDramDmaActive()) return;    // do nothing if DMA still running

    curr = GUS_VoiceGetPosition(gus_left);
    if(curr==last) return;

    if(curr>last)
    {   todo  = curr-last;
        index = last;
    } else
    {   todo = (md_dmabufsize-last) + curr;
    }

    VC_WriteBytes(GUS_MIXBUF,todo*2);

    // Music is mixed to a std. left/right alternating format.  We need
    // them completely separate.  So do that here -->

    if(md_mode & DMODE_16BITS)
    {   ww = (SWORD *)GUS_MIXBUF;
        dw = (SWORD *)GUS_MIXBUF;
        for(i=0; i<todo; i++, dw++, ww+=2)
        {   *dw = *ww;
            dw[todo/2] = ww[1];
        }
    } else
    {   bb = (UBYTE *)GUS_MIXBUF;
        bw = (UBYTE *)GUS_MIXBUF;
        for(i=0; i<todo; i++, bw++, bb+=2)
        {   *bw = *bb;
            bw[todo] = bb[1];
        }
    }
    
    UltraDmaHandler(NULL);

    MDma_Commit(GUS_LEFTMEM,0,todo);
    UltraDownloadDma(gus_left);
    if(!MDma_Start(GUS_DRAM_DMA,GUS_LEFTMEM,todo,WRITE_DMA)) return;

    MDma_Commit(GUS_RIGHTMEM,0,todo);
    UltraDownloadDma(gus_right);    
    if(!MDma_Start(GUS_DRAM_DMA,GUS_RIGHTMEM,todo,WRITE_DMA)) return;

}



