home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_progs
/
sound
/
algorhyt.lha
/
source
/
AlgoRhythms.c
next >
Wrap
C/C++ Source or Header
|
1992-02-21
|
44KB
|
1,169 lines
/*AlgoRhythms.c*/
/*Thomas E. Janzen 4 September 1989; 2-11-90 */
/*18 September 1989 26 nov 89 11 December 1989 16 December 1989*/
/*Music played with this program
/* Copyright © 1990,1991,1992 Thomas E. Janzen */
/*out the serial port to a single MIDI channel with MAXVOICE voices */
/*The music is randomized by changes slowly by sinusoidal functions */
/* Copyright (c) © 1990, 1991, 1992 by Thomas E. Janzen
All Rights Reserved
THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
CHANGES FOR FREE DISTRIBUTION. NO TITLE TO AND OWNERSHIP OF THE
SOFTWARE IS HEREBY TRANSFERRED. THOMAS E. JANZEN ASSUMES NO
RESPONSBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
Thomas E. Janzen
58A School St. Apt. 2-L
Hudson, MA 01749
(508)562-1295
*/
/*
** FACILITY:
**
** AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
** compiled with SAS/C V5.10b
**
** ABSTRACT:
**
** AlgoRhythms.c improvises music.
**
** AUTHORS: Thomas E. Janzen
**
** CREATION DATE: 26-MAR-1990
**
** MODIFICATION HISTORY:
** DATE NAME DESCRIPTION
1.01 12 Aug 90 T Janzen Shortened Duration string to fit in new gadgets
1.02 8 Jan 91 Misc. improvements of code; added Events.StopTime
1.03 11 feb 91 misc. and fixed bug of cut off notes on short scales
1.04 23 Feb 91 put back autorequesters using new compile command no crash
1.05 24 Jul 91 created a custom screen; added quartal and quintal scales;
1.06 24 SEP 91 use algorhythms.col to define colors, update.
1.07 3 NOV 91 Use struct timeval for all times until it must be double
1.08 10 NOV 91 TEJ integers in CHARACTER struct.290 notes/sec @ 16V,64 @ 1
2.0 26 DEC 91 TEJ Record MIDI and save MIDI standard file
Use req.library by Colin Fox and Bruce Dawson
Use 20 voices.
12 JAN 92 Integers for MaxNoteLen and MinNoteLen
**--
*/
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <intuition/intuition.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/devices.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <proto/all.h>
#include <Workbench/startup.h>
#include "MusicTimer.h"
#include "Window.h"
#include "MusicSerial.h"
#include "Gadgets.h"
#include "Files.h"
#include "DrawForm.h"
#include "Scales.h"
#include "Menus.h"
#include "Record.h"
#include <libraries/reqbase.h>
#include <proto/req.h>
#define TWOPI (2 * PI)
#define PROJECT (0)
#define FORM (1)
#define SCALE (2)
#define CHANNEL (3)
/*
** This type of structure holds the instantaneous values for the range and
** median pitch, dynamic, duration, and thickness.
*/
typedef struct {
struct timeval StartTime,
Duration,
StopTime;
int Pitch,
Dynamic,
Channel,
CurPitch,
LowPitch, /* CHANGE THIS IN ALGORHYTHMS.C AND MUSICSERIAL.C*/
HighPitch,
Walking,
Playing;
} NOTEEVENT;
typedef struct {
double CenterCycle,
CenterPhase,
SpreadCycle,
SpreadPhase;
} PARAMETER;
typedef struct {
int PitchSpread, /* range of pitches */
PitchCenter, /* ~ median pitch */
DynamicSpread, /* range of dynamic levels */
DynamicCenter, /* ~ median of dynamic levels */
DurSpread, /* range of durations */
DurCenter, /* ~ median of durations */
Thickness; /* number of voices playing at once */
} CHARACTER;
/*
** The NOTEEVENT type struct holds information for a given note or MIDI
** pitch event.
*/
/*
** If the serial channel fails, fubar is set and the program exits.
*/
#ifdef MEASURE
extern unsigned int NotesTotalMeasure;
#endif
extern int fubar = FALSE,
scale[120] = {48,50,53,55,58,60,62,65,67,70,72,74,77};
/* holds the scale of notes allowed */
static int playing = FALSE, /* playing music */
started = FALSE; /* Has started playing music */
int done = FALSE, /* Is done playing because it timed out */
quit = FALSE; /* Was told to quit out of the program */
static int DelayTicks = 2, /* number of fiftieths of a second to wait */
EventIndex = 0; /* Index into Events */
int range = 10; /* Pitch Range, really length of scale array */
static int halfrange = 5; /* half of range */
static unsigned int MaxNoteLenms = 2000, /* Max duration of note in ms */
MinNoteLenms = 0, /* Min duration of note in ms */
DifNoteLenms = 2000; /* MaxNoteLenms - MinNoteLenms */
static PARAMETER Pitch_Form = {180.0,-PID2,200.0,-PID2},
/* The periods and phases of mean and range for Pitch */
Thickness_Form = {0.0, 0.0,190.0,-PID2},
/* The periods and phases of mean and range for Texture */
Dynamics_Form = {170.0,-PID2,165 ,-PID2},
/* The periods and phases of mean and range for Dynamics */
Duration_Form = {200.0, PID2,180.0, PID2};
/* The periods and phases of mean and range for Duration */
static int numvoices = MAXVOICE; /* Total possible numbers of voices */
static struct timeval Sys_Time,
Range_Time = {0, 0};
static struct ReqFileRequester file_req;
struct Process *process;
APTR old_error_window;
extern struct ReqBase *ReqBase;
static double Cvt_Time_Secs (struct timeval *Time);
static CHARACTER *ranges ( PARAMETER *Pitch,
PARAMETER *Dyn,
PARAMETER *Dur,
PARAMETER *Thickness,
const struct timeval *Music_Time, CHARACTER *NextNow);
static PARAMETER Randomize_Parameter (void);
static void MakeEvent (NOTEEVENT *, CHARACTER *,
struct timeval *Music_Time);
/* Calculates the next note to send out */
static int ParseMessage (int class, int code, struct timeval *StrTime,
PARAMETER *PitchForm,
PARAMETER *RhythmForm,
PARAMETER *DynamicsForm,
PARAMETER *TextureForm,
struct timeval *Duration, int *tempo,
NOTEEVENT *Events);
#ifdef CLI
int main (int argc, char *argv[]) /* CLI version */
#else
void main (void) /* I/O is all Intuition windows/menus/dialogue boxes */
#endif
{
#ifdef CLI
char FileString[128];
#else
static int code,
class, /* mouse codes esp. for menus */
signals,
signal;
auto struct IntuiMessage *message;
#endif
auto struct timeval Tenth_Second = {0, 1000000};
static CHARACTER CurrentStyle;
register int tick = 0; /* Index for counting 1/25's of a second*/
int tempo, /* ticks per second */
i; /* index */
auto struct timeval Music_Time,
Start_Time, /*the current time in seconds*/
PieceDuration = {600, 0}; /*piece length*/
static CHARACTER Now; /* Current instantaneous
mean and range for the 4 parameters*/
/* Time in seconds * 2 * pi */
static NOTEEVENT Events[MAXVOICE];
/* array of the currently playing notes */
#ifndef CLI
MakeWindow (); /* Open the window for AlgoRhythms */
#endif
Open_MIDI_Port (); /* Open the serial port for MIDI use */
if (fubar == TRUE)
{
/* Get out if serial port failed to open */
goto cleanup2; /* skip out on failure */
}
#ifndef CLI
Init_Menu (); /* Set up the menu */
tempo = 50 / DelayTicks; /* Tempo is pulses per second */
range = InstallScale (11, scale); /* Install a musical scale */
halfrange = range / 2; /* recalculate halfrange */
process = (struct Process *)FindTask (NULL);
old_error_window = process->pr_WindowPtr;
process->pr_WindowPtr = (APTR)w;
#endif
for (i = 0; i < MAXVOICE; i++) /* Initialize the note Events */
{
Events[i].Pitch = halfrange;
Events[i].Dynamic = 0.0;
Events[i].StartTime.tv_micro = Events[i].StartTime.tv_secs = 0;
Events[i].StopTime.tv_micro = Events[i].StopTime.tv_secs = 0;
Events[i].Duration.tv_micro = Events[i].Duration.tv_secs = 0;
Events[i].Channel = 0;
Events[i].CurPitch = 60;
Events[i].LowPitch = 24;
Events[i].HighPitch = 108;
Events[i].Walking = FALSE;
Events[i].Playing = FALSE;
}
/*
** set the form of the piece
*/
#ifdef CLI
if (argc != 2)
{
puts ("usage: AlgoRhythmsCLI {Form_file}\n");
goto cleanup2;
exit (1);
}
strcpy (FileString, argv[1]);
i = Read_File (FileString, &PieceDuration,
&range, scale, &numvoices, &tempo, &Pitch_Form,
&Thickness_Form, &Dynamics_Form, &Duration_Form, Events,
&MinNoteLenms, &MaxNoteLenms);
if (i == 0)
{
if (tempo == 0)
{
DelayTicks = 0;
}
else
{
DelayTicks = 50 / (tempo);
}
halfrange = range / 2;
}
#endif
StartTimer (); /* Start timer device */
GetSysTime (&Sys_Time); /* Get the time */
srand (Sys_Time.tv_micro); /* use microseconds time to seed random */
/*
** Save Time the program started
*/
Start_Time = Music_Time;
Music_Time.tv_micro = Music_Time.tv_secs = 0; /* Set time to zero to start */
/*Save Time the program started*/
#ifndef CLI
/* Initialize the Form parameters as random */
Pitch_Form = Randomize_Parameter ();
Duration_Form = Randomize_Parameter ();
Dynamics_Form = Randomize_Parameter ();
Thickness_Form = Randomize_Parameter ();
DrawForm (&PieceDuration, &Pitch_Form, &Duration_Form,
&Dynamics_Form, &Thickness_Form); /* Draw the Form graph */
#endif
Now = *ranges (&Pitch_Form, &Dynamics_Form,
&Duration_Form,
&Thickness_Form, &Music_Time, &CurrentStyle);
/* Initialize the ranges (pitch, dynamic, duration) */
#ifdef CLI
started = TRUE;
done = FALSE;
SendFunction (STARTFUNCT);
#endif
/*
** Master Control Loop
** Program stays in here until it quits
*/
while ( !(quit))
{
/* until you quit */
GetSysTime (&Sys_Time);
Music_Time = Sys_Time;
SubTime (&Music_Time, &Start_Time); /* Music_Time = Now - Start */
/* as long as you are playing */
while (playing = (!(done) && started) && !(quit))
{
GetSysTime (&Sys_Time); /* get the time and convert
to double normalize to
the starting time of the
piece of music*/
Music_Time = Sys_Time;
SubTime (&Music_Time, &Start_Time);
/*
** Get the instantaneous mean & range of
** pitch, dynamics, duration, and texture
*/
if (CmpTime (&Music_Time, &Range_Time) == -1)
{
Now = *ranges (&Pitch_Form, &Dynamics_Form, &Duration_Form,
&Thickness_Form, &Music_Time, &CurrentStyle);
Range_Time = Music_Time;
AddTime (&Range_Time, &Tenth_Second);
}
/* loop through the voices in order*/
for (EventIndex = 0; EventIndex < numvoices; EventIndex++)
{
/*
** if the previous note in this voice
** is over, then make a new note
** Is first parm > than second parm ?
*/
if (CmpTime (&Music_Time, &Events[EventIndex].StopTime) == -1)
{
MakeEvent (&Events[EventIndex], &Now, &Music_Time);
}
}
/* Indicate the time on the form graph */
#ifndef CLI
DrawTime (&Music_Time, &PieceDuration);
/* If there is an action, then find out what */
while (message = (struct IntuiMessage *) GetMsg (w->UserPort))
{
class = message->Class;
code = message->Code;
ReplyMsg ((struct Message *)message);
if ((class == MENUPICK) && (code == MENUNULL))
{
continue;
}
ParseMessage (class, code, &Start_Time,
&Pitch_Form, &Duration_Form, &Dynamics_Form,
&Thickness_Form, &PieceDuration, &tempo, Events);
}
#endif
/*
** If DelayTicks is not zero then pause to
** simulate a regular beat
*/
if (DelayTicks)
{
for (tick = 0; tick < DelayTicks; tick = tick + 2)
{
/* Send the MIDI timing clock */
SendFunction (CLOCKFUNCT);
Delay (2); /* wait 2/50's of a sec*/
}
}
if (done = (CmpTime (&Music_Time, &PieceDuration) == -1))
{
#ifdef CLI
quit = done;
#endif
/* if the piece is done, stop playing */
StopAllNotes (Events);
/* re-initialize started */
started = FALSE;
}
}
/*
** if the piece is playing, then wait, free up AmigaDOS,
** until a mouse event hits this window
*/
#ifndef CLI
signals = 1L << w->UserPort->mp_SigBit;
signal = Wait (signals);
if (!(signal & signals))
{
continue;
}
/* When the event hits, find out what */
while (message = (struct IntuiMessage *) GetMsg (w->UserPort))
{
class = message->Class;
code = message->Code;
ReplyMsg ((struct Message *)message);
if ((class == MENUPICK) && (code == MENUNULL))
{
continue;
}
ParseMessage (class, code, &Start_Time,
&Pitch_Form, &Duration_Form, &Dynamics_Form,
&Thickness_Form, &PieceDuration, &tempo, Events);
}
#endif
continue; /* continue in Master Control Loop until quit */
}
cleanup1: /* normal dump out of the program */
#ifndef CLI
process->pr_WindowPtr = old_error_window;
CloseMenu (); /* shut down menu */
#endif
StopAllNotes (Events); /* turn off all the notes */
Delay (10); /* wait 1/5 seconds */
RemoveTimer (); /* release the timer device */
cleanup2: /* exit here if the serial port wouldn't open*/
#ifndef CLI
ShutWindow (); /* remove the window */
#endif
StopMIDI (); /* close the serial device */
Erase_Recording ();
exit (0); /* exit program */
} /* end main*/
static CHARACTER *ranges (PARAMETER *Pitch,
PARAMETER *Dyn,
PARAMETER *Dur,
PARAMETER *Thickness,
const struct timeval *CurrentTime,
CHARACTER *NextNow)
/* ranges calculates the instantaneous mean and range of
** Pitch, Dynamics, Duration, and Thickness.
** Inputs:
** Pitch : Form parameter
** Dyn : Form parameter
** Dur : Form parameter
** Thickness : Form parameter
** phase : time * 2 * pi
** *NextNow : pointer in which result will be stored
*/
{
double realrange, /* floating-point version of range */
realhalfrange, /* floating-point version of halfrange */
phase;
realrange = (double) range; /* calculate range */
realhalfrange = (double) halfrange;/* calculate half of range */
phase = TWOPI * ((double)(CurrentTime->tv_secs) +
((double)(CurrentTime->tv_micro) * 0.000001));
NextNow->PitchSpread = (int)((sin ((phase / Pitch->SpreadCycle)
+ Pitch->SpreadPhase) + 1.0) * realhalfrange);
/*Pitch range is a sin function of time*/
NextNow->PitchCenter = (int)((sin ((phase / (Pitch->CenterCycle))
+ (Pitch->CenterPhase)) + 1.0) * realhalfrange);
/* Median Pitch is a sin funct of time */
/*
** The following rigamaroll prevents pitch range from
** overlapping into non-usable notes (less than 0 and higher
** than the top scale note). It forces the range to be
** from top or bottom of the scale through the mean and
** an equal distance to the other side
*/
if ((NextNow->PitchCenter - (NextNow->PitchSpread / 2)) < 0)
{
NextNow->PitchCenter = 1 + ((NextNow->PitchCenter
+ (NextNow->PitchSpread / 2)) / 2);
}
else
{
if ((NextNow->PitchCenter + (NextNow->PitchSpread / 2))
> (double)range)
{
NextNow->PitchCenter = realhalfrange - 1
+ ((NextNow->PitchCenter - (NextNow->PitchSpread / 2)) / 2);
}
}
NextNow->DynamicSpread = (int)((sin ((phase / (Dyn->SpreadCycle))
+ Dyn->SpreadPhase) + 1.01) * 63.0);
/*Range of dynamics is a sin function of time*/
NextNow->DynamicCenter = (int)(
(sin (phase / Dyn->CenterCycle + Dyn->CenterPhase) + 1.01) * 50.0
+ 25.0);
/*Median dynamic is a sin function of time*/
NextNow->DurSpread = (int)(((
sin (phase / Dur->SpreadCycle + Dur->SpreadPhase)
+ 1.01) / 2.0)
* (double)DifNoteLenms);
/* Range of durations is a sin function of time*/
NextNow->DurCenter = (int)
(
(
sin (phase / Dur->CenterCycle + Dur->CenterPhase) + 1.01
) / 2.0 * (double)DifNoteLenms
) + MinNoteLenms;
/*Median duration is a sin function of time*/
NextNow->Thickness = (int)(((sin ((phase / (Thickness->SpreadCycle))
+ Thickness->SpreadPhase) + 1.01) *
(double)numvoices / 2.0) - 1.0);
/*the number of voices playing is a sin function of time*/
return NextNow;
}
static PARAMETER Randomize_Parameter(void)
{
/* Returns a randomized parameter of any type */
PARAMETER Temp;
register double reallong_max;
reallong_max = (double)LONG_MAX;
Temp.CenterCycle = ((double)rand () / reallong_max) * 120.0 + 90.0;
/*1.5 to 3.5 minutes */
Temp.CenterPhase = ((double)rand () / reallong_max) * TWOPI;
Temp.SpreadCycle = ((double)rand () / reallong_max) * 120.0 + 90.0;
/*1.5 to 3.5 minutes */
Temp.SpreadPhase = ((double)rand () / reallong_max) * TWOPI;
return Temp;
}
static void MakeEvent (NOTEEVENT *NewEvent, CHARACTER *Style,
struct timeval *Music_Time)
/* MakeEvent finds the next note, its duration, and its dynamic, and then*/
/* plays it */
{
int LowNote, /* Boolean flag that the note is as the */
/* bottom of the scale */
HighNote, /* Boolean flag = note is at top of scale */
OKRandNote, /* Boolean flag, not low and not high */
walk, /* a direction for the note to walk */
NewPitchIndex; /* index to the new pitch */
register double reallong_max, /* maximum integer in real form*/
reallong_maxdiv2; /* max int/2 */
int NewDynamic; /* a temporary holder of a new dynamic value*/
unsigned int NewDuration;/* a temporary holder of a new duration value*/
auto struct timeval NewDuration_time;
OKRandNote = TRUE; /* initialize OKRandNote */
reallong_max = (double)LONG_MAX; /* Init */
reallong_maxdiv2 = reallong_max / 2.0; /* Init */
if (NewEvent->Playing)
{
NewEvent->Dynamic = 0;
NewEvent->StopTime = *Music_Time;
PlayNoteOn (NewEvent); /* Turn off the old note */
NewEvent->Playing = FALSE;
if (Recording)
{
Record_Note_Event (NewEvent);
}
}
if (EventIndex > (int)Style->Thickness)
{
return;
}
if (Style->DynamicSpread)
{
NewDynamic = (rand () % Style->DynamicSpread)
- (Style->DynamicSpread / 2)
+ Style->DynamicCenter;
}
else
{
NewDynamic = Style->DynamicCenter;
}
if (NewDynamic > 127)
{ /*compress dynamic to be valid*/
NewDynamic = 127;
}
if (NewDynamic < 0 )
{ /*compress dynamic to be valid*/
NewDynamic = 0;
}
NewEvent->Dynamic = NewDynamic; /* make dynamic a byte*/
if (Style->DurSpread)
{
NewDuration = (rand () % Style->DurSpread
- Style->DurSpread / 2
+ Style->DurCenter);
}
else
{
NewDuration = Style->DurCenter;
}
NewDuration = (NewDuration < MinNoteLenms) ? MinNoteLenms : NewDuration;
NewDuration = (NewDuration > MaxNoteLenms) ? MaxNoteLenms : NewDuration;
NewDuration_time.tv_secs = NewDuration / 1000;
NewDuration_time.tv_micro = (NewDuration * 1000) % 1000000;
/*
** Put duration in
** durations list
*/
NewEvent->Duration = NewDuration_time;
NewEvent->StartTime = *Music_Time;
NewEvent->StopTime = NewDuration_time;
AddTime (&NewEvent->StopTime, Music_Time);
if (NewEvent->Walking)
{
/* If the voice is walking */
HighNote = NewEvent->CurPitch >= NewEvent->HighPitch;
LowNote = NewEvent->CurPitch <= NewEvent->LowPitch;
walk = (rand () % 3) - 1;
if (LowNote)
{
walk = 1;
}
if (HighNote)
{
walk = -1;
}
NewPitchIndex = NewEvent->Pitch + walk;
}
else
{
if (Style->PitchSpread)
{
NewPitchIndex = rand () % Style->PitchSpread
- Style->PitchSpread / 2
+ Style->PitchCenter;
}
else
{
NewPitchIndex = Style->PitchCenter;
}
HighNote = (scale[NewPitchIndex] >= NewEvent->HighPitch);
LowNote = (scale[NewPitchIndex] <= NewEvent->LowPitch);
OKRandNote = !HighNote && !LowNote;
}
if (NewPitchIndex >= range)
{
NewPitchIndex = range - 1; /*fold under if too hi*/
}
if (NewPitchIndex < 0)
{
NewPitchIndex = 0; /*fold up if too low */
}
NewEvent->Pitch = (int) NewPitchIndex; /*pitch in note list*/
NewEvent->CurPitch = scale[(int)NewPitchIndex];
/*Play the note*/
if (playing && OKRandNote)
{
PlayNoteOn (NewEvent);
NewEvent->Playing = TRUE;
if (Recording)
{
Record_Note_Event (NewEvent);
}
}
return;
}
#ifndef CLI
static int ParseMessage (int class, int code, struct timeval *StrTime,
PARAMETER *PitchForm, PARAMETER *RhythmForm,
PARAMETER *DynamicsForm, PARAMETER *TextureForm,
struct timeval *Duration, int *tempo,
NOTEEVENT Events[MAXVOICE])
/*
** Parse Message interprets the codes from the menu handler in Menu.c
** Inputs:
** class : class of mouse event
** code : code of mouse event
** PitchForm, RhythmForm, DynamicsForm, TextureForm : Form Parameters
** Duration : length of piece in seconds
** tempo : pulses per second
** Events : Array of current note events
*/
{
int i,
tempint,
Status, /* file status */
item = 0, /* menu item */
subitem = 0, /* menu subitem */
Response;
#ifdef MEASURE
static unsigned char MeasureString[32];
static struct IntuiText MeasureTxt = {2, 1, JAM2, 15, 10, &font_choice,
MeasureString, NULL};
#endif
static NOTEEVENT Reset_Event = {{0,0},{0,0},{0,0},0,0,-1,0,0,0,0,0};
static struct timeval StopTime; /* The Time that the music
** stopped */
static char AnswerBuf[96], /* string buffer for user to type in */
MIDI_path[96] = "\0",
MIDI_dir[96] = "\0",
MIDI_file[64] = "\0",
form_path[64] = "\0",
form_dir[96] = "\0",
form_file[64] = "\0",
Title_String[128] = "\0";
char *AnsBuf; /* user answer buffer */
/* Strings for gadgets */
static char FileNameString[] = "File Name",
DurationString[] = "Duration(seconds)",
PaceString[] = "Rhythmic Pace",
DynamicString[] = "Dynamics",
TextureString[] = "Texture",
PitchString[] = "Pitch",
DynamicMean[] = "Dynamic Mean",
DynamicSpread[] = "Dynamic Spread",
TextureSpread[] = "Texture Spread",
PitchMean[] = "Pitch Mean",
PitchSpread[] = "Pitch Spread",
RhythmMean[] = "Rhythm Mean",
RhythmSpread[] = "Rhythm Spread",
VoiceString[] = "Number of Voices",
BlankString[4] = " ",
SpreadPeriodString[] = "Spread Period",
MeanPeriodString[] = "Mean Period",
PulseString[] = "Pulses per Second",
TransposeString[] = "Transpose",
load_file_banner[] = "Load File",
save_form_banner[] = "Save File",
MIDI_form_banner[] = "MIDI file",
NoteLenmsString[] = "Note Length",
MinimumString[] = "Minimum",
MaximumString[] = "Maximum",
About1String[32] = "Welcome to AlgoRhythms 2.0",
About2String[40] = "Copyright 1992 Thomas E. Janzen",
ThanksString[] = "Thanks";
static struct IntuiText About1Txt =
{2, 1, JAM2, 5, 4, &font_choice, About1String, NULL},
About2Txt =
{2, 1, JAM2, 5, 15, NULL, About2String, &About1Txt},
ThanksTxt = {2, 1, JAM1, 5, 4, NULL, ThanksString, NULL};
file_req.dirnamescolor = 2;
file_req.devicenamescolor = 2;
switch (class)
{
case NEWSIZE: /* Window has been re-sized, so re-draw the graph */
DrawForm (Duration, PitchForm, RhythmForm, DynamicsForm,
TextureForm);
break;
case MENUPICK: /* a menu selection was made */
if (code != MENUNULL)
{
item = ITEMNUM(code);
subitem = SUBNUM(code);
switch (MENUNUM(code))
{
case PROJECT: /* Project menu strip was selected */
if (item != NOITEM)
switch (item)
{
case 0: /* quit program */
quit = TRUE;
break;
case 1: /* About copyright notice */
Response = AutoRequest (w, &About2Txt, &ThanksTxt,
&ThanksTxt, 0L, 0L, 300L, 60L);
break;
case 2: /* Save MIDI file */
if (ReqBase != NULL)
{
file_req.PathName = MIDI_path;
file_req.Dir = MIDI_dir;
file_req.File = MIDI_file;
if (!FileRequester (&file_req))
{
break;
}
}
else
{
Status = GetStringInput (MIDI_path,
MIDI_form_banner,
FileNameString);
if (Status == 1) break;
}
Write_MIDI (MIDI_path);
break;
case 3: /* Erase */
Erase_Recording ();
break;
case 4: /* Record */
Record_Init ();
Recording = !Recording;
break;
case 5: /* Save a form file */
if (ReqBase == NULL)
{
Status = GetStringInput (form_path,
save_form_banner,
FileNameString);
if (Status)
{
DisplayBeep (NULL);
break;
}
}
else
{
file_req.PathName = form_path;
file_req.Dir = form_dir;
file_req.File = form_file;
if (!FileRequester (&file_req))
{
break;
}
}
Status = Save_File (form_path, Duration,
&range, scale, &numvoices,
tempo, PitchForm, TextureForm,
DynamicsForm, RhythmForm,
Events, MinNoteLenms,
MaxNoteLenms);
if (Status)
{
DisplayBeep (NULL);
break;
}
strcpy (Title_String, form_path);
SetWindowTitles (w, Title_String, (void *) -1L);
break;
case 6: /* load a form file */
if (ReqBase == NULL)
{
Status = GetStringInput (form_path,
load_file_banner,
FileNameString);
if (Status)
{
DisplayBeep(NULL);
break;
}
}
else
{
file_req.PathName = form_path;
file_req.Dir = form_dir;
file_req.File = form_file;
if (!FileRequester (&file_req))
{
break;
}
}
Status = Read_File (form_path, Duration,
&range, scale, &numvoices, tempo, PitchForm,
TextureForm, DynamicsForm, RhythmForm, Events,
&MinNoteLenms, &MaxNoteLenms);
if (!Status)
{
if (*tempo == 0) DelayTicks = 0;
else
{
DelayTicks = 50 / (*tempo);
}
halfrange = range / 2;
DrawForm(Duration, PitchForm, RhythmForm,
DynamicsForm, TextureForm);
strcpy (Title_String, form_path);
SetWindowTitles (w, Title_String, (void *) -1L);
Range_Time.tv_secs
= Range_Time.tv_micro
= 0;
}
else
{
DisplayBeep(NULL);
}
break;
case 7: /* Continue after stopping */
started = TRUE;
PlayNoteOn (&Reset_Event);
GetSysTime (&Sys_Time);
StrTime->tv_secs = StrTime->tv_secs
+ (int)(Sys_Time.tv_secs - StopTime.tv_secs);
break;
case 8: /* stop the music but don't exit */
started = FALSE;
for (i = 0; i < MAXVOICE; i++)
{
Events[i].StartTime.tv_secs
= Events[i].StartTime.tv_micro
= 0;
Events[i].Duration.tv_secs
= Events[i].Duration.tv_micro
= 0;
Events[i].StopTime.tv_secs
= Events[i].StopTime.tv_micro
= 0;
}
StopAllNotes (Events);
GetSysTime (&StopTime);
#ifdef MEASURE
sprintf (MeasureString, "%d", NotesTotalMeasure);
PrintIText (rp, &MeasureTxt, 1, 1);
NotesTotalMeasure = 0;
#endif
break;
case 9: /* Start to Play music */
started = TRUE;
done = FALSE;
GetSysTime (StrTime);
PlayNoteOn (&Reset_Event);
for (i = 0; i < MAXVOICE; i++)
{
Events[i].StartTime.tv_secs
= Events[i].StartTime.tv_micro
= 0;
Events[i].Duration.tv_secs
= Events[i].Duration.tv_micro
= 0;
Events[i].StopTime.tv_secs
= Events[i].StopTime.tv_micro
= 0;
}
SendFunction (STARTFUNCT);
Range_Time.tv_secs
= Range_Time.tv_micro
= 0;
break;
default:
break;
} /*switch itemnum*/
break;
case FORM: /* Form menu strip was selected */
if (item != NOITEM)
switch (item)
{
case 0: /* note length */
if (subitem != NOSUB)
switch (subitem)
{
case 0: /* minimum note length */
sprintf (AnswerBuf, "%5.2f",
(double)MinNoteLenms / 1000.0);
AnsBuf = GetGadgetInput (AnswerBuf,
NoteLenmsString, MinimumString);
MinNoteLenms
= (int)(atof (AnsBuf) * 1000.0);
DifNoteLenms
= MaxNoteLenms - MinNoteLenms;
break;
case 1: /* maximum note length */
sprintf (AnswerBuf, "%5.2f",
(double)MaxNoteLenms / 1000.0);
AnsBuf = GetGadgetInput (AnswerBuf,
NoteLenmsString, MaximumString);
MaxNoteLenms
= (int)(atof (AnsBuf) * 1000.0);
DifNoteLenms
= MaxNoteLenms - MinNoteLenms;
break;
default:
break;
}
break;
case 1: /* Texture form set up */
if (subitem != NOSUB)
switch(subitem)
{
case 0: /* Randomize texture */
*TextureForm =
Randomize_Parameter ();
break;
case 1: /* Spread Period */
sprintf (AnswerBuf, "%2.0f",
TextureForm->SpreadCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
TextureString, SpreadPeriodString);
TextureForm->SpreadCycle = atof (AnsBuf);
break;
case 2: /* Spread Phase */
TextureForm->SpreadPhase =
GetPhaseInput( TextureForm->SpreadPhase,
TextureSpread);
break;
default:
break;
}
break;
case 2: /* Dynamic */
if (subitem != NOSUB)
switch (subitem)
{
case 0: /* Randomize */
*DynamicsForm =
Randomize_Parameter ();
break;
case 1: /* Spread Phase*/
DynamicsForm->SpreadPhase =
GetPhaseInput (
DynamicsForm->SpreadPhase,
DynamicSpread);
break;
case 2: /* Spread Period */
sprintf (AnswerBuf,"%2.0f",
DynamicsForm->SpreadCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
DynamicString,
SpreadPeriodString);
DynamicsForm->SpreadCycle = atof (AnsBuf);
break;
case 3: /* mean Phase */
DynamicsForm->CenterPhase =
GetPhaseInput (
DynamicsForm->CenterPhase,
DynamicMean);
break;
case 4: /* Mean Period */
sprintf (AnswerBuf, "%2.0f",
DynamicsForm->CenterCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
DynamicString,
MeanPeriodString);
DynamicsForm->CenterCycle = atof (AnsBuf);
break;
default:
break;
}
break;
case 3: /* Rhythm */
if (subitem != NOSUB)
switch (subitem)
{
case 0: /* Randomize */
*RhythmForm =
Randomize_Parameter ();
break;
case 1: /* Spread Phase */
RhythmForm->SpreadPhase =
GetPhaseInput (RhythmForm->SpreadPhase,
RhythmSpread);
break;
case 2: /* Spread Period */
sprintf (AnswerBuf, "%2.0f",
RhythmForm->SpreadCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
PaceString, SpreadPeriodString);
RhythmForm->SpreadCycle = atof(AnsBuf);
break;
case 3: /* mean Phase */
RhythmForm->CenterPhase =
GetPhaseInput (
RhythmForm->CenterPhase,
RhythmMean);
break;
case 4: /* Mean Period */
sprintf (AnswerBuf, "%2.0f",
RhythmForm->CenterCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
PaceString,
MeanPeriodString);
RhythmForm->CenterCycle =
atof (AnsBuf);
break;
default:
break;
}
break;
case 4: /* Pitch */
if (subitem != NOSUB)
switch (subitem)
{
case 0: /* Randomize */
*PitchForm =
Randomize_Parameter ();
break;
case 1: /* Spread Phase */
PitchForm->SpreadPhase =
GetPhaseInput (PitchForm->SpreadPhase,
PitchSpread);
break;
case 2: /* Spread Period */
sprintf (AnswerBuf, "%2.0f",
PitchForm->SpreadCycle);
AnsBuf = GetGadgetInput (AnswerBuf,
PitchString, SpreadPeriodString);
PitchForm->SpreadCycle = atof (AnsBuf);
break;
case 3: /* mean Phase */
PitchForm->CenterPhase = GetPhaseInput (
PitchForm->CenterPhase, PitchMean);
break;
case 4: /* Mean Period */
sprintf (AnswerBuf, "%2.0f",
PitchForm->CenterCycle);
AnsBuf = GetGadgetInput(AnswerBuf,
PitchString, MeanPeriodString);
PitchForm->CenterCycle = atof (AnsBuf);
break;
default:
break;
}
break;
case 5: /* Duration */
sprintf (AnswerBuf, "%2.0f",
Cvt_Time_Secs (Duration));
AnsBuf = GetGadgetInput (AnswerBuf, BlankString,
DurationString);
Duration->tv_secs = (int) atof (AnsBuf);
break;
case 6: /* pulse */
sprintf (AnswerBuf, "%d", *tempo);
AnsBuf = GetGadgetInput (AnswerBuf,
BlankString, PulseString);
*tempo = abs (atoi (AnsBuf));
if (*tempo == 0) DelayTicks = 0;
else
DelayTicks = 50 / (*tempo);
break;
case 7: /* ReDraw */
DrawForm (Duration, PitchForm, RhythmForm,
DynamicsForm, TextureForm);
break;
case 8: /* numvoices */
sprintf (AnswerBuf, "%d", numvoices);
AnsBuf = GetGadgetInput (AnswerBuf,
BlankString, VoiceString);
tempint = atoi (AnsBuf);
if ((tempint <= MAXVOICE)
&& (tempint > 0))
numvoices = tempint;
else
DisplayBeep (NULL);
break;
default:
break;
} /* switch itemnum */
break;
case SCALE:
if (item != NOITEM)
switch(item)
{
case 0: /* transpose the scale */
sprintf (AnswerBuf, "0");
AnsBuf = GetGadgetInput (AnswerBuf, BlankString,
TransposeString);
TransposeScale (atoi (AnsBuf), scale, range);
break;
default:
range = InstallScale (item, scale);
halfrange = range / 2;
} /* switch itemnum */
break;
case CHANNEL:
GetChannelStuff (&Events[item], item);
break;
} /* switch menunum */
} /* while not menunull */
break;
case CLOSEWINDOW:
quit = TRUE;
break;
default:
break;
} /* switch class */
return (0);
} /* end function */
#endif
static double Cvt_Time_Secs (struct timeval *Time)
{
return (double)Time->tv_secs + ((double)Time->tv_micro / 1000000.0);
}