(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.




                            Simple Audio

                            by Dan Baker     


The code shown below allows you to generate a tone with the Amiga's audio
hardware.  Use the frequency variable to set the pitch in Hz.  Use the
duration variable to set the duration of the tone in seconds.

Audio device IO is handled mainly through the IOAudio structure which is
defined in the audio.h header file.  To make a tone, you open the audio
device and send commands to it using the IOAudio structure.  When you are
finished, close the device.

In the example below, most of the code is used to initialize fields in the 
IOAudio structure.  For instance, the structure is filled in with channel
allocation information just before the  audio device is opened.  This will
cause a channel to be allocated automatically when the device is opened.

The Amiga has a complex allocation and arbitration scheme which is
described in detail in the ROM Kernel Manuals from Addison-Wesley.  For
now though just remember that the array whichannel[] tells the Amiga that 
you want any one of the four audio channels.

After the audio device has been opened the IOAudio structure is initialized 
to play a note.  In the example, AllocMem() is used to reserve two bytes of 
chip memory for the wave data which in this case is a very simple square wave.  
The address of the two byte sample is used in the IOAudio structure along with
computed values for playback sampling rate, sample length and number of cycles.

The command is sent to the audio device using BeginIO().  Once the command is
sent, Wait() is called which puts the task to sleep untill the audio device 
has finished the command.  Finally, GetMsg() is used to clear the reply from 
the audio device which is then closed with CloseDevice().

In the example below, a 2 byte sample is used.  To avoid aliasing distortion
the length of the sample should be increased to 32 bytes and the period
should be restricted to the range 124-256.  This will limit the tones that
can be produced to a one-octave range.  You can find more information on
aliasing distortion and other audio topics in the Amiga Hardware Manual and
in the Amiga ROM Kernel Manuals, both published by Addison-Wesley.





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

struct GfxBase *GfxBase;
struct Message *GetMsg();
struct MsgPort *CreatePort();
APTR            OpenLibrary();
APTR            AllocMem();
ULONG           OpenDevice();
UBYTE           whichannel[] = { 1,2,4,8 };

void
main()
{
struct IOAudio *AudioIOBptr;
struct MsgPort *port;
struct Message *msg;
BYTE           *waveptr;
ULONG           device;
LONG            frequency=440;        /* frequency of the tone           */
LONG            duration =3;          /* duration in seconds             */
LONG            clock    =3579545;    /* Clock constant, 3546895 for PAL */
LONG            samples  =2;          /* Number of sample bytes          */


/*---------------------------------------*/
/* Ask the system if we are PAL or NTSC  */
/* and set clock constant accordingly    */
/*---------------------------------------*/
GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
if(GfxBase==0L) goto killaudio;
if(GfxBase->DisplayFlags & PAL) clock=3546895;        /* PAL clock */
else                            clock=3579545;        /* NTSC clock */
if(GfxBase)CloseLibrary(GfxBase);


/*------------------------------*/
/* Allocate audio I/O blocks    */
/*------------------------------*/
AudioIOBptr=(struct IOAudio *)
         AllocMem( sizeof(struct IOAudio),MEMF_PUBLIC | MEMF_CLEAR);
if(AudioIOBptr==0) goto killaudio;
printf("IO block allocated...\n");


/*-----------------------------------------------*/
/* Set up audio I/O block for channel allocation */
/*-----------------------------------------------*/
port=CreatePort(0,0);
if(port==0) goto killaudio;
printf("Port created...\n");

AudioIOBptr->ioa_Request.io_Message.mn_ReplyPort   = port;
AudioIOBptr->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
AudioIOBptr->ioa_Request.io_Command                = ADCMD_ALLOCATE;
AudioIOBptr->ioa_Request.io_Flags                  = ADIOF_NOWAIT;
AudioIOBptr->ioa_AllocKey                          = 0;
AudioIOBptr->ioa_Data                              = whichannel;
AudioIOBptr->ioa_Length                            = sizeof(whichannel);
printf("IO block initialized for channel allocation...\n");


/*-----------------------------------------------*/
/* Open the audio device and allocate a channel  */
/*-----------------------------------------------*/
device=OpenDevice("audio.device",0,AudioIOBptr,0);
if(device!=0) goto killaudio;
printf("Audio device opened, channel allocated...\n");


/*-----------------------------------------*/
/* Set up audio I/O block to make a sound. */
/*-----------------------------------------*/
waveptr=(BYTE *)AllocMem( samples , MEMF_CHIP|MEMF_PUBLIC);
if(waveptr==0) goto killaudio;
waveptr[0]=  127;
waveptr[1]= -127;
printf("Wave data ready...\n");

AudioIOBptr->ioa_Request.io_Message.mn_ReplyPort = port;
AudioIOBptr->ioa_Request.io_Command              = CMD_WRITE;
AudioIOBptr->ioa_Request.io_Flags                = ADIOF_PERVOL;
AudioIOBptr->ioa_Data                            = (BYTE *)waveptr;
AudioIOBptr->ioa_Length                          = samples;
AudioIOBptr->ioa_Period                          = clock/(samples*frequency);
AudioIOBptr->ioa_Volume                          = 64;
AudioIOBptr->ioa_Cycles                          = frequency*duration;
printf("IO block initialized to play tone...\n");

/*-----------------------------------*/
/* Send the command to start a sound */
/*-----------------------------------*/
printf("Sarting tone now...\n");
BeginIO(AudioIOBptr);
Wait(1 << port->mp_SigBit);
msg=GetMsg(port);

printf("Sound finished...\n");

killaudio:

  printf("Killing audio device...\n");
  if(waveptr!=0)     FreeMem(waveptr, 2);
  if(port!=0)        DeletePort(port);
  if(device==0)      CloseDevice(AudioIOBptr);
  if(AudioIOBptr!=0) FreeMem( AudioIOBptr,sizeof(struct IOAudio) );
}



