/*

Name:
DRV_PAU.C

Description:
Mikmod driver for output to 8-bit Paula channels.

Portability:

This code is Amiga chipset specific.

This port was done on 28/01/97 by Tony Bybell.
bybell@cse.psu.edu

*/

#include <exec/types.h>
#include <exec/memory.h>
#include <devices/audio.h>
#include <graphics/gfxbase.h>
#include <proto/all.h>
#include <stdlib.h>
#include <stdio.h>
#define  AMIGA_PAULADRV
#include "mikmod.h"

#define PAULABUFFERSIZE 8192

struct  GfxBase *LocalGfxBase;
UBYTE   whichchannell[]={1,8};

UBYTE   whichchannelr[]={2,4};

int     DBFlag=0;
short   IsSixteenBit=0;
short   IsStereo=0;

struct  IOAudio *AIOptrl=NULL;
struct  MsgPort *portl=NULL;
struct  Message *msgl=NULL;
ULONG   devicel;

struct  IOAudio *AIOptrr=NULL;
struct  MsgPort *portr=NULL;
struct  Message *msgr=NULL;
ULONG   devicer;


LONG    clock=3579545;
LONG    slen=0;

char *PAULA_DMABUF=NULL;
char *PAULA_LEFT[2], *PAULA_RIGHT[2];


static void Paula_Exit(void)
{
int i;

VC_Exit();

        if(portr)
                {
                DeletePort(portr);
                portr=NULL;
                }

        if(AIOptrr)
                {
                CloseDevice((struct IORequest *)AIOptrr);
                FreeMem(AIOptrr,sizeof(struct IOAudio));
                AIOptrr=NULL;
                }
                
        if(portl)
                {
                DeletePort(portl);
                portl=NULL;
                }

        if(AIOptrl)
                {
                CloseDevice((struct IORequest *)AIOptrl);
                FreeMem(AIOptrl,sizeof(struct IOAudio));
                AIOptrl=NULL;
                }

        for(i=0;i<2;i++)
                {
                if(PAULA_LEFT[i])FreeMem(PAULA_LEFT[i], slen);
                if(PAULA_RIGHT[i])FreeMem(PAULA_RIGHT[i],slen);
                PAULA_LEFT[i]=PAULA_RIGHT[i]=NULL;
                }

        if(PAULA_DMABUF)
                {
                FreeMem(PAULA_DMABUF,  PAULABUFFERSIZE);
                PAULA_DMABUF=NULL;
                }
}


static int Paula_IsThere(void)
{
return 1;       /* Paula is always there */
}


