/***************************************\
* This file controls the audio (beep.c) *
\***************************************/

#include "exec/types.h"
#include "exec/memory.h"
#include "devices/audio.h"

extern struct MsgPort *CreatePort();

/* allocation map: first try for a left chan, else right */
static UBYTE allocationMap[] = {1, 8, 2, 4};

#define REPS    3          /* number of copies of pattern in buffer */
#define BUFSIZE (32*REPS)

static struct IOAudio *ioa = NULL;

InitAudio(loudness) int loudness; {
   int i;
   ioa = (struct IOAudio *)AllocMem(sizeof(*ioa), MEMF_PUBLIC|MEMF_CLEAR);
   if (ioa == NULL) return(TRUE);
   ioa->ioa_Request.io_Message.mn_Node.ln_Pri = 10;
   ioa->ioa_Request.io_Message.mn_ReplyPort = CreatePort("Beeper", 0);
   if (ioa->ioa_Request.io_Message.mn_ReplyPort == NULL) return(Flush(FALSE));
   ioa->ioa_Data = allocationMap;
   ioa->ioa_Length = sizeof(allocationMap);
   if (OpenDevice(AUDIONAME, 0, ioa, 0)) return(Flush(FALSE));
   ioa->ioa_Request.io_Command = CMD_WRITE;
   ioa->ioa_Request.io_Flags = ADIOF_PERVOL;
   ioa->ioa_Data = (UBYTE *)AllocMem(BUFSIZE, MEMF_CHIP);
   if (ioa->ioa_Data == NULL) return(Flush(TRUE));
   for (i=0; i<BUFSIZE; i++) {
      int j;
      j = Sine32nd(i*2) * 4 + Sine32nd(i*3) * 9;
      ioa->ioa_Data[i] = (j > 0 ? j+65 : j-65) / 130;
      }
   ioa->ioa_Length = BUFSIZE;
   /* start a request so we can wait for it later (in Flush) */
   ioa->ioa_Period = ioa->ioa_Cycles = 200;
   ioa->ioa_Volume = 0;
   BeginIO(ioa);
   SetBeeper(loudness);
   return(FALSE);
   }

SetBeeper(loudness) int loudness; {
   if (loudness < 0 || loudness > 4) ioa->ioa_Volume = 0;
   else {
      ioa->ioa_Period = 127*(loudness+2)/2;
      ioa->ioa_Cycles = 480/(loudness+2);
      ioa->ioa_Volume = (60 >> loudness) + 4;
      }
   }

Beep() {
   if ((! ioa) || ioa->ioa_Volume == 0) return(TRUE); /* need video beep */
   BeginIO(ioa);
   return(FALSE);
   }

CleanUpBeeper() {
   if (ioa) Flush(TRUE);
   }

static Flush(opened) int opened; {
   if (opened) {
      WaitIO(ioa);
      if (ioa->ioa_Data) FreeMem(ioa->ioa_Data, BUFSIZE);
      CloseDevice(ioa);
      }
   if (ioa->ioa_Request.io_Message.mn_ReplyPort)
      DeletePort(ioa->ioa_Request.io_Message.mn_ReplyPort);
   FreeMem(ioa, sizeof(*ioa));
   ioa = NULL;
   return(TRUE);
   }

static Sine32nd(n) int n; { /* returns 1270*sin(2PI*n/32), rounded */
   static int qtr[] = {0, 248, 486, 706, 898, 1056, 1173, 1246, 1270};
   if (n < 0) return(-Sine32nd(-n));
   n %= 32;
   switch (n/8) {
      case 0: return(qtr[n]);
      case 1: {n = 16-n; return(qtr[n]);}
      case 2: {n -= 16; return(-qtr[n]);}
      case 3: {n = 32-n; return(-qtr[n]);}
      }
   return(0);
   }
