#include #include #include #include #include "sample.h" #include "sounds.h" #define YES 1 #define NO 0 extern int debug; /* #define WHERE fprintf(stderr,"%s %s %d\n",__FILE__,__FUNC__,__LINE__); */ /* #define WHAT(x) fprintf(stderr,"%s %s %d %s\n",__FILE__,__FUNC__,__LINE__,x->name); */ #define WHERE #define WHAT(x) #define CLOCKFREQ 3579545 extern Sound *sounds[]; extern int maxsounds; int audio_up = NO; /* set to yes after initilization is complete, */ /* used by "endaudio" to figure out clean up */ struct Device *AudioDevice; struct MsgPort *AudioPort; struct IOAudio *openIOB; static UBYTE LeftMap[] = {LEFT0, LEFT1}; static UBYTE RightMap[] = {RIGHT0, RIGHT1}; static UBYTE TryLeftMap[] = {LEFT1, LEFT0, RIGHT1, RIGHT0}; static UBYTE TryRightMap[] = {RIGHT1, RIGHT0, LEFT1, LEFT0}; _abort() { fputs("abort caused by ^C or audio panic\n",stderr); cleanup(debug); exit(10); } panic(s) char *s; { fprintf(stderr,"panic: %s\n",s); _abort(); } struct IOAudio *IOBallocate() { struct IOAudio *IOB; if ((IOB = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR)) == (struct IOAudio *) NULL) panic("IOBallocate failed"); return(IOB); } IOBfree(IOBp) struct IOAudio *IOBp; { if (IOBp != NULL) FreeMem(IOBp, sizeof(struct IOAudio)); } InitPlayIOB(soundp) Sound *soundp; { struct IOAudio *IOB = soundp->IOBs[PLAY_IOB]; IOB->ioa_Request.io_Command = CMD_WRITE; IOB->ioa_Request.io_Flags = ADIOF_PERVOL; IOB->ioa_Volume = soundp->volume; IOB->ioa_Cycles = soundp->cycles; IOB->ioa_Data = (UBYTE *)&soundp->samplep->sampledata[0]; IOB->ioa_Length = (ULONG)soundp->samplep->nsamples; IOB->ioa_Period = (CLOCKFREQ / soundp->samplep->sampsec) + soundp->detune; } InitStopIOB(soundp) Sound *soundp; { struct IOAudio *IOB = soundp->IOBs[STOP_IOB]; IOB->ioa_Request.io_Command = ADCMD_FINISH; IOB->ioa_Request.io_Flags = IOF_QUICK; } InitAllocIOB(soundp) Sound *soundp; { struct IOAudio *allocIOB = soundp->IOBs[ALLOC_IOB]; allocIOB->ioa_Request.io_Command = ADCMD_ALLOCATE; allocIOB->ioa_Request.io_Message.mn_Node.ln_Pri = soundp->precedence; if (!soundp->flags & EITHER) { allocIOB->ioa_Data = (soundp->flags & LEFT) ? LeftMap : RightMap; allocIOB->ioa_Length = 2; } else { allocIOB->ioa_Data = (soundp->flags & LEFT) ? TryLeftMap : TryRightMap; allocIOB->ioa_Length = 4; } allocIOB->ioa_Request.io_Flags = (ADIOF_NOWAIT | IOF_QUICK); } InitDeallocIOB(soundp) Sound *soundp; { struct IOAudio *IOB = soundp->IOBs[FREE_IOB]; IOB->ioa_Request.io_Command = ADCMD_FREE; IOB->ioa_Request.io_Flags = IOF_QUICK; } initsound(soundindex) int soundindex; { int i; struct IOAudio *IOB; Sound *soundp = sounds[soundindex]; if ((soundp->port = CreatePort(soundp->name, 0)) == 0) { fprintf(stderr,"can't create audio port \"%s\"\n",soundp->name); panic("can't create audio port"); } for (i = 0; i < MAX_SOUND_IOBS; i++) { IOB = soundp->IOBs[i] = IOBallocate(); IOB->ioa_Request.io_Message.mn_ReplyPort = soundp->port; IOB->ioa_Request.io_Device = AudioDevice; /* We assign our own AllocKeys so we'll have a handle to determine * which sound structure we received at a reply port. This also * makes playtime overhead less by not having to throw around * dynamically-allocated allocation keys. If AllocKey * is zero when channels are allocated, a key is dynamically assigned * We use soundindex + 1 instead of soundindex to prevent a zero * allockey. Also, we reduce playtime overhead by not throwing * dynamically-assigned keys around. */ IOB->ioa_AllocKey = soundindex + 1; } InitPlayIOB(soundp); InitStopIOB(soundp); InitAllocIOB(soundp); InitDeallocIOB(soundp); } initaudio() { int i; openIOB = IOBallocate(); if (OpenDevice(AUDIONAME, 0, openIOB, 0) != 0) panic("can't open audio device"); AudioDevice = openIOB->ioa_Request.io_Device; for (i = 0; i < maxsounds; i++) initsound(i); audio_up = YES; } endaudio() { int i, j; if (audio_up) { for (i = 0; i < maxsounds; i++) StopSound(sounds[i]); } for (i = 0; i < maxsounds; i++) { for (j = 0; j < MAX_SOUND_IOBS; j++) IOBfree(sounds[i]->IOBs[j]); if (sounds[i]->port) DeletePort(sounds[i]->port,sizeof(struct MsgPort)); } CloseDevice(openIOB); IOBfree(openIOB); } PlaySound(soundp) Sound *soundp; { int i; struct IOAudio *allocIOB = soundp->IOBs[ALLOC_IOB]; struct IOAudio *playIOB = soundp->IOBs[PLAY_IOB]; if (soundp->flags & PLAYING) return; BeginIO(allocIOB); /* the only possible error return is ADIOERR_NOALLOCATION */ if (allocIOB->ioa_Request.io_Error) return; for (i = PLAY_IOB; i <= FREE_IOB; i++) soundp->IOBs[i]->ioa_Request.io_Unit = allocIOB->ioa_Request.io_Unit; BeginIO(playIOB); /* possible errors are IOERR_ABORTED and ADIOERR_NOALLOCATION */ if (playIOB->ioa_Request.io_Error) return; soundp->flags |= PLAYING; } DeallocSound(soundp) Sound *soundp; { struct IOAudio *freeIOB = soundp->IOBs[FREE_IOB]; BeginIO(freeIOB); /* only possible error return is ADIOERR_NOALLOCATION */ } StopSound(soundp) Sound *soundp; { struct IOAudio *stopIOB = soundp->IOBs[STOP_IOB]; struct IOAudio *freeIOB= soundp->IOBs[FREE_IOB]; WHAT(soundp); if (soundp->flags & PLAYING) { soundp->flags &= ~PLAYING; BeginIO(stopIOB); /* only error return is ADIOERR_NOALLOCATION */ WaitIO(soundp->IOBs[PLAY_IOB]); /* error returns can be IOERR_ABORTED and ADIOERR_NOALLOCATION */ } DeallocSound(soundp); } WaitSound(soundp) Sound *soundp; { WHAT(soundp); if (soundp->flags & PLAYING) { WaitIO(soundp->IOBs[PLAY_IOB]); soundp->flags &= ~PLAYING; } DeallocSound(soundp); } dumpsound(soundp) Sound *soundp; { printf("dump of sound %s\n",soundp->name); printf("cycles %d, volume %d, flags %d, precedence %d, detune %d\n", soundp->cycles, soundp->volume, soundp->flags, soundp->precedence, soundp->detune); dumpsample(soundp->samplep); } dumpsample(samptr) Sample *samptr; { int i, linect; printf("nsamples %d, sampsec %d\n",samptr->nsamples, samptr->sampsec); /* for (i = 0; i < samptr->nsamples; i++) { printf("%4d ",samptr->sampledata[i]); if (++linect > 14) { putchar('\n'); linect = 0; } } */ }