/*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 Thomas E. Janzen */
/*This program Copyright 1990 Thomas E. Janzen All Rights Reserved */
/*This program is for a Commodore (TM) Amiga (TM) 500 playing MIDI */
/*Lattice C 5.05*/
/*out the serial port to a single MIDI channel with MAXVOICE voices */
/*The music is randomized by changes slowly by sinusoidal functions */
/*
**  FACILITY:
**
**	AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
**	compiled with Lattice (TM) C 5.05
**
**  ABSTRACT:
**
**	Algorhythms improvises music over the MIDI serial port.
**	See the manual.
**
**  AUTHOR: Thomas E. Janzen
**
**  CREATION DATE:	26-MAR-1990
**
**  MODIFICATION HISTORY:
**    DATE	NAME	DESCRIPTION
**--
*/

#define	TWOPI	(2 * PI)
#define	DURMAX	2.0
#define PROJECT (0)
#define FORM (1)
#define SCALE (2)
#define CHANNEL (3)
#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 <proto/dos.h>
#include <proto/graphics.h>
#include <proto/exec.h>
#include <proto/mathffp.h>
#include <proto/intuition.h>
#include	"Workbench/startup.h"

#define	STRINGSIZE 80

#include "musictimer.h"
#include "window.h"

extern struct Window *w;

#include "musicserial.h"
#include "Gadgets.h"

struct Parameter Randomize_Parameter(void);

#include "files.h"
#include "DrawForm.h"

extern struct GfxBase *GfxBase;
extern struct IntuitionBase *IntuitionBase;
extern struct DOSBase *DOSBase;
extern struct MathBase *MathBase;

void MakeEvent(struct NoteEvent *, struct Character *, 
	const double CurTime); /* Calculates the next note to send out */

struct Parameter {
	double CenterCycle;
	double CenterPhase;
	double SpreadCycle;
	double SpreadPhase;
};

int fubar=FALSE;

static struct Parameter Pitch_Form 	= {180.0,-PID2,200.0,-PID2};
static struct Parameter Thickness_Form	= {0.0,    0.0,190.0,-PID2};
static struct Parameter Dynamics_Form	= {170.0,-PID2,165  ,-PID2};
static struct Parameter Duration_Form	= {200.0, PID2,180.0, PID2};

struct Character {
	double	PitchSpread;	/*range of pitches*/
	double	PitchCenter;	/* ~ median pitch*/
	double	DynamicSpread;	/*range of dynamic levels*/
	double	DynamicCenter;	/* ~ median of dynamic levels*/
	double	DurSpread;	/*range of durations */
	double	DurCenter;	/* ~ median of durations */
	double	Thickness; 	/*number of voices playing at once*/
};

struct Character *ranges(
	struct Parameter *Pitch, 
	struct Parameter *Dyn, 
	struct Parameter *Dur,  
	struct Parameter *Thickness, 
	const double phase);

int EventPointer = 0;

/*Pitch Range*/
int	range=10;
int	halfrange=5;

#include "scales.h"
#include "menus.h"

int ParseMessage(int class, int code, double *StrTime,
	struct Parameter *PitchForm, struct Parameter *RhythmForm,
	struct Parameter *DynamicsForm, struct Parameter *TextureForm,
	double *Duration,int *tempo, struct NoteEvent *Events);

int	scale[120] = {48,50,53,55,58,60,62,65,67,70,72,74,77};
	/* holds the scale of notes allowed */

static	int	numvoices=MAXVOICE;

static struct timeval timval;

int playing = FALSE; /* playing music */
int started= FALSE;
int done=FALSE;

int quit=FALSE;
int DelayTicks = 2;

double MaxNoteLen = 2.0;
double MinNoteLen = 0.0;
double NoteLenDif = 2.0;