static int Paula_Init(void)
{
char *filter=(char *)0xbfe001;

*filter|=0x02;  /* Turn off the low pass filter */

if(IsSixteenBit=(md_mode&DMODE_16BITS)) 
        slen=PAULABUFFERSIZE/4; else
        slen=PAULABUFFERSIZE/2;

if(!(IsStereo=(md_mode&DMODE_STEREO))) slen<<=1;


PAULA_DMABUF=(char *)AllocMem(PAULABUFFERSIZE,MEMF_PUBLIC);
PAULA_LEFT[0]=(char *)AllocMem(slen,MEMF_CHIP|MEMF_CLEAR);
PAULA_LEFT[1]=(char *)AllocMem(slen,MEMF_CHIP|MEMF_CLEAR);
PAULA_RIGHT[0]=(char *)AllocMem(slen,MEMF_CHIP|MEMF_CLEAR);
PAULA_RIGHT[1]=(char *)AllocMem(slen,MEMF_CHIP|MEMF_CLEAR);
if((!PAULA_DMABUF)||(!PAULA_LEFT[0])||(!PAULA_LEFT[1])
        ||(!PAULA_RIGHT[0])||(!PAULA_RIGHT[1]))
        {
        printf("Could not malloc buffer memory!\n");
        Paula_Exit();
        return(0);
        }


if(!(LocalGfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
        {
        printf("Could not open graphics.library!\n");
        Paula_Exit();
        return(0);
        }

if(LocalGfxBase->DisplayFlags & PAL) clock=3546895; else clock=3579545;
CloseLibrary((struct Library *)LocalGfxBase);

if(!(AIOptrl=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR)))
        {
        printf("Could not alloc IOAudio structure mem!\n");
        Paula_Exit();
        return(0);
        }

if(!(portl=CreatePort(0,0)))
        {
        printf("Could not create reply port!\n");
        Paula_Exit();
        return(0);
        }

AIOptrl->ioa_Request.io_Message.mn_ReplyPort     =       portl;
AIOptrl->ioa_Request.io_Message.mn_Node.ln_Pri   =       0;
AIOptrl->ioa_Request.io_Command                  =       ADCMD_ALLOCATE;
AIOptrl->ioa_Request.io_Flags                    =       ADIOF_NOWAIT;
AIOptrl->ioa_AllocKey                            =       0;
AIOptrl->ioa_Data                                =       whichchannell;
AIOptrl->ioa_Length                              =       sizeof(whichchannell);

if(devicel=OpenDevice("audio.device",0L,(struct IORequest *)AIOptrl,0L))
        {
        printf("Could not grab audio.device!\n");
        Paula_Exit();
        return(0);
        }


if(!(AIOptrr=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR)))
        {
        printf("Could not alloc IOAudio structure mem!\n");
        Paula_Exit();
        return(0);
        }

if(!(portr=CreatePort(0,0)))
        {
        printf("Could not create reply port!\n");
        Paula_Exit();
        return(0);
        }

AIOptrr->ioa_Request.io_Message.mn_ReplyPort     =       portr;
AIOptrr->ioa_Request.io_Message.mn_Node.ln_Pri   =       0;
AIOptrr->ioa_Request.io_Command                  =       ADCMD_ALLOCATE;
AIOptrr->ioa_Request.io_Flags                    =       ADIOF_NOWAIT;
AIOptrr->ioa_AllocKey                            =       0;
AIOptrr->ioa_Data                                =       whichchannelr;
AIOptrr->ioa_Length                              =       sizeof(whichchannelr);

if(devicer=OpenDevice("audio.device",0L,(struct IORequest *)AIOptrr,0L))
        {
        printf("Could not grab audio.device!\n");
        Paula_Exit();
        return(0);
        }

AIOptrl->ioa_Request.io_Message.mn_ReplyPort     =       portl;
AIOptrl->ioa_Request.io_Command                  =       CMD_WRITE;
AIOptrl->ioa_Request.io_Flags                    =       ADIOF_PERVOL;
AIOptrl->ioa_Data                                =       (BYTE *)PAULA_LEFT[0];
AIOptrl->ioa_Length                              =       slen;
AIOptrl->ioa_Period                              =       clock/md_mixfreq;
AIOptrl->ioa_Volume                              =       64;
AIOptrl->ioa_Cycles                              =       1;

AIOptrr->ioa_Request.io_Message.mn_ReplyPort     =       portr;
AIOptrr->ioa_Request.io_Command                  =       CMD_WRITE;
AIOptrr->ioa_Request.io_Flags                    =       ADIOF_PERVOL;
AIOptrr->ioa_Data                                =       (BYTE *)PAULA_RIGHT[0];
AIOptrr->ioa_Length                              =       slen;
AIOptrr->ioa_Period                              =       clock/md_mixfreq;
AIOptrr->ioa_Volume                              =       64;
AIOptrr->ioa_Cycles                              =       1;

BeginIO((struct IORequest *)AIOptrl);
BeginIO((struct IORequest *)AIOptrr);


if(!VC_Init()){ return 0; }
return 1;
}


static void Paula_Update(void)
{
short i;
int db;
char *buf, *left, *right;
ULONG signals;


Wait(1L<<portl->mp_SigBit);      
msgl=GetMsg(portl);      
signals=Wait((1L<<portr->mp_SigBit)|SIGBREAKF_CTRL_C);      
msgr=GetMsg(portr);


AIOptrl->ioa_Data=(BYTE *)PAULA_LEFT[DBFlag];
if(IsStereo)
        AIOptrr->ioa_Data=(BYTE *)PAULA_RIGHT[DBFlag]; else
        AIOptrr->ioa_Data=(BYTE *)PAULA_LEFT[DBFlag];


BeginIO((struct IORequest *)AIOptrl);
BeginIO((struct IORequest *)AIOptrr);


db=1-DBFlag;
buf=PAULA_DMABUF;
left=PAULA_LEFT[db];
right=PAULA_RIGHT[db];

	VC_WriteBytes(PAULA_DMABUF,PAULABUFFERSIZE);

if(IsStereo)
{
if(IsSixteenBit)
        for(i=0;i<slen;i++)
                {
                *left++=*buf;   buf+=2;
                *right++=*buf;  buf+=2;
                }
        else
        {
        for(i=0;i<slen;i++)
                {
                *left++=(*buf++)^0x80;  
                *right++=(*buf++)^0x80; 
                }
        }
}
else
{
if(IsSixteenBit)
        for(i=0;i<slen;i++)
                {
                *left++=*buf;   buf+=2;
                }
        else
        {
        for(i=0;i<slen;i++)
                {
                *left++=(*buf++)^0x80;  
                }
        }
}
DBFlag=db;

if(signals&SIGBREAKF_CTRL_C)
        {
        printf("** BREAK **\n");
        Paula_Exit();
        exit(0);
        }
}



DRIVER drv_pau={
	NULL,
	"Eight-bit Paula sound output",
	"Paula Eight-bit output driver v1.0",
	Paula_IsThere,
	VC_SampleLoad,
	VC_SampleUnload,
	Paula_Init,
	Paula_Exit,
	VC_PlayStart,
	VC_PlayStop,
	Paula_Update,
	VC_VoiceSetVolume,
	VC_VoiceSetFrequency,
	VC_VoiceSetPanning,
	VC_VoicePlay
};
