/*
* Audio_8SVX.c
*
* 8SVX example - double buffers >128K samples
*
* Compile with SAS C 5.10 lc -b1 -cfistq -v -y -L
*
* Run from CLI only
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/audio.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <graphics/gfxbase.h>
#include <iff/iff.h>
#include <iff/8svx.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef LATTICE
int CXBRK(void) { return(0); } /* Disable SAS CTRL/C handling */
int chkabort(void) { return(0); } /* really */
#endif
#define VHDR MakeID('V','H','D','R')
#define BODY MakeID('B','O','D','Y')
#define MY8S MakeID('8','S','V','X')
void kill8svx(char *);
void kill8(void);
/*--------------------*/ /* These globals are needed */
/* G L O B A L S */ /* by the clean up routines */
/*--------------------*/
struct IOAudio *AIOptr1, /* Pointers to Audio IOBs */
*AIOptr2,
*Aptr;
struct Message *msg; /* Msg, port and device for */
struct MsgPort *port, /* driving audio */
*port1,*port2;
ULONG device;
UBYTE *sbase,*fbase; /* For sample memory allocation */
ULONG fsize,ssize; /* and freeing */
struct FileHandle *v8handle;
UBYTE chan1[] = { 1 };/* Audio channel allocation arrays */
UBYTE chan2[] = { 2 };
UBYTE chan3[] = { 4 };
UBYTE chan4[] = { 8 };
UBYTE *chans[] = {chan1,chan2,chan3,chan4};
BYTE oldpri,c; /* Stuff for bumping priority */
struct Task *mt=0L;
struct GfxBase *GfxBase = NULL;
/*-----------*/
/* M A I N */
/*-----------*/
void main(int argc,char **argv)
{
/*-------------*/
/* L O C A L S */
/*-------------*/
char *fname; /* File name and data pointer*/
UBYTE *p8data; /* for file read. */
ULONG clock; /* Clock constant */
ULONG length[2]; /* Sample lengths */
BYTE iobuffer[8], /* Buffer for 8SVX header */
*psample[2]; /* Sample pointers */
Chunk *p8Chunk; /* Pointers for 8SVX parsing */
Voice8Header *pVoice8Header;
ULONG y,rd8count,speed; /* Counters, sampling speed */
ULONG wakebit; /* A wakeup mask */
/*-------------*/
/* C O D E */
/*-------------*/
/*------------------------------*/
/* Check Arguments, Initialize */
/*------------------------------*/
fbase=0L;
sbase=0L;
AIOptr1=0L;
AIOptr2=0L;
port=0L;
port1=0L;
port2=0L;
v8handle=0L;
device=1L;
if (argc < 2)
{
kill8svx("No file name given.\n");
exit(1L);
}
fname=argv[1];
/*---------------------------*/
/* Initialize Clock Constant */
/*---------------------------*/
GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
if (GfxBase==0L)
{
puts("Can't open graphics library\n");
exit(1L);
}
if (GfxBase->DisplayFlags & PAL)
clock=3546895L; /* PAL clock */
else
clock=3579545L; /* NTSC clock */
if (GfxBase)
CloseLibrary( (struct Library *) GfxBase);
/*---------------*/
/* Open the File */
/*---------------*/
v8handle= (struct FileHandle *) Open(fname,MODE_OLDFILE);
if (v8handle==0)
{
kill8svx("Can't open 8SVX file.\n");
exit(1L);
}
/*-------------------------------------------*/
/* Read the 1st 8 Bytes of the File for Size */
/*-------------------------------------------*/
rd8count=Read((BPTR)v8handle,iobuffer,8L);
if (rd8count==-1)
{
kill8svx ("Read error.\n");
exit(1L);
}
if (rd8count<8)
{
kill8svx ("Not an IFF 8SVX file, too short\n");
exit(1L);
}
/*-----------------*/
/* Evaluate Header */
/*-----------------*/
p8Chunk=(Chunk *)iobuffer;
if (p8Chunk->ckID != FORM )
{
kill8svx("Not an IFF FORM.\n");
exit(1L);
}
/*--------------------------------------------*/
/* Allocate Memory for File and Read it in. */
/*--------------------------------------------*/
fbase= (UBYTE *)AllocMem(fsize=p8Chunk->ckSize , MEMF_PUBLIC|MEMF_CLEAR);
if (fbase==0)
{
kill8svx("No memory for read.\n");
exit(1L);
}
p8data=fbase;
rd8count=Read((BPTR)v8handle,p8data,p8Chunk->ckSize);
if (rd8count==-1)
{
kill8svx ("Read error.\n");
exit(1L);
}
if (rd8count<p8Chunk->ckSize)
{
kill8svx ("Malformed IFF, too short.\n");
exit(1L);
}
/*-------------------*/
/* Evaluate IFF Type */
/*-------------------*/
if (MakeID( *p8data, *(p8data+1) , *(p8data+2) , *(p8data+3) ) != MY8S )
{
kill8svx("Not an IFF 8SVX file.\n");
exit(1L);
}
/*----------------------*/
/* Evaluate 8SVX Chunks */
/*----------------------*/
p8data=p8data+4;
while( p8data < fbase+fsize )
{
p8Chunk=(Chunk *)p8data;
switch(p8Chunk->ckID)
{
case VHDR:
/*------------------------------------------------*/
/* Get a pointer to the 8SVX header for later use */
/*------------------------------------------------*/
pVoice8Header=(Voice8Header *)(p8data+8L);
break;
case BODY:
/*-------------------------------------------------*/
/* Create pointers to 1-shot and continuous parts */
/* for the top octave and get length. Store them. */
/*-------------------------------------------------*/
psample[0] = (BYTE *)(p8data + 8L);
psample[1] = psample[0] + pVoice8Header->oneShotHiSamples;
length[0] = (ULONG)pVoice8Header->oneShotHiSamples;
length[1] = (ULONG)pVoice8Header->repeatHiSamples;
break;
default:
break;
}
/* end switch */
p8data = p8data + 8L + p8Chunk->ckSize;
if (p8Chunk->ckSize&1L == 1)
p8data++;
}
/* Play either the one-shot or continuous, not both */
if (length[0]==0)
y=1;
else
y=0;
/*---------------------------------------*/
/* Allocate chip memory for samples and */
/* copy from read buffer to chip memory. */
/*---------------------------------------*/
if (length[y]<=102400)
ssize=length[y];
else
ssize=102400;
sbase=(UBYTE *)AllocMem( ssize , MEMF_CHIP | MEMF_CLEAR);
if (sbase==0)
{
kill8svx("No chip memory.\n");
exit(1L);
}
CopyMem(psample[y],sbase,ssize);
psample[y]+=ssize;
/*----------------------------------*/
/* Calculate playback sampling rate */
/*----------------------------------*/
speed = clock / pVoice8Header->samplesPerSec;
/*-------------------*/
/* Bump our priority */
/*-------------------*/
mt=FindTask(NULL);
oldpri=SetTaskPri(mt,21);
/*--------------------------------*/
/* Allocate two audio I/O blocks */
/*--------------------------------*/
AIOptr1=(struct IOAudio *)
AllocMem( sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
if (AIOptr1==0)
{
kill8svx("No IO memory\n");
exit(1L);
}
AIOptr2=(struct IOAudio *)
AllocMem( sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
if (AIOptr2==0)
{
kill8svx("No IO memory\n");
exit(1L);
}
/*----------------------*/
/* Make two reply ports */
/*----------------------*/
port1=CreatePort(0,0);
if (port1==0)
{
kill8svx("No port\n");
exit(1L);
}
port2=CreatePort(0,0);
if (port2==0)
{
kill8svx("No port\n");
exit(1L);
}
c=0;
while(device!=0 && c<4)
{
/*---------------------------------------*/
/* Set up audio I/O block for channel */
/* allocation and Open the audio device */
/*---------------------------------------*/
AIOptr1->ioa_Request.io_Message.mn_ReplyPort = port1;
AIOptr1->ioa_Request.io_Message.mn_Node.ln_Pri = 127; /* No stealing! */
AIOptr1->ioa_AllocKey = 0;
AIOptr1->ioa_Data = chans[c];
AIOptr1->ioa_Length = 1;
device=OpenDevice(AUDIONAME,0L,(struct IORequest *)AIOptr1,0L);
c++;
}
if (device!=0)
{
kill8svx("No channel\n");
exit(1L);
}
/*-------------------------------------------*/
/* Set Up Audio IO Blocks for Sample Playing */
/*-------------------------------------------*/
AIOptr1->ioa_Request.io_Command =CMD_WRITE;
AIOptr1->ioa_Request.io_Flags =ADIOF_PERVOL;
/*--------*/
/* Volume */
/*--------*/
AIOptr1->ioa_Volume=60;
/*---------------*/
/* Period/Cycles */
/*---------------*/
AIOptr1->ioa_Period =(UWORD)speed;
AIOptr1->ioa_Cycles =1;
*AIOptr2 = *AIOptr1; /* Make sure we have the same allocation keys, */
/* same channels selected and same flags */
/* (but different ports...) */
AIOptr1->ioa_Request.io_Message.mn_ReplyPort = port1;
AIOptr2->ioa_Request.io_Message.mn_ReplyPort = port2;
/*--------*/
/* Data */
/*--------*/
AIOptr1->ioa_Data =(UBYTE *)sbase;
AIOptr2->ioa_Data =(UBYTE *)sbase + 51200;
/*-----------------*/
/* Run the sample */
/*-----------------*/
if (length[y]<=102400)
{
AIOptr1->ioa_Length=length[y]; /* No double buffering needed */
BeginIO((struct IORequest *)AIOptr1); /* Begin the sample, wait for */
wakebit=0L; /* it to finish, then quit. */
wakebit=Wait(1 << port1->mp_SigBit);
while((msg=GetMsg(port1))==0){};
}
else
{
length[y]-=102400; /* It's a real long sample so */
AIOptr1->ioa_Length=51200L; /* double buffering is needed */
AIOptr2->ioa_Length=51200L;
BeginIO((struct IORequest *)AIOptr1); /* Start up the first 2 blocks */
BeginIO((struct IORequest *)AIOptr2);
Aptr=AIOptr1;
port=port1; /* Set the switch... */
while(length[y]>0)
{ /* Wait() for one IO to finish */
wakebit=Wait(1 << port->mp_SigBit); /* reuse the IO block & queue */
while((msg=GetMsg(port))==0){}; /* it up again while the 2nd IO*/
/* block plays.Switch & repeat */
/* Set length of next IO block */
if (length[y]<=51200)
Aptr->ioa_Length=length[y];
else
Aptr->ioa_Length=51200L;
/* Copy sample fragment from read buffer to chip memory */
CopyMem(psample[y],Aptr->ioa_Data,Aptr->ioa_Length);
/* Adjust size and pointer of read buffer*/
length[y]-=Aptr->ioa_Length;
psample[y]+=51200;
BeginIO((struct IORequest *)Aptr);
if (Aptr==AIOptr1)
{
Aptr=AIOptr2; /* This logic handles switching */
port=port2; /* between the 2 IO blocks and */
} /* the 2 ports we are using. */
else
{
Aptr=AIOptr1;
port=port1;
}
}
/*-------------------------------------------------*/
/* OK we are at the end of the sample so just wait */
/* for the last two parts of the sample to finish */
/*-------------------------------------------------*/
wakebit=Wait(1 << port->mp_SigBit);
while((msg=GetMsg(port))==0){};
if (Aptr==AIOptr1)
{
Aptr=AIOptr2; /* This logic handles switching */
port=port2; /* between the 2 IO blocks and */
} /* the 2 ports we are using. */
else
{
Aptr=AIOptr1;
port=port1;
}
wakebit=Wait(1 << port->mp_SigBit);
while((msg=GetMsg(port))==0){};
}
kill8();
exit(0L);
}
/*----------------*/
/* Abort the Read */
/*----------------*/
void
kill8svx(kill8svxstring)
char *kill8svxstring;
{
puts(kill8svxstring);
kill8();
}
/*-------------------------*/
/* Return system resources */
/*-------------------------*/
void kill8()
{
if (device ==0)
CloseDevice((struct IORequest *)AIOptr1);
if (port1 !=0)
DeletePort(port1);
if (port2 !=0)
DeletePort(port2);
if (AIOptr1!=0)
FreeMem( AIOptr1,sizeof(struct IOAudio) );
if (AIOptr2!=0)
FreeMem( AIOptr2,sizeof(struct IOAudio) );
if (mt!=0)
SetTaskPri(mt,oldpri);
if (sbase !=0)
FreeMem (sbase, ssize);
if (fbase !=0)
FreeMem(fbase,fsize);
if (v8handle!=0)
Close((BPTR)v8handle);
}