/**************************************************************************/ /* DSound V0.91a */ /* Copyright 1991 by Dave Schreiber, All Rights Reserved */ /* */ /* To compile: */ /* lc -Lcd -v DSound */ /* */ /* Revision history: */ /* V0.91a - First release (September 11, 1991) */ /**************************************************************************/ #include #include #include #include #include #include #include #include "dsound.h" #include #include UBYTE rightAMap[]={2,4}; UBYTE leftAMap[]={1,8}; UBYTE eitherAMap[]={1,2,4,8}; UBYTE *allocationMap=eitherAMap; char filename[140]; #define BUF_SIZE 30000 void InterpretArgs(int argc,char *argv[]); BOOL noFilter=FALSE; UBYTE volume=0; UWORD speed=0; ULONG bufSize=BUF_SIZE; void filter_on(void); void filter_off(void); char *version="$VER: DSound V0.91a (11.9.91)"; char *copyright="Copyright 1991 by Dave Schreiber, All Rights Reserved"; struct IntuitionBase *IntuitionBase=NULL; struct GfxBase *GfxBase=NULL; struct Window *window=NULL; struct NewWindow newWindow= { 100,50,300,10,-1,-1,CLOSEWINDOW,WINDOWCLOSE|WINDOWDRAG|WINDOWDEPTH, NULL,NULL,"<-- Click to stop (DSound V0.91)",NULL,NULL,1,1,1000,1000, WBENCHSCREEN }; BPTR file=NULL; main(int argc,char *argv[]) { struct IOAudio *iob1,*iob2; struct Voice8Header vhdr; UBYTE foo2[5]; ULONG len; ULONG toRead; BOOL done=FALSE; filename[0]=NULL; GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L); IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L); if(GfxBase==NULL || IntuitionBase==NULL) cleanup(50); InterpretArgs(argc,argv); if(filename[0]==NULL) { WriteMsg("Please specify a filename\n"); cleanup(75); } /*Open the file*/ file=Open(filename,MODE_OLDFILE); if(file==NULL) { WriteMsg("Couldn't open the file\n"); cleanup(100); } newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3; window=OpenWindow(&newWindow); if(window==NULL) cleanup(110); /*Read the header*/ Position(file,"VHDR"); Read(file,foo2,4); Read(file,&vhdr,sizeof(struct Voice8Header)); /*Check for compression*/ if(vhdr.sCompression!=0) { WriteMsg("The sound sample is compressed\n"); cleanup(400); } /*Find the BODY*/ Position(file,"BODY"); Read(file,foo2,4); /*Get the length of the sample*/ len=vhdr.oneShotHiSamples; /*Get the first audio channel*/ iob1=GetAudioChannel(bufSize); if(iob1==NULL) { WriteMsg("Couldn't create the first buffer\n"); cleanup(150); } /* If the user didn't specify a volume, get it from the VHDR */ if(volume==0) volume=(vhdr.volume>>10); /* If the VHDR gave a volume of zero, use maximum volume*/ if(volume==0) volume=64; /* Get the samples/sec rate (either the rate given by the user, or the*/ /* rate found in the VHDR) */ if(speed==0) speed=1000000000/(vhdr.samplesPerSec*279); else speed=1000000000/(speed*279); InitAudioChannel(iob1,volume,speed); /*Get the 2nd audio channel*/ iob2=DuplicateAudioChannel(iob1); if(iob2==NULL) { FreeAudioChannel(iob1); WriteMsg("Couldn't create the second buffer"); cleanup(175); } /* Load the first buffer*/ toRead=MIN(len,bufSize); LoadAudioBuffer(file,iob1,toRead); len-=toRead; iob1->ioa_Length=toRead; /* Make sure there's enough data so that we have something to put in */ /* the second buffer */ if(len!=0) { toRead=MIN(len,bufSize); LoadAudioBuffer(file,iob2,toRead); len-=toRead; iob2->ioa_Length=toRead; } else /* It appears that the entire sound sample is small enough to */ /* fit into the first buffer, so don't play the second */ iob2->ioa_Length=0; /*Switch off the filter, if necessary */ if(noFilter) filter_off(); /*And queue up the play requests*/ BeginIO((struct ioRequest *)iob1); if(iob2->ioa_Length!=0) BeginIO((struct ioRequest *)iob2); /* If the sound sample was small enough to fit into the two buffers, */ /* play them then finish up */ if(len==0 || GetMsg(window->UserPort)!=NULL) { WaitIO((struct ioRequest *)iob1); if(iob2->ioa_Length!=0) WaitIO((struct ioRequest *)iob2); done=TRUE; } /*Otherwise, play those samples then read more from disk*/ /*Loop while there's stuff to read*/ while(!done) { /*Fill the first buffer*/ WaitIO((struct ioRequest *)iob1); toRead=MIN(len,bufSize); if(toRead==0 || GetMsg(window->UserPort)!=NULL) { /*If there's no stuff left to read, wait 'till the second buffer*/ /*finishes, then quit*/ WaitIO((struct ioRequest *)iob2); done=TRUE; break; } LoadAudioBuffer(file,iob1,toRead); len-=toRead; /*Play the first buffer*/ BeginIO((struct ioRequest *)iob1); /*Wait for the second buffer to finish*/ WaitIO((struct ioRequest *)iob2); toRead=MIN(len,bufSize); if(toRead==0 || GetMsg(window->UserPort)!=NULL) { /*If there's no stuff left to read, wait 'till the first buffer*/ /*finishes, then quit*/ WaitIO((struct ioRequest *)iob1); done=TRUE; break; } /*Reload it*/ LoadAudioBuffer(file,iob2,toRead); len-=toRead; /*Play it*/ BeginIO((struct ioRequest *)iob2); } /*Switch the filter off if it was switched off*/ if(noFilter) filter_on(); /*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/ /*how much memory to free*/ iob1->ioa_Length=iob2->ioa_Length=bufSize; FreeAudioChannel(iob1); DeleteDuplication(iob2); /*Free allocated resources and exit*/ cleanup(0); } // Get an audio channel struct IOAudio *GetAudioChannel(ULONG bufferSize) { struct IOAudio *aIOB; void *audioBuf; struct Port *aPort; aPort=(struct Port *)CreatePort("dsound",0); if(aPort==NULL) return(NULL); /* Allocate the chip memory buffer for the channel */ audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP); if(audioBuf==NULL) { DeletePort(aPort); return(NULL); } /* Allocate an IOAudio structure*/ aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); if(aIOB==NULL) { DeletePort(aPort); FreeMem(audioBuf,bufferSize); return(NULL); } /* Set up the IOAudio to allocate the command channel */ aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0; aIOB->ioa_Request.io_Message.mn_ReplyPort=aPort; aIOB->ioa_Data=allocationMap; aIOB->ioa_Length=2; aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE; OpenDevice("audio.device",0,(struct ioRequest *)aIOB,0); if(aIOB->ioa_AllocKey==0) { DeletePort(aPort); FreeMem(audioBuf,bufferSize); FreeMem(aIOB,sizeof(struct IOAudio)); return(NULL); } else { /* Set up the IOAudio for writes */ aIOB->ioa_Request.io_Command=CMD_WRITE; aIOB->ioa_Request.io_Flags=ADIOF_PERVOL; aIOB->ioa_Data=audioBuf; aIOB->ioa_Length=bufferSize; return(aIOB); } } /* Free an allocated audio channel */ void FreeAudioChannel(struct IOAudio *aIOB) { if(aIOB==NULL) return; /* Free the audi obuffer */ if(aIOB->ioa_Data!=NULL) FreeMem(aIOB->ioa_Data,aIOB->ioa_Length); /* Free the audio channel */ aIOB->ioa_Request.io_Command=ADCMD_FREE; BeginIO((struct ioRequest *)aIOB); WaitIO((struct ioRequest *)aIOB); DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort); /* Close the audio channel */ CloseDevice((struct ioRequest *)aIOB); /* Free the IOAudio structure */ FreeMem(aIOB,sizeof(struct IOAudio)); return; } /* Initialize an IOAudio's volume, period, and set the number of cycles */ /* to one */ void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period) { aIOB->ioa_Period=period; aIOB->ioa_Volume=volume; aIOB->ioa_Cycles=1; return; } /* Duplicate an IOAudio structure */ struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB) { struct IOAudio *aIOB; void *audioBuf; if(OrigIOB==NULL) return(NULL); /* Allocate the alternate buffer */ audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP); if(audioBuf==NULL) return(NULL); /*Allocate the IOAudio structure*/ aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); if(aIOB==NULL) { FreeMem(audioBuf,OrigIOB->ioa_Length); return(NULL); } /*Copy the original IOAudio's contents to the new one*/ CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio)); /*Except for the buffer pointer, of course*/ aIOB->ioa_Data=audioBuf; return(aIOB); } /*Delete a duplicated IOAudio*/ void DeleteDuplication(struct IOAudio *aIOB) { if(aIOB != NULL) { /* Free the memory for the buffer and IOAudio */ if(aIOB->ioa_Data != NULL) FreeMem(aIOB->ioa_Data,aIOB->ioa_Length); FreeMem(aIOB,sizeof(struct IOAudio)); } return; } /* Load an IOAudio's buffer from an open file */ ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead) { if(toRead==0) return(0); aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead); return(aIOB->ioa_Length); } /* Seek forward in a file until the given string is found (useful for */ /* finding chunk in IFF files */ void Position(BPTR file,char *string) { UBYTE len; char chr; UBYTE i; len=strlen(string); for(;;) { Read(file,&chr,1); if(chr==string[0]) { Read(file,&chr,1); for(i=1;i<4 && string[i]==chr;i++) { if(i!=3) Read(file,&chr,1); } if(i==4) return; } } } /* Interpret the command line arguments */ void InterpretArgs(int argc,char *argv[]) { int i; for(i=1;i 28000) speed=0; break; /* The volume at which the sample should be played */ case 'v': case 'V': volume=atol(&argv[i][2]); if(volume > 64) volume=0; break; /* The size of the chip RAM buffers */ case 'b': case 'B': bufSize=(atol(&argv[i][2])+1)&(~1); if(bufSize==0) bufSize=BUF_SIZE; break; } else if(argv[i][0]=='?') { /*On-line help*/ WriteMsg("DSound V0.91a ©1991 by Dave Schreiber\n"); WriteMsg("Usage:\m"); WriteMsg(" DSound \n"); WriteMsg("Where the options are:\n"); WriteMsg(" -l -- Play the sample using the left speaker\n"); WriteMsg(" -r -- Play the sample using the right speaker\n"); WriteMsg(" -f -- Shut off the low-pass filter\n"); WriteMsg(" -s -- Play the sample at the given speed (samples/sec)\n"); WriteMsg(" -v -- Play the sample at the given volume (0-64)\n"); WriteMsg(" -b -- Use a buffer of size (default is 30K)\n"); exit(0); } else /*Otherwise, the argument is a filename */ strcpy(filename,argv[i]); } } /*Switch on the low-pass filter */ void filter_on() { *((char *)0x0bfe001)&=0xFD; } /*Switch off the low-pass filter*/ void filter_off() { *((char *)0x0bfe001)|=0x02; } /*Write a message to the CLI*/ void WriteMsg(char *errMsg) { Write(Output(),errMsg,strlen(errMsg)); } /* Free allocated resources */ void cleanup(int err) { if(file!=NULL) Close(file); if(window!=NULL) CloseWindow(window); if(GfxBase!=NULL) CloseLibrary((struct Library *)GfxBase); if(IntuitionBase!=NULL) CloseLibrary((struct Library *)IntuitionBase); exit(err); }