/* * 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); }