home *** CD-ROM | disk | FTP | other *** search
- /*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);
- }
-