void main(void)
{
	register int tick=0;
	int code, class; /* mouse codes esp. for menus */
	int Action=0;
	register double	CurTime; /*the current time in seconds*/
	double	PieceDuration=600.0; /*piece length in seconds*/
	int tempo;
	static struct NoteEvent Events[MAXVOICE];
	register int temptv_secs;
	register int temptv_micro;
	static struct Character Now;
	int	i;
	static double StartTime=0.0;/*time that the program starts to execute*/

	register double phase;

	MakeWindow();
	Open_MIDI_Port();
	if(fubar == TRUE) goto cleanup2;
	Init_Menu(); /*menu*/

	tempo=50/DelayTicks;

	range=InstallScale(11,scale);
	halfrange=range/2;

	for (i=0;i<MAXVOICE;i++) {
		Events[i].Pitch=halfrange;
		Events[i].Dynamic=0.0;
		Events[i].StartTime=0.0;
		Events[i].Duration=0.0;
		Events[i].Channel=0;
		Events[i].CurPitch=60;
		Events[i].LowPitch=24;
		Events[i].HighPitch=108;
		Events[i].Walking=FALSE;
	}

	/*set the form of the piece*/
	StartTimer();
	GetSysTime(&timval);
	temptv_secs = (int)timval.tv_secs;
	temptv_micro= (int)timval.tv_micro;
	srand(temptv_micro);
	StartTime=(double)temptv_secs+(((double)temptv_micro)*0.000001);
		/*Save Time the program started*/
	CurTime=0.0;

	GetSysTime(&timval);
	StartTime=
	 (double)timval.tv_secs+(((double)timval.tv_micro)*0.000001);
		/*Save Time the program started*/
	phase=TWOPI*CurTime;

	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);

	Now = *ranges(&Pitch_Form,&Dynamics_Form,
		&Duration_Form,&Thickness_Form, phase);
		/*Initialize the ranges (pitch, dynamic, duration)*/

	/*Master Control Loop*/
	while(!(quit)) {
		GetSysTime(&timval);
		CurTime=(double)timval.tv_secs +
			(((double)timval.tv_micro)*0.000001)-StartTime;
		while (playing = (!(done) && started) && !(quit)) {
			GetSysTime(&timval);
			CurTime=(double)timval.tv_secs +
			(((double)timval.tv_micro)*0.000001)-StartTime;
			phase = TWOPI * CurTime;
			Now = *ranges(&Pitch_Form,&Dynamics_Form,
			&Duration_Form,&Thickness_Form, phase);
			for (EventPointer=0;EventPointer < numvoices;
			     EventPointer++) {
				if((CurTime-Events[EventPointer].StartTime)
					> Events[EventPointer].Duration) {
					MakeEvent(&Events[EventPointer],
					&Now, CurTime);
				}
			}
			DrawTime(CurTime,PieceDuration);
			if (Action=CheckMenu(&class, &code)) {
				ParseMessage(class,code,&StartTime,
				&Pitch_Form,&Duration_Form,&Dynamics_Form,
				&Thickness_Form,&PieceDuration,&tempo,
				Events);
			}
			if (DelayTicks) {
				for(tick=0;tick<DelayTicks;tick=tick+2) {
					SendFunction(CLOCKFUNCT);
					Delay(2);/*give music a pulse*/
				}
			}
			if(done=(CurTime > PieceDuration)) {
				StopAllNotes(Events);
				started=FALSE;
			}
		}
		Wait(1 << w->UserPort->mp_SigBit);
		if (Action=CheckMenu(&class, &code)) {
			ParseMessage(class,code,&StartTime,
			&Pitch_Form,&Duration_Form,&Dynamics_Form,
			&Thickness_Form,&PieceDuration,&tempo,Events);
			}
		continue;
	}	
cleanup1:
	CloseMenu();
	StopAllNotes(Events);
	Delay(10);
	RemoveTimer();
cleanup2: /* exit here if the serial port wouldn't open*/
	ShutWindow();
	StopMIDI();
	exit(0);
} /* end main*/

