home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d7xx
/
d787
/
scale.lha
/
Scale
/
Source.lha
/
atool31.c
next >
Wrap
C/C++ Source or Header
|
1992-12-12
|
26KB
|
870 lines
/* Audiotools.c release 3.1 -- by Rob Peck */
/* This is a modified version of AudioTools -- changes by Dick Taylor */
/* to use with the SCALE program. November 1992 */
/* Please refer to file scale.doc for AudioTools background. */
#include "exec/types.h"
#include "exec/memory.h"
#include "devices/audio.h"
/* audiotools.h -- in original version, this was a separate module */
#define StartChannel(c) ControlChannel(c, CMD_START)
#define StopChannel(c) ControlChannel(c, CMD_STOP)
#define ResetChannel(c) ControlChannel(c, CMD_RESET)
#define FlushChannel(c) ControlChannel(c, CMD_FLUSH)
#define BIG_WAVE 256L /* size of biggest waveform */
#define NBR_WAVES 7L /* number of waves per instrument */
#define WAVES_TOTAL 1024L /* alloc size for instrument's waves */
#define DEFAULT_DURATION 500L /* 500/1000ths of a second default */
#define AUDBUFFERS 20L /* iob msg packets before need to allot */
#define YES 1L
#define NO 0L
#define BAD_CHANNEL_SELECTED -1L /* channel # out of range */
#define NOT_YOUR_CHANNEL -2L /* not owned by your task */
#define OUT_OF_RANGE_FREQ -3L /* frequency that we cannot play */
#define OUT_OF_RANGE_PRI -4L /* priority value wont fit in 1 byte */
/* Note that the definition of ExtIOB has now been changed (added to) */
struct ExtIOB {
struct IORequest ioa_Request;
WORD ioa_AllocKey;
UBYTE *ioa_Data;
ULONG ioa_Length;
UWORD ioa_Period;
UWORD ioa_Volume;
UWORD ioa_Cycles;
struct Message ioa_WriteMsg; /* up to here, same as IOAudio */
LONG iob_Identifier; /* This field is added */
};
/* a few forward declarations */
extern struct ExtIOB *GetIOB();
extern int FreeIOB();
extern int GetChannel();
extern int InitBlock();
extern struct MsgPort *CreatePort();
extern struct MsgPort *InitAudio();
extern APTR AllocMem();
extern struct Message *GetMsg();
extern struct Task *FindTask();
extern LONG SetCycles();
extern int TicksPerSec; /* Clock ticks per second -- */
/* NTSC (American) = 3579545, or */
/* PAL (European) = 3546895 */
struct auMsg {
struct Message au_Message;
LONG aum_Identifier; /* matches the bottom of ExtIOB */
};
/* these are used to keep track of allocated channels */
struct Unit *unit[4]; /* global pointers to Units */
WORD key[4]; /* global value for alloc keys */
struct Task *usertask[4]; /* in preparation for making this
* a shared library of routines
* (loadable from disk), keep track
* of which user actually owns a
* channel currently. */
/* End of audiotools.h, start of former external module globals.c */
struct IOAudio openIOB; /* IOB to open and close the device */
struct MsgPort *auReplyPort; /* temporary pointer */
struct MsgPort *controlPort; /* Port for ControlChannel functions */
char *globalname = "global"; /* the name for global IOB's */
char *dynamicname = "dynamic"; /* the name for dynamic IOB's */
UBYTE anychan[4] = { 1, 2, 4, 8 }; /* channel masks for mono */
/* Resolve most all externals */
struct ExtIOB audbuffer[AUDBUFFERS]; /* globals to build-in */
UBYTE *chipaudio[4]; /* pointers to waveforms in CHIP RAM */
struct Device *device; /* global pointer to audio device */
LONG datalength[4]; /* length of the data for a wave */
struct MsgPort *replyPort[4]; /* one ReplyPort per channel */
BYTE inuse[AUDBUFFERS]; /* keep track of globals in-use */
LONG dynamix[4]; /* counters for how many
* dynamically allocated audio
* message I/O blocks */
/* Each waveform buffer contains 8 octaves of the wave.
* The offset values specify where in the buffer the
* proper waveform table for that octave begins.
*/
int woffsets[] = { 0, 256, 384, 448, 480, 496, 504, 508, 510 };
/* Length of each waveform within a buffer */
int wlen[] = { 256, 128, 64, 32, 16, 8, 4, 2, 1 };
/* Period value to go with particular notes within an octave. */
int perval[] = { 428, 404, 381, 360, 339, 320,
302, 285, 269, 254, 240, 226, 214 };
UBYTE *w1, *w2, *w3;
/* End of globals.c */
struct MsgPort *
InitAudio()
{
LONG error,i;
struct MsgPort *userport; /* NEW item */
LONG firstuser; /* THIS WILL GET MOVED when shared library is made */
firstuser = TRUE;
/* Declare all message blocks available */
for(i=0; i<AUDBUFFERS; i++) { inuse[i] = NO; }
/* Open device but don't allocate channels */
openIOB.ioa_Length = 0; /* (no allocation table) */
error = OpenDevice("audio.device",0,&openIOB,0);
if(error) return((struct MsgPort *)0);
/* Get the device address for later use */
device = openIOB.ioa_Request.io_Device;
/* Create ports for replies from each channel as well as
* one port to be used for the control and synchonous functions */
for(i=0; i<4; i++)
{
auReplyPort = CreatePort(0,0);
replyPort[i] = auReplyPort;
if(auReplyPort == 0) return((struct MsgPort *)0);
chipaudio[i] = 0; /* have not yet created the waves */
datalength[i] = 1; /* might use for custom sound samples */
/* Also, zero out key values for each channel, as well as
* unit value and usertask value (no channel owned by any task)*/
/* When implemented as a shared library, "firstuser" will only
* be true when the library is first opened.*/
if(firstuser)
{
key[i] = 0;
unit[i] = 0;
usertask[i] = 0;
}
}
controlPort = CreatePort(0,0);
if(controlPort == 0) return((struct MsgPort *)0);
error = MakeWaves();
if(error == -1) return((struct MsgPort *)0);
for(i=0; i<4; i++)
{ dynamix[i] = 0; } /* no dynamic I/O blocks allocated
* for any channel thus far */
userport = CreatePort(0,0);
return(userport);
}
int
CheckIOBDone()
{
LONG i, status;
status = 0; /* means there are still some iob's in play */
/* when status = 5, then everything is free */
for(i=0; i<AUDBUFFERS; i++)
{ if(inuse[i] == YES)
{
/* Sooner or later, this will catch both the statics & dynamics.
* Note that this will only work if NO iob's sent off with a
* duration value of "0", because zero means "forever". */
ReEmployIOB();
}
}
/* Note to implementors... maintaining inuse[i] now seems
* like a lousy idea, unless it is accompanied by a variable
* statics_inplay that decrements to zero when all statics
* are done. That makes it much easier to check than going
* through all of the inuse[]'s.*/
for(i=0; i<4; i++)
{
if(dynamix[i] > 0)
/* If this channel still playing a dynamically allocated block, */
/* wait for all messages to return before the program exits. */
{
ReEmployIOB(); /* take another shot at freeing it all */
}
}
for(i=0; i<4; i++) /* Check again as we nearly exit */
{
if(dynamix[i] == 0) status++;
}
if(status == 4) /* All dynamics are free, now check the statics.
* Any not free force an early return. */
{
#ifdef DEBUG
printf("ch0,1,2,3 have %ld,%ld,%ld,%ld dyn.blocks playing\n",
dynamix[0], dynamix[1], dynamix[2], dynamix[3]);
#endif
for(i=0; i<AUDBUFFERS; i++)
{
if(inuse[i] == YES)
{
#ifdef DEBUG
printf("iob still in use is: %ld\n",i);
#endif
return(0);
}
}
#ifdef DEBUG
printf("All global I/O blocks are done\n");
#endif
return(1); /* DONE! */
}
else
{
return(0); /* still some out there! */
}
}
FinishAudio(uport)
struct MsgPort *uport;
{
LONG i;
struct auMsg *aum; /* A little bigger than a standard message,
* but this routine will not know (or care) about the difference.*/
if(uport == 0)
{
goto no_init; /* InitAudio didn't work, bypass
* the usual port emptying and so on. */
}
/* If the user says FinishAudio, IT MEANS FINISH AUDIO. Flush anything
* that is still in play, NOW. You can use "CheckIOBDone()" to see if
* everything is finished BEFORE you call FinishAudio. If CheckIOBDone() is
* equal to zero (FALSE), it means that something is still playing. */
for(i=0; i<4; i++) FlushChannel(i);
while(CheckIOBDone() == 0)
{
Delay(12); /* Be a good multitasking neighbor;
* sleep a little before trying again */
}
/* Empty the port if the user has not yet done so */
while((aum = (struct auMsg *)GetMsg(uport)) != NULL)
{
aum->au_Message.mn_ReplyPort = 0; /* let system deallocate it */
/* *** THIS WILL CHANGE --will be based on the identifier field instead.*/
}
ReEmployIOB(); /* free all static and dynamic messages */
for(i=0; i<4; i++) FreeChannel(i);
DeletePort(uport);
no_init:
if(device) CloseDevice(&openIOB);
#ifdef DEBUG
printf("closed the device\n");
#endif
for(i=0; i<4; i++)
{
if(chipaudio[i]) FreeMem(chipaudio[i],WAVES_TOTAL);
if(replyPort[i])
DeletePort(replyPort[i]);
}
if(controlPort) DeletePort(controlPort);
return(0); /* no errors */
}
int
ControlChannel(channel, command)
WORD channel;
WORD command;
{
LONG rtn;
struct ExtIOB *iob, controlIOB;
if(channel < 0 || channel > 3) return(BAD_CHANNEL_SELECTED);
if(usertask[channel] != FindTask(0)) return(NOT_YOUR_CHANNEL);
iob = &controlIOB;
iob->ioa_Request.io_Device = device;
iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
InitBlock(iob,channel); /* init it for CMD_WRITE, then change */
iob->ioa_Request.io_Command = command;
iob->ioa_Request.io_Flags = IOF_QUICK;
BeginIO(iob);
WaitIO(iob);
rtn = ((LONG)(iob->ioa_Request.io_Error));
return(rtn);
}
struct ExtIOB *
GetIOB(ch)
LONG ch;
{
WORD i,use_reply;
struct ExtIOB *iob; /* in case we need to allocate one */
ReEmployIOB(); /* find already used ones and free them */
/* so that when we do a get... */
if(ch == -1) use_reply = 0; /* which reply port to use */
else use_reply = ch;
for(i=0; i<AUDBUFFERS; i++)
{
if(inuse[i] == NO)
{
inuse[i] = YES;
audbuffer[i].ioa_Request.io_Device = device;
audbuffer[i].ioa_Request.io_Message.mn_ReplyPort =
replyPort[use_reply];
audbuffer[i].ioa_Request.io_Message.mn_Length = i;
audbuffer[i].ioa_Request.io_Message.mn_Node.ln_Name =
globalname;
#ifdef DEBUG
printf("Using global iob\n");
#endif
return(&audbuffer[i]);
}
}
/* if all globals are in use, have to allocate one */
iob = (struct ExtIOB *)AllocMem(sizeof(struct ExtIOB),
MEMF_CLEAR );
/* BUG FIX - was MEMF_FAST only, and would not run on 512k machine!! */
if(iob == 0) return(0); /* out of memory */
else
{
iob->ioa_Request.io_Device = device;
iob->ioa_Request.io_Message.mn_ReplyPort =
replyPort[use_reply];
iob->ioa_Request.io_Message.mn_Node.ln_Name =
dynamicname;
iob->ioa_Request.io_Message.mn_Length = dynamix[use_reply];
dynamix[use_reply] += 1; /* add one to number allocated
* for a specific channel */
#ifdef DEBUG
printf("Using dynamic iob\n");
#endif
return(iob);
}
return(0);
}
/* Free a global or an allocated IOB */
int
FreeIOB(iob, ch)
struct ExtIOB *iob;
LONG ch; /* which channel was it attached to? */
{
WORD i;
if(iob->ioa_Request.io_Message.mn_Node.ln_Name == dynamicname)
{
FreeMem(iob, sizeof(struct ExtIOB));
if(dynamix[ch]) dynamix[ch] -= 1; /* subtract one if nonzero */
return(0L);
}
else if(iob->ioa_Request.io_Message.mn_Node.ln_Name == globalname)
{
i = iob->ioa_Request.io_Message.mn_Length;
if(i < AUDBUFFERS)
{
inuse[i] = NO; /* frees this one for reuse */
}
return(0L);
}
/* if get here, the names don't match... something is wrong.*/
else
{
printf("FreeIOB: names don't match...unknown error\n");
return(-1); /* unknown source of IOB fed to routine. */
}
return(0);
}
/* Initialize an audio I/O block for default CMD_WRITE operation. */
int
InitBlock(iob, channel)
struct ExtIOB *iob;
WORD channel;
{
/* Device and ReplyPort fields have been initialized by GetIOB */
iob->ioa_Request.io_Unit = unit[channel];
/* Allocation key */
iob->ioa_AllocKey = key[channel];
/* Where is the waveform? Just be sure is in MEMF_CHIP!!! */
/* USER initializes datalength[ch] before calling this; */
/* for sampled sound command write operation. */
iob->ioa_Data = chipaudio[channel];
iob->ioa_Length = datalength[channel];
/* Another routine, must initialize:
period ioa_Period volume ioa_Volume
cycles ioa_Cycles message ioa_WriteMsg */
/* Default command type is CMD_WRITE */
iob->ioa_Request.io_Command = CMD_WRITE;
/* If IOF_QUICK is zeroed, this would affect the
* period and volume. If a CMD_WRITE, it queues if
* another note is already playing. We queue CMD_WRITES. */
iob->ioa_Request.io_Flags = ADIOF_PERVOL;
return(0);
}
/* To request "any" channel, use ch = -1;
* To request a specific channel, use ch = {0, 1, 2 or 3};
* Again NOTE, this returns two globals as well as the channel number! */
int
GetChannel(ch)
LONG ch;
{
int error, value;
struct ExtIOB *iob, controlIOB;
iob = &controlIOB;
iob->ioa_Request.io_Device = device;
iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
InitBlock(iob,0); /* init it for CMD_WRITE, then change */
iob->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
iob->ioa_Request.io_Command = ADCMD_ALLOCATE;
if(ch == -1)
{
iob->ioa_Data = (UBYTE *)anychan;
iob->ioa_Length = 4;
}
else if(ch >=0 && ch <= 3)
{
/* Test to be sure that this channel is now free. If
* usertask[i] is not zero, either the current task
* has already allocated this channel, or a different
* task is now using it. */
if(usertask[ch] != 0) return(-1);
iob->ioa_Data = (UBYTE *)(&anychan[ch]);
iob->ioa_Length = 1;
}
else /* chose a bad channel number; cannot allocate it */
{
return(-1);
}
iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
BeginIO(iob);
error = WaitIO(iob); /* returns nonzero if error */
if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
{
GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
}
if(error)
{
return(-1);
}
switch((LONG)(iob->ioa_Request.io_Unit))
{
case 1: value = 0; break;
case 2: value = 1; break;
case 4: value = 2; break;
case 8: value = 3; break;
default: value = -1; break;
}
if(value == -1) return(-1L);
unit[value] = (iob->ioa_Request.io_Unit);
key[value] = (iob->ioa_AllocKey);
usertask[value] = FindTask(0); /* THIS user task owns it now */
return(value);
}
int
FreeChannel(channel)
LONG channel;
{
int error;
struct ExtIOB *iob, controlIOB;
if(channel < 0 || channel > 3) return(BAD_CHANNEL_SELECTED);
if(usertask[channel] != FindTask(0)) return(NOT_YOUR_CHANNEL);
iob = &controlIOB;
iob->ioa_Request.io_Device = device;
iob->ioa_Request.io_Message.mn_ReplyPort = controlPort;
InitBlock(iob,channel); /* init it for CMD_WRITE, then change it */
/* (pick up unit, key value for channel) */
iob->ioa_Request.io_Command = ADCMD_FREE;
iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
BeginIO(iob);
error = WaitIO(iob); /* returns nonzero if error */
if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
{
GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
}
usertask[channel] = 0; /* free again... */
if(error)
{
return(error);
}
return(0);
}
/* SOME OF THE FOLLOWING ROUTINES ARE PARAPHRASED FROM A USENET and BIX
* POSTING MADE IN 1985 BY STEVEN A. BENNETT. */
/* I have modified his routines to queue the audio commands in
* place of starting forever-duration and canceling each note.
* Many of his original comments have been incorporated into
* the article.*/
/* ******************************************************************* */
/* NOTE: There are some differences in PlayNote as compared to the article.
* See the audiotools.DOC for details.*/
/* ******************************************************************* */
/* Starts a sound on the channel with specified period and volume. */
/* This nice little routine takes a note and plays it on the given
* voice. The note is basically an integer from
* 0 to 11 (c to b) plus 12 per octave above the first and lowest.
*
* The waveform to use is determined by adding an index (woffsets[])
* dependent on the octave.
*
* The length of the waveform (in wlen[]) is likewise dependent on
* the octave. Note that octaves start with zero, not one.
*/
int
/*PlayNote(channel, note, wf, vol, duration, priority, messageport, id)*/
PlayNote(channel, note, vol, duration)
/* char *wf; /* waveform to use */
/* LONG vol, channel, duration, note; /* specific note number */
/* LONG priority;
struct MsgPort *messageport;
LONG id; */
LONG channel, note, vol, duration;
{
LONG per, len, oct; /* period, length of waveform, which octave */
char *wavepointer; /* where to find start of waveform */
struct ExtIOB *iob;
if(channel < 0 || channel > 3) return(BAD_CHANNEL_SELECTED);
if(usertask[channel] != FindTask(0)) return(NOT_YOUR_CHANNEL);
if(note < 0 || note > 95) return(OUT_OF_RANGE_FREQ);
/* if(priority < -128 || priority > 127)return(OUT_OF_RANGE_PRI);*/
iob = GetIOB(channel);
if(iob != 0)
{
InitBlock(iob, channel); /* set up for CMD_WRITE */
oct = note / 12;
/* wavepointer = wf + woffsets[oct];*/
wavepointer = w1 + woffsets[oct]; /* Always waveform #1 */
len = wlen[oct];
per = perval[note % 12];
/* Set the parameters */
iob->ioa_Data = (UBYTE *)wavepointer;
iob->ioa_Length = len;
iob->ioa_Period = per;
iob->ioa_Volume = vol;
/* iob->ioa_Request.io_Message.mn_Node.ln_Pri = priority;*/
iob->ioa_Request.io_Message.mn_Node.ln_Pri = 0; /* always pri=0*/
/* additions for support of tell-me-when-note-starts */
/* iob->iob_Identifier = id;*/
iob->iob_Identifier = 0; /* Always id = 0 */
/* Initialize message port. If 0, then no pushing back
* of a message. If nonzero, message gets recirculated
* by ReEmployIOB until the user finally acknowledges it
* by using MayGetNote.
*/
/* iob->ioa_WriteMsg.mn_ReplyPort = messageport;*/
iob->ioa_WriteMsg.mn_ReplyPort = 0; /* Always messageport = 0 */
/* if(messageport != 0)
{ */
/* If 0, no sending message when note plays;
* if nonzero, user gets a message that can
* be read by MayGetNote. uport, received from
* InitAudio, is where the message goes */
/* Tell the audio device to "reply" to this message */
/* iob->ioa_Request.io_Flags |= ADIOF_WRITEMESSAGE;
} */
/* Calculate cycles from duration in 1000ths of a second */
/* Multiply all-in-one to maintain max precision possible */
/* (all integer arithmetic.) */
iob->ioa_Cycles = SetCycles(duration,len,per);
BeginIO(iob);
return(0L); /* all went ok */
}
return(-99L); /* (else-part) iob was zero, couldn't do the above. */
}
/* SetWaves(w1, w2, w3): create first sawtooth, triangle and square wave */
SetWaves(w1, w2, w3)
UBYTE *w1, *w2, *w3;
{
int i, increment, value, sqvalue;
value = 0; increment = 2;
sqvalue = 127;
for (i = 0; i < BIG_WAVE; ++i)
{
w1[i] = i; /* do the sawtooth */
if(i > 62 && i < 180) increment = -2;
else
if(i >= 180) increment = 2;
w2[i] = value; value += increment; /* triangle wave */
if(i > 126) sqvalue = -127;
w3[i] = sqvalue;
}
return(0L);
}
/* ExpandWave(wfp) - replicate waves in decreasing sample sizes */
ExpandWave(wfp)
BYTE *wfp;
{
int i, j, rate;
BYTE *tptr;
rate = 1;
tptr = wfp + BIG_WAVE;
for (i = 0; i < NBR_WAVES - 1; ++i)
{
rate *= 2;
for (j = 0; j < BIG_WAVE; j += rate)
*tptr++ = wfp[j];
}
return(0L);
}
/* MakeWaves -- Just makes a sawtooth, triangle and square wave
* in chip mem and expands them.*/
int
MakeWaves()
{
/* allocate the memory for the waveforms.
*/
w1 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
w2 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
w3 = (UBYTE *)AllocMem(WAVES_TOTAL, MEMF_CHIP);
if (w1 == NULL || w2 == NULL || w3 == NULL)
return(-1L); /* ran out of memory! */
/* get and expand the waveforms */
SetWaves(w1, w2, w3);
ExpandWave(w1); chipaudio[0]=w1;
ExpandWave(w2); chipaudio[1]=w2;
ExpandWave(w3); chipaudio[2]=w3;
return(0L);
}
/* ReEmployIOB is not new (as compared to article) but it
* has changed a lot since the article was written.*/
/* ReEmployIOB - look at ALL of the reply ports and if any IOBs
hanging around with nothing to do, free them.*/
ReEmployIOB()
{
LONG i;
struct MsgPort *mp;
struct ExtIOB *iob;
/* now declare a pointer to "the first iob pushed back onto the port" */
struct ExtIOB *pushback;
/* What happens here is that iob's are removed from the message port
* when they come back from the audio device. If YOU have set the
* messageport nonzero, it means that you wanted to know when
*** THIS WILL CHANGE --- will be based on setting
the priority value to nonzero.
* this note began to play. The WriteMsg part of the iob is then
* linked, as a message, onto your user port. So this routine here
* cannot free the iob until it is certain that YOU have finished
* using it. The iob_Priority field is READ here. If it still
* nonzero, the iob is pushed back onto the message port (on the
* end of the message queue) to be read again. We hold a pointer
* named pushback that lets us keep track of when we see that
* again. If we see it twice, it means we have completed a full
* circle through the queue of messages and have freed everything
* that we can this time. Therefore, we examine it and either
* free it or push it back again, then exit.*/
for(i=0; i<4; i++) /* remove all iob's from ALL ports */
/* (that is, unless we have to push one back) */
{
mp = replyPort[i];
pushback = (struct ExtIOB *)0; /* nothing pushed back so far */
while((iob = (struct ExtIOB *)GetMsg(mp)) != 0)
{
/* Here is what triggers the Identifier message for MayGetNote */
/* First see if messageport in WriteMsg is greater than zero;
* if so, audio device is done, but user hasnt acknowledged
* this message yet (by using MayGetNote).*/
if(iob->ioa_WriteMsg.mn_ReplyPort != 0)
{
/* If we get here, we already know we will push it back */
/* because User has not yet freed it (using MayGetNote) */
PutMsg(mp, iob);
if(iob == pushback) /* If so, we saw it already */
{
break; /* Go out to empty next port */
}
if(pushback == 0)
{
pushback = iob; /* Remember FIRST one pushed back */
}
}
else /* messageport value is zero, can free the iob */
{
#ifdef DEBUG
printf("freeing %ls iob; ID=%ld\n",
iob->ioa_Request.io_Message.mn_Node.ln_Name,
iob->ioa_Request.io_Message.mn_Length);
#endif
FreeIOB(iob,i);
}
}
}
return(0L);
}
LONG
SetCycles(duration, len, per)
LONG len, per; /* period, length of waveform, which octave */
LONG duration;
{
/* Calculate cycles from duration in 1000ths of a second */
/* Multiply all-in-one to maintain max precision possible */
/* (all integer arithmetic.) */
long cycles, ipart;
long dividend, divisor;
if(duration == 0) return(0); /* forever is forever */
ipart = 0;
if(duration > 1000)
{
ipart = duration/1000;
duration = duration - (ipart * 1000);
}
/* Fool it a little so we don't get integer overflow...
* 3.5 million times 1000 is about all we can take in a 32 bit word*/
/* TicksPerSec: either 3579545 (NTSC) or 3546895 (PAL) */
dividend = (TicksPerSec * ipart) +
((long)TicksPerSec * (long)duration)/(long)1000 ;
divisor = len * per;
cycles = (((long)dividend *10/ (long)divisor) + 5) / 10; /* Round */
if(duration != 0 && cycles == 0) cycles = 1;
return(cycles);
}
struct MsgPort *myport;
atool31(v)
int v;
{
LONG i, channel, error;
if (v > 0) goto Fin;
myport = InitAudio();
if(myport == 0)
{
printf("Problem in InitAudio!");
FinishAudio(myport);
}
for(i=0; i<4; i++)
{
channel = GetChannel(-1);
if(channel == -1)
{
printf("cannot get a channel!\n");
FinishAudio(myport);
}
error = StopChannel(channel);
if(error)
{
printf("error in stopping channel = %ld\n",error);
FinishAudio(myport);
}
}
return(0);
Fin:
FinishAudio(myport); /* NEW parameter for FinishAudio */
/* printf("Done!\n");*/
return(0);
} /* end of atool31() */
StartChans()
{
int i, error;
for(i=0; i<4; i++)
{
error = StartChannel(i);
if(error)
{
printf("error starting channel = %ld\n",error);
FinishAudio(myport);
}
}
}