home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d7xx
/
d787
/
scale.lha
/
Scale
/
Source.lha
/
scale2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-12
|
14KB
|
498 lines
/* Program Scale2.c -- calls to "atool31" and "PlayNote" in atool31.c */
/* ==> RECOMMENDED <== */
/* Set tab interval to 3 for listing of this code */
/* Programmer: Dick Taylor November 1992 */
/* 99 Valley View Rd, Glastonbury CT 06033 USA */
/* Please refer to file scale.doc for usage and background. */
#include <exec/types.h>
#include <intuition/intuition.h>
#include <exec/ports.h>
#include <devices/timer.h>
#define SECONDS tr_time.tv_secs
#define MICROSECONDS tr_time.tv_micro
extern int PlayNote(), atool31(), StartChans();
extern char Key, Key2, Note[4], TimeV[4], ttext[];
extern int Octave[4], Tempo;
extern struct /* Ascend/Descend structure */
{
char ad[15]; /* For each of 4 channels, we have */
int ct[15]; /* 15 pairs of A/D/R and count, 14 are usable */
} zChan[4];
extern BOOL fin, cycle;
extern struct Gadget stop_gadget;
extern struct PropInfo tempo_info;
extern struct Gadget tempo_gadget;
extern struct IntuiText tp_text;
extern struct IntuiText stext_request;
extern struct IntuiText sok_request;
extern struct Window *w;
int Increm[4], /* Increment, either 0 or -12; per channel */
ADRsig[4], /* Ascend(1)/Descend(-1)/Rest(0) signal; per chan */
iADR[4], /* Position in ADR array; per chan */
zCt[4], /* ADR Count for current ADR step; per chan */
ProtoScale[4][8], /* Prototype Scale notes, per channel */
RelTime[4], /* Relative Time, either 1, 2, or 4; per chan */
Vol[4], /* Volume; per chan. 50 = play 0 = rest */
Duration[4], /* Note Duration; per chan. 500 = .5 sec */
iScale = 1, /* In playing scales after the first octave -- */
/* 1 = play 7 notes 0 = play 8 notes, all chan's */
jScale; /* Same usage as iScale */
char aCh; /* Temp -- char: A, D, R, + */
BOOL Desc[4], /* Descending flag T or F; per chan */
SaveDesc[4], /* Save Descending flag T or F; per chan */
Play[4], /* Play flag T or F; per chan */
PFlag[4], /* Play Flag: T for A or D, F for R; per chan */
Repeat=FALSE, /* Repeat Flag: T if any chan is repeating (+) */
ChRep[4], /* Chan Repeat Flag: T if chan repeating (+); per chan */
rtn; /* Flag -- Default F; T if user signals to stop Play */
/* This program uses the TimerDevice to time each 1/1 octave, so that */
/* all notes will be synchronized at the start of each 1/1 octave. */
int secs, /* Total Wait time for 1/1 octave, in microseconds */
/* Specify time in seconds (xx.yyy) to Timer Device in 2 parts -- */
I_secs, /* Whole-number seconds -- xx (integer)*/
M_secs, /* Fractional seconds -- yyy in microseconds */
TimingFF = 10000; /* Timing Fudge Factor -- empirically */
/* determined value (= .01 sec), subtracted from secs, */
/* to smooth transition from one octave to the next. */
struct
{
int Pitch[32]; /* Structure/array for saving one set of notes */
int Volume[32]; /* before sending them to PlayNote. */
} Chan[4]; /* One set = either 1, 2, or 4 octaves of notes, */
/* depending on Relative Time value -- RelTime[] */
int kPV[4]; /* Position counters -- Pitch/Vol, per Chan */
PlayScale()
{
int c, /* Channel -- 0, 1, 2, 3 */
i,j,m,n; /* Local variables */
BOOL First = TRUE;
struct Message *Tmsg; /* TimerDevice message */
ULONG wakebits,IDCMPsig,TIMERsig;
BOOL ErrOpenTimer = TRUE,err;
int val;
struct timerequest *tr; /* Request Block Pointer */
struct MsgPort *tp; /* Port Pointer */
struct MsgPort *CreatePort();
tp = (struct MsgPort *) CreatePort(0,0); /* Create Port for TimerDevice */
if (tp == 0)
{
stext_request.IText =
"Module scale2: Can't create port for TimerDevice; exit.";
AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
goto StopPlay;
}
tr = NULL; /* Create TimerDevice request block */
tr = (struct timerequest *) CreateExtIO(tp,sizeof(struct timerequest));
if (tr == 0)
{
stext_request.IText =
"Module scale2: Can't create request block for TimerDevice; exit.";
AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
goto StopPlay;
}
ErrOpenTimer = OpenDevice(TIMERNAME,UNIT_VBLANK,tr,0); /* Open Timer Device */
if (ErrOpenTimer)
{
stext_request.IText =
"Module scale2: Can't open TimerDevice; exit.";
AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
goto StopPlay;
}
atool31(0); /* Initialize the AudioTools system */
StartChans(); /* Start channels -- will play when receive notes */
IDCMPsig = 1<<w->UserPort->mp_SigBit; /* IDCMP signal bit */
TIMERsig = 1<<tp->mp_SigBit; /* TimerDevice signal bit */
rtn = FALSE;
err = Prelims(); /* Convert some input items to AudioTools numeric form: */
/* Key Note; per chan -- First Note, prototype scale notes */
if (err) goto StopPlay;
/* This major loop plays the scales. */
do /* do-while loop -- repeats when cycle = TRUE */
{
Setup(); /* For each chan, initialize variables & flags */
/* This loop plays one time through all scale spec's */
/* It continues to loop as long as any non-+ chan's are active */
while (zCt[0]+zCt[1]+zCt[2]+zCt[3] > 0)
{
GetNotes(); /* Calc 1 set of notes for all chan's; save in array. */
/* 1 set of notes = Either 1, 2, or 4 octaves per chan, */
/* depending on value of RelTime[] 1, 2, or 4 */
if (First)
First = FALSE;
else
{
WaitAgain: /* Wait for IDCMP signal or Timer signal */
wakebits = Wait(IDCMPsig | TIMERsig);
if (wakebits & IDCMPsig)
{
DoIDCMP(); /* Process IDCMP message(s) */
}
if (wakebits & TIMERsig)
while (Tmsg = (struct Message *) GetMsg(tp))
/* Receive Timer message, do nothing */ ;
else goto WaitAgain;
if (rtn == TRUE)
goto StopPlay;
}
/* Start the Timer Device */
tr->tr_node.io_Command = TR_ADDREQUEST;
tr->SECONDS = I_secs;
tr->MICROSECONDS = M_secs;
SendIO(tr); /* Send Timer command to system */
PlayIt(); /* Send notes from array to PlayNote in AudioTools */
jScale = iScale;
} /* Close while loop (zCt[0]+zCt[1]+...) */
} /* Close do-while loop */
while (cycle);
Delay(secs/20000 + 1); /* Wait for last octave to finish */
/* Delay for length of last Timer interval */
while (Tmsg = (struct Message *) GetMsg(tp))
/* Receive last Timer message, do nothing */ ;
StopPlay:
atool31(1); /* Close down the sound system */
if (!ErrOpenTimer) CloseDevice(tr); /* Close TimerDevice */
if (tr) DeleteExtIO(tr,sizeof(struct timerequest)); /* Delete IO Block */
if (tp) DeletePort(tp); /* Delete Port */
} /* Close function PlayScale() */
Prelims() /* Convert some input items to AudioTools numeric form: */
/* Key Note; per chan -- First Note, prototype scale notes */
{
int
i,j,m,n, /* Local variables */
FNInt, /* First Note Interval, from key note */
KeyNote, /* Key Note -- starting note (0-6) for current key */
KeyNoteInt; /* Key Note Interval -- interval to find starting note */
static ScaleInt[8] = {0,2,2,1,2,2,2,1}; /* Intervals major scale */
char tempKey;
/* Find the Key note */
KeyNote = (Key - 'A' + 5) % 7; /* Conv Key CDEFGAB to digit 0-6 */
/* (0 = C, 1 = D, ... , 6 = B) */
KeyNoteInt = 0;
for (j = 0; j <= KeyNote; ++j)
KeyNoteInt += ScaleInt[j]; /* Convert Key code to Key note interval */
if (Key2 == '#') KeyNoteInt += 1;
else if (Key2 == 'b') KeyNoteInt -= 1;
iScale = 1;
for (i = 0; i < 4; ++i)
{
ChRep[i] = FALSE;
RelTime[i] = TimeV[i] - '0'; /* Conv char 1/2/4 to integer */
if (zChan[i].ad[0] != ' ' && (RelTime[i] == 2 || RelTime[i] == 4)) iScale = 0;
Duration[i] = Tempo / RelTime[i]; /* Get note duration */
FNInt = 0; /* Find interval from Key note to first note */
tempKey = Key; n = 0;
if (Note[i] != ' ')
while (tempKey != Note[i]) /* Step up key to reach Note[] */
{
n += 1;
FNInt += ScaleInt[n]; /* FNInt = note interval from Key note */
tempKey += 1; /* Increm temp key */
if (tempKey > 'G') tempKey = 'A';
if (n > 7)
{
stext_request.IText =
"Module scale2: program error finding 1st note. Exit";
AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
return(TRUE); /* Exit signal */
}
}
ProtoScale[i][0] = 12*(Octave[i]-1) + KeyNoteInt + FNInt; /*Get 1st note of scale */
m = 1 + n;
for (j = 1; j < 8; ++j)
{ ProtoScale[i][j] = ProtoScale[i][j-1] + ScaleInt[m]; /* Rest of scale notes */
m += 1;
if (m > 7) m = 1;
}
}
return(FALSE); /* OK return */
} /* Close function Prelims() */
Setup() /* For each chan, initialize variables & flags */
{ /* needed to play the scales */
int i;
char a;
jScale = 0;
for (i = 0; i < 4; ++i)
{
iADR[i] = 0; /* position in A/D series */
zCt[i] = 0;
aCh = zChan[i].ad[0];
if (aCh == ' ') Play[i] = FALSE; /* Chan doesn't play */
else
{
Play[i] = TRUE;
PFlag[i] = TRUE;
if (aCh == 'D') /* Descend */
{ Desc[i] = TRUE;
Increm[i] = -12;
ADRsig[i] = -1;
}
else if (aCh == 'A') /* Ascend */
{ Desc[i] = FALSE;
Increm[i] = 0;
ADRsig[i] = 1;
}
else /* Rest */
{ ADRsig[i] = 0;
PFlag[i] = FALSE;
}
zCt[i] = zChan[i].ct[0]; /* Count for first A/D */
SaveDesc[i] = Desc[i];
}
}
} /* Close function Setup() */
GetNotes() /* Calc 1 set of notes for all chan's; save in array. */
/* 1 set of notes = Either 1, 2, or 4 octaves per chan, */
/* depending on value of RelTime[] 1, 2, or 4 */
{
int c,i,j,m,n,p; /* local variables */
secs = (Tempo * (8-jScale)) * 1000; /* Total Wait time in microsecs */
secs -= TimingFF; /* Empirical fudge factor */
/* Divide Wait time into 2 parts -- */
I_secs = secs / 1000000; /* Whole number (integer) seconds */
M_secs = secs % 1000000; /* Fractional part in microsecs */
for (i = 0; i < 4; ++i)
{
kPV[i] = 0; /* Reset channel note position counters */
if (ADRsig[i] == 0) Vol[i] = 0; /* Set volume for each channel */
else Vol[i] = 50; /* 0 = rest, 50 = play */
}
for (j = jScale; j < 8; ++j) /* Play 8 or 7 scale notes */
/* jScale value: 0 = 8 note scale, 1 = 7 notes */
{
for (c = 0; c < 4; ++c) /* Four channels */
{
if (Play[c])
{
n = j * RelTime[c];
for (i = 0; i < RelTime[c]; ++i)
{
m = (n + i) % 8;
if (Desc[c]) m = 7 - m;
p = ProtoScale[c][m] + Increm[c];
Chan[c].Pitch[kPV[c]] = p; /* Save pitch in struct/array */
Chan[c].Volume[kPV[c]] = Vol[c]; /* Save volume */
kPV[c] += 1;
}
}
if (Play[c])
{
if (RelTime[c] == 2 && j == 3) CheckAD(c);
if (RelTime[c] == 4 && j != 7 && j%2 == 1) CheckAD(c);
}
} /* Close channel loop c */
} /* Close scale loop j */
for (i = 0; i < 4; ++i)
kPV[i] = 0; /* Reset channel note position counters */
} /* Close function GetNotes() */
DoIDCMP() /* Process IDCMP message(s) */
{
struct IntuiMessage *Imsg; /* IDCMP message */
ULONG class;
struct Gadget *address;
int i, val;
while (Imsg = (struct IntuiMessage *) GetMsg(w->UserPort))
{
class = Imsg->Class;
address = Imsg->IAddress;
ReplyMsg(Imsg);
switch (class)
{
case CLOSEWINDOW:
fin = TRUE;
rtn = TRUE;
break;
case GADGETUP:
if (address == &stop_gadget)
{
rtn =TRUE;
}
else if (address == &tempo_gadget)
{
tp_text.FrontPen = 0;
PrintIText (w->RPort,&tp_text,0,0); /* Erase old Tempo val */
Tempo = 500 - (float)tempo_info.HorizPot/MAXPOT * 400;
val = (Tempo + 5)/ 10;
for (i = 2; i > 0; --i)
{
ttext[i] = val%10 + '0';
val = val/10;
}
tp_text.FrontPen = 1;
PrintIText (w->RPort,&tp_text,0,0); /* Write new Tempo val */
for (i = 0; i < 4; ++i)
Duration[i] = Tempo/RelTime[i]; /* New Durations */
secs = (Tempo * (8-jScale)) * 1000;
secs -= TimingFF; /* Empirical fudge factor */
I_secs = secs / 1000000; /* New Timer values */
M_secs = secs % 1000000;
}
break;
default:
break;
} /* Close switch */
} /* Close while */
} /* Close function DoIDCMP() */
PlayIt() /* Send notes from array to PlayNote in AudioTools */
{
int c,i,j,m;
/* Send array notes to PlayNote */
for (j = jScale; j < 8; ++j)
{
for (c = 0; c < 4; ++c)
{
if (Play[c])
{
for (i = 0; i < RelTime[c]; ++i)
{
PlayNote(c,Chan[c].Pitch[kPV[c]],
Chan[c].Volume[kPV[c]],Duration[c]);
kPV[c] += 1;
}
}
}
}
for (i = 0; i < 4; ++i)
if (Play[i]) CheckAD(i);
/* If using Repeat (+), check when to stop playing */
if (Repeat)
{ m = 0;
for (i=0; i<4; ++i) /* Are any non-repeats */
if (!ChRep[i]) m += zCt[i]; /* still playing? */
if (m == 0)
for (i=0; i<4; ++i)
zCt[i] = 0; /* Set all zCt's = 0 stops play */
}
} /* Close function PlayIt() */
CheckAD(i) /* Process the ADR+ entry to prep for next octave */
int i; /* i is the channel */
{
if (zCt[i] > 1)
{
zCt[i] -= 1; /* Decrement ADR+ step count */
Increm[i] += ADRsig[i] * 12; /* Bump increment either up or down */
/* by 12, for next octave --either higher or lower. */
/* No change for R = rest */
}
else
{
iADR[i] += 1; /* Advance ADR+ entry counter */
aCh = zChan[i].ad[iADR[i]]; /* Retrieve next ADR+ code */
if (aCh == ' ')
{
Play[i] = FALSE;
zCt[i] = 0; /* All done this chan */
}
else
{ /* Take next AD entry */
if (aCh == '+') /* '+' = repeat ADR's */
{ Repeat = TRUE; /* Restart at beginning of ADR+ series*/
ChRep[i] = TRUE;
iADR[i] = 0;
PFlag[i] = FALSE;
aCh = zChan[i].ad[0];
}
if (aCh == 'R')
{
ADRsig[i] = 0; /* 'R' = rest */
Vol[i] = 0; /* Set Volume to 0 */
}
else
{ if (aCh == 'D') /* Check asc/desc */
{
Desc[i] = TRUE; /* Descending */
ADRsig[i] = -1;
}
else
{
Desc[i] = FALSE; /* Ascending */
ADRsig[i] = 1;
}
Play[i] = TRUE;
Vol[i] = 50; /* Set Volume to 50 */
if (! PFlag[i])
{
PFlag[i] = TRUE;
if (aCh == 'A') Increm[i] = 0;
else Increm[i] = -12;
}
else if (Desc[i] == SaveDesc[i])
Increm[i] += ADRsig[i]*12;
SaveDesc[i] = Desc[i];
}
zCt[i] = zChan[i].ct[iADR[i]]; /* Get count this AD */
}
}
} /* Close function CheckAD() */