struct Character *ranges(
	struct Parameter *Pitch, 
	struct Parameter *Dyn,
	struct Parameter *Dur,  
	struct Parameter *Thickness, 
	const double phase)
{
	static struct Character NextNow;
	register double realhalfrange;

	realhalfrange=(double)halfrange;

	NextNow.PitchSpread=(sin((phase/Pitch->SpreadCycle)+
		Pitch->SpreadPhase)+1.0)*
		realhalfrange;
		/*Pitch range is a sin function of time*/
	NextNow.PitchCenter=(sin((phase/(Pitch->CenterCycle))+
		(Pitch->CenterPhase))+1.0)*
		realhalfrange; 
		/*Median Pitch is a sin funct of time*/

	if((NextNow.PitchCenter - (NextNow.PitchSpread/2)) < 0) {
		NextNow.PitchCenter = 1.0 + ((NextNow.PitchCenter+
			(NextNow.PitchSpread/2))/2);
	}
	else {
		if((NextNow.PitchCenter+(NextNow.PitchSpread/2)) > 
			(double)range) {
			NextNow.PitchCenter = realhalfrange - 1.0  + 
			((NextNow.PitchCenter - (NextNow.PitchSpread/2.0))
			/2.0);
		}
	}

	NextNow.DynamicSpread=(sin((phase/(Dyn->SpreadCycle))+
		Dyn->SpreadPhase)+1.01)*63;
		/*Range of dynamics is a sin function of time*/
	NextNow.DynamicCenter=((sin((phase/(Dyn->CenterCycle))+
		Dyn->CenterPhase)+1.01)* 50) + 25;
		/*Median dynamic is a sin function of time*/
	NextNow.DurSpread=(sin((phase/(Dur->SpreadCycle))+
		Dur->SpreadPhase)+1.01)*NoteLenDif;
		/* Range of durations is a sin function of time*/
	NextNow.DurCenter=((sin((phase/(Dur->CenterCycle))+
		Dur->CenterPhase)+1.01)*NoteLenDif)+MinNoteLen; 
		/*Median duration is a sin function of time*/
	NextNow.Thickness=((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;
}

struct Parameter Randomize_Parameter(void)
{
	struct Parameter Temp;
	register double reallong_max;
	
	reallong_max=(double)LONG_MAX;
	Temp.CenterCycle=((double)rand()/reallong_max)*(120)+90;
		/*1.5 to 3.5 minutes */
	Temp.CenterPhase=((double)rand()/reallong_max)*TWOPI;
	Temp.SpreadCycle=((double)rand()/reallong_max)*(120)+90;
		/*1.5 to 3.5 minutes */
	Temp.SpreadPhase=((double)rand()/reallong_max)*TWOPI;
	return Temp;
}

void MakeEvent(struct NoteEvent *NewEvent,
	struct Character *Style, const double CurTime) {
	int LowNote;
	int HighNote;
	int OKRandNote;
	
	int	walk;
	register double reallong_max;	
	register double reallong_maxdiv2;
	double	NewDynamic; /*a temporary holder of a new dynamic value*/
	double	NewDuration; /*a temporary holder of a new duration value*/
	int	NewPitchIndex;

	OKRandNote=TRUE;
	reallong_max=(double)LONG_MAX;
	reallong_maxdiv2=reallong_max/2.0;
	PlayNoteOff(NewEvent);
		/*Turn off the previous note*/
		/*for this voice*/
	if (EventPointer<=(int)(Style->Thickness)) {
		
		NewDynamic= ((((double)rand()/reallong_maxdiv2))-1.0)
			*(Style->DynamicSpread)+(Style->DynamicCenter);
			/*get random dynamic*/
		if (NewDynamic > 127){ /*compress dynamic to be valid*/
			NewDynamic=127;
			}
		if (NewDynamic < 0 ) { /*compress dynamic to be valid*/
			NewDynamic=0;
		}
		NewEvent->Dynamic=(int)NewDynamic;/* make dynamic a byte*/

		NewDuration=((((double)rand()/reallong_maxdiv2))-1.0)
			* (Style->DurSpread)+(Style->DurCenter) +
			((Style->DurSpread)/8);
			/*Get random duration*/
		if (NewDuration<0.0) { /*force duration positive*/
			NewDuration = 0;
		}
		NewEvent->Duration=NewDuration; /*Put duration in */
		/* durations list */
		NewEvent->StartTime=CurTime;
		/*Make attacktime for this note */
		/* equal to current time */

		/*PITCH*/
		if(NewEvent->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 {
			NewPitchIndex= 
			((((double)rand()/reallong_maxdiv2))-1.0)
			* (Style->PitchSpread)+(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) {	
			/*fold up if too low */
			NewPitchIndex = 0;
			}
		NewEvent->Pitch=(int)NewPitchIndex; /*pitch in note list*/
		NewEvent->CurPitch=scale[(int)NewPitchIndex];
		/*Play the note*/
		if (playing && OKRandNote)PlayNoteOn(NewEvent);
	}
}

int ParseMessage(int class, int code, double *StrTime,
	struct Parameter *PitchForm, struct Parameter *RhythmForm,
	struct Parameter *DynamicsForm, struct Parameter *TextureForm,
	double *Duration,int *tempo, struct NoteEvent Events[MAXVOICE]
	) {
	int i;
	int tempint;
	int Status; /* file status */
	extern int midi_addr;
	int item=0; int subitem=0;
	static double StopTime, ContTime;
	static char AnswerBuf[96];
	static char FileString[64]={0,0,0,0,0,0,0,0,0};
	char *AnsBuf;
	static char FileNameString[] = "File Name";
	static char DurationString[]="Duration in Seconds";
	static char PaceString[]="Rhythmic Pace";
	static char DynamicString[]="Dynamics";
	static char TextureString[]="Texture";
	static char PitchString[]="Pitch";
	
	static char DynamicMean[]="Dynamic Mean";
	static char DynamicSpread[]="Dynamic Spread";
	static char TextureSpread[]="Texture Spread";
	static char PitchMean[]="Pitch Mean";
	static char PitchSpread[]="Pitch Spread";
	static char RhythmMean[]="Rhythm Mean";
	static char RhythmSpread[]="Rhythm Spread";
	
	static char VoiceString[]="Number of Voices";
	static char BlankString[4]=" ";
	static char SpreadPeriodString[]="Spread Period";
	static char MeanPeriodString[]="Mean Period";
	static char PulseString[]="Pulses per Second";
	static char TransposeString[]="Tranpose";
	static char LoadFileString[]="Load File";
	static char SaveFileString[]="Save File";
	static char NoteLenString[]="Note Length";
	static char MinimumString[]="Minimum";
	static char MaximumString[]="Maximum";
	
	static char About1String[24]=
		"Welcome to AlgoRhythms";
	static struct IntuiText About1Txt=
		{2,1,JAM1,5,4,NULL,About1String,NULL};
	static char About2String[32]=
		"Copyright 1990 Thomas E. Janzen";
	static struct IntuiText About2Txt=
		{2,1,JAM1,5,15,NULL,About2String,&About1Txt};
	static char ThanksString[]="Thanks";
	struct IntuiText ThanksTxt={2,1,JAM1,5,4,NULL,ThanksString,
		NULL};
	
	int Response;
	switch(class) {
	 case NEWSIZE:
	        DrawForm(*Duration,PitchForm,RhythmForm,
			DynamicsForm,TextureForm);
		break;
	 case MENUPICK:
	  if (code != MENUNULL) {
	   item=ITEMNUM(code);
	   subitem=SUBNUM(code);
	   switch(MENUNUM(code)) {
	    case PROJECT:
	     if (item != NOITEM) switch(item) {
	      case 0: /*quit*/
	       quit=TRUE;
	       break;
	      case 1: /*About*/
	       Response=AutoRequest(w,&About2Txt,&ThanksTxt,&ThanksTxt,
	       0L,0L,300L,60L);
	       break;
	      case 2: /*save*/
	       sprintf(AnswerBuf,"%s",FileString);
	       Status=GetStringInput(AnswerBuf,SaveFileString,
	       		FileNameString);
		if (Status == 1) break;
		Status=Save_File(AnswerBuf,Duration,&range,scale,
		&numvoices,tempo,PitchForm,TextureForm,DynamicsForm,
		RhythmForm,Events,MinNoteLen,MaxNoteLen);
		if (Status == 0) {
			__builtin_strcpy(FileString,AnswerBuf);
		}
		else {
			DisplayBeep(NULL);
		}
	       break;
	      case 3: /*load*/
	       sprintf(AnswerBuf,"%s",FileString);
	       Status=GetStringInput(AnswerBuf,LoadFileString,
	       		FileNameString);
		if (Status == 1) break;
		Status=Read_File(AnswerBuf,Duration,
		&range,scale,&numvoices,tempo,PitchForm,
		TextureForm,DynamicsForm,RhythmForm,Events,
		&MinNoteLen,&MaxNoteLen);
		if (Status == 0) {
			if (*tempo == 0) {
				DelayTicks=0;
			}
			else {
				DelayTicks=50/(*tempo);
			}
			halfrange=range/2;
			__builtin_strcpy(FileString,AnswerBuf);
			DrawForm(*Duration,PitchForm,RhythmForm,
			DynamicsForm,TextureForm);
		}
		else {
			DisplayBeep(NULL);
		}
	       break;
	      case 4: /* Continue */
	      	started=TRUE;
	        GetSysTime(&timval);
	        ContTime=(double)timval.tv_secs+
		(((double)timval.tv_micro)*0.000001);
		*StrTime=*StrTime+(ContTime-StopTime);
	      break;
	      case 5: /*stop*/
	       started=FALSE;
	       for (i=0;i<MAXVOICE;i++) {
		(&Events[i])->StartTime=0.0;
		(&Events[i])->Duration=0.0;
	       }
		StopAllNotes(Events);
	       GetSysTime(&timval);
	       StopTime=(double)timval.tv_secs+
		(((double)timval.tv_micro)*0.000001);
	       break;
	      case 6: /*Start to Play*/
	       started=TRUE;
	       done=FALSE;
	       GetSysTime(&timval);
	       *StrTime=(double)timval.tv_secs+
		(((double)timval.tv_micro)*0.000001);
	       for (i=0;i<MAXVOICE;i++) {
		(&Events[i])->StartTime=0.0;
		(&Events[i])->Duration=0.0;
	       }
	       SendFunction(STARTFUNCT);
	       break;
	      } /*switch itemnum*/
	      break;
	      case FORM:
	       if (item != NOITEM) switch(item) {
		case 0: /*note length*/
		 if (subitem != NOSUB) switch(subitem) {
		   case 0: /*minimum*/
		    sprintf(AnswerBuf,"%5.2f",MinNoteLen);
	            AnsBuf=GetGadgetInput(AnswerBuf,
		   	NoteLenString,MinimumString);
		    MinNoteLen=atof(AnsBuf);
		    NoteLenDif=MaxNoteLen-MinNoteLen;
		   break;
		   case 1: /*maximum*/
		    sprintf(AnswerBuf,"%5.2f",MaxNoteLen);
	            AnsBuf=GetGadgetInput(AnswerBuf,
		   	NoteLenString,MaximumString);
		    MaxNoteLen=atof(AnsBuf);
		    NoteLenDif=MaxNoteLen-MinNoteLen;
		   break;
		}
		break;
	        case 1: /*Texture*/
		 if (subitem != NOSUB) switch(subitem) {
		case 0: /* Randomize */
		   *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;
		}
		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;
		}
		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;
	       }
		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;
		}
		break;
	       case 5: /*Duration*/
		sprintf(AnswerBuf,"%2.0f",*Duration);
	        AnsBuf=GetGadgetInput(AnswerBuf,
			BlankString,DurationString);
		*Duration=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;
	      } /*switch itemnum*/
	      break;
	      case SCALE:
	       if (item != NOITEM) switch(item) {
	        case 0: /*transpose*/
		 sprintf(AnswerBuf,"0");
		 AnsBuf=GetGadgetInput(AnswerBuf,
		 	BlankString,TransposeString);
		 TransposeScale(atoi(AnsBuf),scale,range);
		break;
                default:
	         range=InstallScale(12-item,scale);
	         halfrange=range/2;
	       } /*switch itemnum*/
	      break;
	      case CHANNEL:
		GetChannelStuff(&Events[item],item);
		break;
	      } /*switch menunum*/
	     } /*while menunull*/
	     break;
	     case CLOSEWINDOW:
		quit=TRUE;
	     break;
	    } /*switch class*/
	return (0);
} /*end function*/

