/*************************************************************************/ /* Play.c */ /*Contains code used to play samples (mono out of one or both speakers, */ /*and stereo). */ /*************************************************************************/ #include #include #include #include #include #include #include #include #include "dsound.h" #include #include #include UBYTE rightAMap[]={4,2,1,8}; UBYTE leftAMap[]={1,8,2,4}; UBYTE eitherAMap[]={1,2,4,8}; UBYTE bothAMap[]={8,3,5,10}; extern UBYTE volume; extern UWORD speed; extern ULONG bufSize; extern BOOL readAll; extern struct Window *window; /*Play a sample out of one speaker (left, right, or either)*/ void playMonoSample(BPTR file,channel audioChannel,struct Voice8Header *vhdr, ULONG len) { struct IOAudio *iob1,*iob2; ULONG toRead; BOOL done=FALSE; UBYTE *allocationMap; /*Load the entire sample into memory, if the user so specified*/ if(readAll) { storeLeft(file,len,bufSize); file=0L; } /*Decide which audio channel will be allocated*/ switch(audioChannel) { case MONO_LEFT: allocationMap=leftAMap; break; case MONO_RIGHT: allocationMap=rightAMap; break; case UNSPECIFIED: allocationMap=eitherAMap; break; } /*Get the first audio channel*/ iob1=GetAudioChannel(bufSize,allocationMap); 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\n"); cleanup(175); } /* Load the first buffer*/ toRead=MIN(len,bufSize); LoadAudioBuffer(file,iob1,toRead); len-=toRead; /*Store the number of samples to be played*/ 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; /*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) { Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) + (1<UserPort->mp_SigBit)); /* vvvv Bug fix */ if(iob2->ioa_Length!=0 && GetMsg(window->UserPort)==NULL) Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; } /*Otherwise, play those samples then read more from disk*/ /*Loop while there's stuff to read*/ while(!done) { /*Fill the first buffer*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(len,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the second buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } LoadAudioBuffer(file,iob1,toRead); len-=toRead; iob1->ioa_Length=toRead; /*Play the first buffer*/ BeginIO((struct IORequest *)iob1); /*Wait for the second buffer to finish*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(len,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the first buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } /*Reload it*/ LoadAudioBuffer(file,iob2,toRead); len-=toRead; iob2->ioa_Length=toRead; /*Play it*/ BeginIO((struct IORequest *)iob2); } /*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); return; } /*Play a stereo sample out of both speakers*/ /*If the user specifies that just one of the two stereo channels will*/ /*be played, DSound.c calls playMonoSample*/ void playStereoSample(BPTR leftFile,channel audioChannel, struct Voice8Header *vhdr, ULONG length, char *filename) { struct IOAudio *iob1_right,*iob2_right,*iob1_left,*iob2_left; ULONG toRead; BOOL done=FALSE; BPTR rightFile; /*Open the file again*/ rightFile=dupFileHandle(leftFile,filename); /*And position ourselves at the start of the right channel's data*/ Seek(rightFile,length,OFFSET_CURRENT); /*Read the entire sample into memory, if specified*/ if(readAll) { storeLeft(leftFile,length,bufSize); storeRight(rightFile,length,bufSize); Close(rightFile); leftFile=0L; rightFile=4L; } /*Get the first audio channel*/ iob1_left=GetAudioChannel(bufSize,leftAMap); if(iob1_left==NULL) { WriteMsg("Couldn't create the first stereo buffer\n"); cleanup(150); } iob1_right=GetAudioChannel(bufSize,rightAMap); if(iob1_right==NULL) { WriteMsg("Couldn't create the second stereo 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_left,volume,speed); InitAudioChannel(iob1_right,volume,speed); /*Get the 2nd audio channel*/ iob2_left=DuplicateAudioChannel(iob1_left); if(iob2_left==NULL) { FreeAudioChannel(iob1_left); FreeAudioChannel(iob1_right); WriteMsg("Couldn't create the second buffer"); cleanup(175); } iob2_right=DuplicateAudioChannel(iob1_right); if(iob2_right==NULL) { FreeAudioChannel(iob1_left); DeleteDuplication(iob2_left); FreeAudioChannel(iob1_right); WriteMsg("Couldn't create the second buffer"); cleanup(175); } /* Load the first buffer*/ toRead=MIN(length,bufSize); LoadAudioBuffer(leftFile,iob1_left,toRead); LoadAudioBuffer(rightFile,iob1_right,toRead); iob1_left->ioa_Length=iob1_right->ioa_Length=toRead; length-=toRead; iob1_right->ioa_Length=iob1_left->ioa_Length=toRead; /* Make sure there's enough data so that we have something to put in */ /* the second buffer */ if(length!=0) { toRead=MIN(length,bufSize); LoadAudioBuffer(leftFile,iob2_left,toRead); LoadAudioBuffer(rightFile,iob2_right,toRead); length-=toRead; iob2_right->ioa_Length=iob2_left->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_left->ioa_Length=iob2_right->ioa_Length=0; /*And queue up the play requests*/ BeginIO((struct IORequest *)iob1_left); BeginIO((struct IORequest *)iob1_right); if(iob2_left->ioa_Length!=0) { BeginIO((struct IORequest *)iob2_left); BeginIO((struct IORequest *)iob2_right); } /* If the sound sample was small enough to fit into the two buffers, */ /* play them then finish up */ if(length==0) { Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); if(iob2_left->ioa_Length!=0 && GetMsg(window->UserPort)==NULL) Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; } /*Otherwise, play those samples then read more from disk*/ /*Loop while there's stuff to read*/ while(!done) { /*Wait for the first buffer to finish playing*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(length,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the second buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } LoadAudioBuffer(leftFile,iob1_left,toRead); LoadAudioBuffer(rightFile,iob1_right,toRead); length-=toRead; iob1_left->ioa_Length=iob1_right->ioa_Length=toRead; /*Play the first buffer*/ BeginIO((struct IORequest *)iob1_left); BeginIO((struct IORequest *)iob1_right); /*Wait for the second buffer to finish*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(length,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the first buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } /*Reload it*/ LoadAudioBuffer(leftFile,iob2_left,toRead); LoadAudioBuffer(rightFile,iob2_right,toRead); length-=toRead; iob2_left->ioa_Length=iob2_right->ioa_Length=toRead; /*Play it*/ BeginIO((struct IORequest *)iob2_left); BeginIO((struct IORequest *)iob2_right); } /*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/ /*how much memory to free*/ iob1_left->ioa_Length=iob2_left->ioa_Length=bufSize; iob1_right->ioa_Length=iob2_right->ioa_Length=bufSize; FreeAudioChannel(iob1_left); DeleteDuplication(iob2_left); FreeAudioChannel(iob1_right); DeleteDuplication(iob2_right); if(rightFile != 4L) Close(rightFile); return; } /*Play a mono sample (or a single channel of a stereo sample) out of */ /*both speakers simultaneously*/ void playMonoTwice(BPTR file,channel audioChannel,struct Voice8Header *vhdr, ULONG length) { struct IOAudio *iob1_right,*iob2_right,*iob1_left,*iob2_left; ULONG toRead; BOOL done=FALSE; /*Read the entire sample into memory, if the user so specified*/ if(readAll) { storeLeft(file,length,bufSize); file=0L; } /*Get the first audio channel*/ iob1_left=GetAudioChannel(bufSize,leftAMap); if(iob1_left==NULL) { WriteMsg("Couldn't create the first stereo buffer\n"); cleanup(150); } iob1_right=GetAudioChannel(bufSize,rightAMap); if(iob1_right==NULL) { WriteMsg("Couldn't create the second stereo buffer\n"); cleanup(150); } FreeMem(iob1_right->ioa_Data,iob1_right->ioa_Length); iob1_right->ioa_Data=iob1_left->ioa_Data; /* 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_left,volume,speed); InitAudioChannel(iob1_right,volume,speed); /*Get the 2nd audio channel*/ iob2_left=DuplicateAudioChannel(iob1_left); if(iob2_left==NULL) { FreeAudioChannel(iob1_left); FreeAudioChannel(iob1_right); WriteMsg("Couldn't create the second buffer"); cleanup(175); } iob2_right=DuplicateAudioChannel(iob1_right); if(iob2_right==NULL) { FreeAudioChannel(iob1_left); DeleteDuplication(iob2_left); FreeAudioChannel(iob1_right); WriteMsg("Couldn't create the second buffer"); cleanup(175); } FreeMem(iob2_right->ioa_Data,iob2_right->ioa_Length); iob2_right->ioa_Data=iob2_left->ioa_Data; /* Load the first buffer*/ toRead=MIN(length,bufSize); LoadAudioBuffer(file,iob1_left,toRead); length-=toRead; iob1_right->ioa_Length=iob1_left->ioa_Length=toRead; /* Make sure there's enough data so that we have something to put in */ /* the second buffer */ if(length!=0) { toRead=MIN(length,bufSize); LoadAudioBuffer(file,iob2_left,toRead); length-=toRead; iob2_right->ioa_Length=iob2_left->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_left->ioa_Length=iob2_right->ioa_Length=0; /*And queue up the play requests*/ BeginIO((struct IORequest *)iob1_left); BeginIO((struct IORequest *)iob1_right); if(iob2_left->ioa_Length!=0) { BeginIO((struct IORequest *)iob2_left); BeginIO((struct IORequest *)iob2_right); } /* If the sound sample was small enough to fit into the two buffers, */ /* play them then finish up */ if(GetMsg(window->UserPort)!=NULL) done=TRUE; else if(length==0) { /* Bug!!! */ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); if(iob2_left->ioa_Length!=0 && GetMsg(window->UserPort)==NULL) Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; } /*Otherwise, play those samples then read more from disk*/ /*Loop while there's stuff to read*/ while(!done) { /*Fill the first buffer*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(length,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the second buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } LoadAudioBuffer(file,iob1_left,toRead); length-=toRead; iob1_right->ioa_Length=iob1_left->ioa_Length=toRead; /*Play the first buffer*/ BeginIO((struct IORequest *)iob1_left); BeginIO((struct IORequest *)iob1_right); /*Wait for the second buffer to finish*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); toRead=MIN(length,bufSize); if(GetMsg(window->UserPort)!=NULL) { done=TRUE; break; } else if(toRead==0) { /*If there's no stuff left to read, wait 'till the first buffer*/ /*finishes, then quit*/ Wait((1<ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | (1<UserPort->mp_SigBit)); done=TRUE; break; } /*Reload it*/ LoadAudioBuffer(file,iob2_left,toRead); length-=toRead; iob2_right->ioa_Length=iob2_left->ioa_Length=toRead; /*Play it*/ BeginIO((struct IORequest *)iob2_left); BeginIO((struct IORequest *)iob2_right); } /*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/ /*how much memory to free*/ iob1_left->ioa_Length=iob2_left->ioa_Length=bufSize; iob1_right->ioa_Length=iob2_right->ioa_Length=bufSize; iob1_right->ioa_Data=NULL; iob2_right->ioa_Data=NULL; FreeAudioChannel(iob1_left); DeleteDuplication(iob2_left); FreeAudioChannel(iob1_right); DeleteDuplication(iob2_right); return; } /*End of Play.c*/