
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/errors.h>
#include <hardware/custom.h>
#include <libraries/dos.h>
#include <devices/audio.h>

#define BUFSIZE 250L
#define STP2    10
#define STSIZE  (1<<STP2)
#define STSTEP  (2*3.141593/STSIZE)
#define XMOUSEREG       (*((BYTE *)0xdff00b))
#define YMOUSEREG       (-(*(BYTE *)0xdff00a))

extern struct MsgPort *CreatePort();
extern struct Library *OpenLibrary();
extern void *AllocMem();
extern struct IOAudio *GetMsg();
UBYTE allocationMap[]={1,8,2,4};
struct Library *MathBase=0;
struct MsgPort *allocPort=0;
struct IOAudio *allocIOB=0;
struct Device *device=0;
struct Interrupt *interrupt=0;
struct MsgPort *soundPort=0;
BYTE *buffer[2]={0};
struct IOAudio *soundIOB[2]={0};

int newBuffer();
UBYTE sineTable[STSIZE];
ULONG angle=0;
ULONG frequency=0x2000000;
BYTE lastYMouse;

main()
{
	int i;
	FLOAT sine=0.0;
	FLOAT cosine=1.0;

	if((MathBase=OpenLibrary("mathffp.library",0L))==0)
		cleanup("Cannot open math library");
	for(i=0;i<STSIZE; ++i)  {
		sineTable[i]=127*sine+0.5;      
		sine += STSTEP * (cosine -= STSTEP * sine);
	}

	lastYMouse=YMOUSEREG;

	if((allocPort=CreatePort("sound example",0L))==0)
		cleanup("Cannot create reply port");
	if((allocIOB=AllocMem((long)sizeof(struct IOAudio),
											MEMF_PUBLIC|MEMF_CLEAR))==0)
		cleanup("Out of memory");
	allocIOB->ioa_Request.io_Message.mn_Node.ln_Pri=-40;
	allocIOB->ioa_Request.io_Message.mn_ReplyPort=allocPort;
	allocIOB->ioa_Data=allocationMap;
	allocIOB->ioa_Length=sizeof(allocationMap);

	switch(OpenDevice(AUDIONAME,0L,allocIOB,0L)) {
	case IOERR_OPENFAIL:
		cleanup("Cannot open audio device");
	case ADIOERR_ALLOCFAILED:
		cleanup("Cannot allocate audio channel");
	}
	device=allocIOB->ioa_Request.io_Device;

	if((interrupt=AllocMem((long)sizeof(struct Interrupt),
											MEMF_CLEAR|MEMF_PUBLIC))==0)
		cleanup("Out of memory");

	interrupt->is_Code=(VOID(*)())newBuffer;


	if((soundPort=AllocMem((long)sizeof(struct MsgPort),
											MEMF_CLEAR|MEMF_CHIP))==0)
		cleanup("Out of memory");

	soundPort->mp_Flags=PA_SOFTINT;
	soundPort->mp_SigTask=(struct Task *)interrupt;
	soundPort->mp_Node.ln_Type=NT_MSGPORT;
	NewList(&soundPort->mp_MsgList);


	for (i=0; i<2; ++i) {
		if((buffer[i]=AllocMem(BUFSIZE,MEMF_CHIP))==0)
			cleanup("Out of Memory");
		if((soundIOB[i]=AllocMem((LONG) sizeof(struct IOAudio),
											MEMF_PUBLIC|MEMF_CLEAR))==0)
			cleanup("Out of memory");
		soundIOB[i]->ioa_Request.io_Message.mn_ReplyPort=soundPort;
		soundIOB[i]->ioa_Request.io_Device=device;
		soundIOB[i]->ioa_Request.io_Unit=allocIOB->ioa_Request.io_Unit;
		soundIOB[i]->ioa_Request.io_Command=CMD_WRITE;
		soundIOB[i]->ioa_Request.io_Flags=ADIOF_PERVOL;
		soundIOB[i]->ioa_AllocKey=allocIOB->ioa_AllocKey;
		soundIOB[i]->ioa_Data=(UBYTE *)buffer[i];
		soundIOB[i]->ioa_Length=BUFSIZE;
		soundIOB[i]->ioa_Period=200;
		soundIOB[i]->ioa_Volume=64;
		soundIOB[i]->ioa_Cycles=1;
		ReplyMsg(soundIOB[i]);
	}
	printf("Press ctrl-c to stop\n");
	Wait(SIGBREAKF_CTRL_C);
	cleanup("");
}  /* end main */

/************************************/
cleanup(mes)
TEXT *mes;
{
	int i;
	printf(mes);
	printf("\n");
	if(device!=0)
		CloseDevice(allocIOB);
	for(i=0; i<2; ++i) {
		if(soundIOB[i])
			FreeMem(soundIOB[i],(LONG)sizeof(struct IOAudio));
		if(buffer[i])
			FreeMem(buffer[i],BUFSIZE);
	}
	if(soundPort)
		FreeMem(soundPort,(LONG)sizeof(struct MsgPort));
	if(interrupt)
		FreeMem(interrupt,(LONG) sizeof(struct Interrupt));
	if(allocIOB)
		FreeMem(allocIOB,(LONG)sizeof(struct IOAudio));
	if(allocPort)
		DeletePort(allocPort,(LONG)sizeof(struct MsgPort));
	if (MathBase)
		CloseLibrary(MathBase);
	exit(0);
}

newBuffer()
{
	int i;
	struct IOAudio *ioa;
	BYTE *buffer;
	BYTE mouseChange,curYMouse;
	ULONG newFreq;

#ifdef AZTEC_C
	int_start();
#endif
	ioa=GetMsg(soundPort);
	if (ioa && ioa->ioa_Request.io_Error==0) {
		curYMouse=YMOUSEREG;
		mouseChange=curYMouse-lastYMouse;
		lastYMouse=curYMouse;
		newFreq=frequency+mouseChange*(frequency>>6);
		if(newFreq>0x800000 && newFreq <0x40000000)
			frequency=newFreq;
		buffer=(BYTE *)ioa->ioa_Data;
		for(i=0; i<BUFSIZE; ++i)
			*buffer++=sineTable[(angle+=frequency)>>(32-STP2)];
		Disable();
		BeginIO(ioa);
		Enable();
	}
#ifdef AZTEC_C
	int_end();
#endif
}

