/***************************************************************************** * PlaySound.c * This routine sets up an ioRequest and plays back a waveform through the * Amiga audio hardware * * Usage : PlaySound(buffer,repeat,period,volume) * buffer is a pointer to a waveform * repeat is the number of times to play the wave (0 == forever) * period determines the playback rate (minimum value == 124) * volume goes from 0 to 64 *****************************************************************************/ #include "exec/types.h" #include "devices/audio.h" #include "exec/memory.h" #define LEFT0F 1 #define RIGHT0F 2 #define RIGHT1F 4 #define LEFT1F 8 #define SIGBREAKF_CTRL_C (1<<12) extern struct MsgPort *CreatePort(); struct IOAudio *AllocMem(); /* Look for a left channel, then a right */ UBYTE allocationMap[] = { LEFT0F, LEFT1F, RIGHT0F, RIGHT1F }; /***************************************************************************** * Purpose: To allocate and initialize an IO Request Block. * *****************************************************************************/ SetIOA(per, vol, repeat, len, ioa) LONG per, vol, repeat; ULONG len; struct IOAudio **ioa; { struct MsgPort *port; /* Allocate IOAudio structure */ (*ioa) = AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR); /* If Allocation Successful ... */ if (*ioa) { /* Set Priority */ (*ioa)->ioa_Request.io_Message.mn_Node.ln_Pri = 10; /* Create Message port for IORequest to talk to Amiga */ if (!(port = CreatePort(NULL, 0))) { FreeMem((*ioa), sizeof(struct IOAudio)); *ioa = NULL; } /* If Creation Successful ... */ else { /* Get a channel */ (*ioa)->ioa_Request.io_Message.mn_ReplyPort = port; (*ioa)->ioa_Data = allocationMap; (*ioa)->ioa_Length = sizeof(allocationMap); /* Open Audio Device for output */ if(OpenDevice(AUDIONAME, 0, (*ioa), 0)) { DeletePort(port); FreeMem((*ioa), sizeof(struct IOAudio)); *ioa = NULL; } /* If open worked ... */ else { /* Set Up Request */ (*ioa)->ioa_Request.io_Flags = ADIOF_PERVOL; (*ioa)->ioa_Request.io_Command = CMD_WRITE; (*ioa)->ioa_Period = per; (*ioa)->ioa_Volume = vol; /* For some reason, the Audio chip can't play samples */ /* longer than 131k, so we kludge. Oh, well. */ if(len < 131000) (*ioa)->ioa_Cycles = repeat; else (*ioa)->ioa_Cycles = 1; } } } } /***************************************************************************** * Purpose: To play back a sound. * *****************************************************************************/ struct IOAudio *PlaySound(buffer, buflen, repeat, period, volume) BYTE *buffer; ULONG buflen; LONG repeat,period,volume; { struct IOAudio *ioa; BYTE *DataPtr; ULONG PlayLen; DataPtr = buffer; /* Set Up IOAudio structure */ SetIOA(period, volume, repeat, buflen, &ioa); if (!ioa) return(NULL); /* Set up data and length pointers of ioa */ SetLength(&PlayLen, buflen, &DataPtr, ioa); /* Send command to Audio chip */ BeginIO(ioa); repeat--; /* If no data remains to play, return ioa pointer */ if(PlayLen == 0) return(ioa); /* If there is more (buflen > 131000), continue until there isn't */ while(TRUE) { ULONG signals; /* Wait until current chunk is done */ signals = Wait((1 << ioa->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) | SIGBREAKF_CTRL_C); if (signals & SIGBREAKF_CTRL_C) { SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); return(ioa); } /* If more remains, continue */ if(PlayLen > 0) { /* update pointers and start next chunk */ FixLength(&PlayLen, &DataPtr, ioa); BeginIO(ioa); /* return if playing the last chunk for the last time */ if((PlayLen == 0) && (repeat == 0)) return(ioa); } /* If not ... */ else { /* Check repeat counter */ if(repeat != 0) { /* Restart wave */ DataPtr = buffer; SetLength(&PlayLen, buflen, &DataPtr, ioa); BeginIO(ioa); if(repeat > 0) repeat--; } } } } /***************************************************************************** * Purpose: To stop and delete a sound. THIS IS THE CLEAN UP ROUTINE!! * *****************************************************************************/ StopSound(struct IOAudio *ioa) { AbortIO(ioa); if(ioa->ioa_Request.io_Device) CloseDevice(ioa); if(ioa->ioa_Request.io_Message.mn_ReplyPort) DeletePort(ioa->ioa_Request.io_Message.mn_ReplyPort); if(ioa) FreeMem(ioa,sizeof(struct IOAudio)); } /***************************************************************************** * Purpose: To set the length of the sound to be played. * *****************************************************************************/ SetLength(ULONG *LenPtr, ULONG buflen, BYTE **DataHndl, struct IOAudio *ioa) { if(buflen <= 131000) (*LenPtr) = buflen; else (*LenPtr) = 131000; ioa->ioa_Length = (*LenPtr); ioa->ioa_Data = (*DataHndl); if((*LenPtr) != buflen) { (*LenPtr) = buflen - 131000; (*DataHndl) += 131000; } else (*LenPtr) = 0; } /***************************************************************************** * Purpose: To Check, if the full sound is to be played (or max 131000 bytes)* *****************************************************************************/ FixLength(ULONG *LenPtr, BYTE **DataHndl, struct IOAudio *ioa) { if((*LenPtr) > 131000) { ioa->ioa_Length = 131000; ioa->ioa_Data = (*DataHndl); (*LenPtr) -= 131000; (*DataHndl) += 131000; } else { ioa->ioa_Length = (*LenPtr); ioa->ioa_Data = (*DataHndl); (*LenPtr) = 0; } }