home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff546.lzh
/
DSound
/
DSound.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-19
|
12KB
|
533 lines
/**************************************************************************/
/* 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 <exec/types.h>
#include <exec/exec.h>
#include <devices/audio.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include "dsound.h"
#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
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<argc;i++)
{
if(argv[i][0]=='-')
switch(argv[i][1])
{
/* Use the left channel */
case 'l':
case 'L':
allocationMap=leftAMap;
break;
/* Use the right channel */
case 'r':
case 'R':
allocationMap=rightAMap;
break;
/* Switch off the low-pass filter while the sample is playing */
case 'f':
case 'F':
noFilter=TRUE;
break;
/* Play a sample at a given speed */
case 's':
case 'S':
speed=atol(&argv[i][2]);
if(speed > 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 <options> <filename>\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<speed> -- Play the sample at the given speed (samples/sec)\n");
WriteMsg(" -v<volume> -- Play the sample at the given volume (0-64)\n");
WriteMsg(" -b<bufsize> -- Use a buffer of size <bufsize> (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);
}