/* Program Scale.c   Play 1 to 4 simultaneous independent scales */

/*		==> 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 & programming background. */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <graphics/gfxbase.h>

/* These constants are used in constructing the user interface. */
#define KGX 390
#define KGY 120
#define TGX 390
#define TGY 148
#define AGX 30
#define AGY 128
#define CIN 20
#define CGY 27
#define ADX 94
#define CTX 104
#define CYXI 150
#define ZX -55
#define GG 60
#define PGX 420
#define PGY 180

/*#include modified "FileWindow.h" -- 9 lines inserted */
/* What file_window() will return: */
#define LOAD    500
#define SAVE    600
#define CANCEL  800
#define QUIT    900
#define PANIC1  1001		/* Cannot open window for FileWindow */
#define PANIC2  1002		/* Not enough memory */

/* The minimum size of the total file name string -- Drawer + File: */
#define TOTAL_LENGTH  130 /*  130 char's incl NULL */

/* THE END -- of modified FileWindow.h */

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
extern int help();
extern USHORT FileWindow();
extern void PlayScale();

	/* Box for 1-char gadget */
/*SHORT c1_box[] = {0,0,  15,0,  15,10,  0,10,  0,0};
struct Border c1_border = {0,0,1,0,JAM1,5,c1_box,NULL};*/

	/* Box for 2-char gadget (also used for 1 char) */
SHORT c2_box[] = {0,0,  23,0,  23,10,  0,10,  0,0};
struct Border c2_border = {0,0,1,0,JAM1,5,c2_box,NULL};

	/* Box for 3-char gadget */
SHORT c3_box[] = {0,0,  39,0,  39,10,  0,10,  0,0};
struct Border c3_border = {0,0,1,0,JAM1,5,c3_box,NULL};

	/* Box for 4-char gadget */
SHORT c4_box[] = {0,0,  79,0,  79,14,  0,14,  0,0};
struct Border c4_border = {0,0,1,0,JAM1,5,c4_box,NULL};

	/* Box for 6-char gadget */
SHORT c6_box[] = {0,0,  59,0,  59,10,  0,10,  0,0};
struct Border c6_border = {0,0,1,0,JAM1,5,c6_box,NULL};

	/* Box for ADR Edit */
SHORT ad_box[] = {-10,-5,  160,-5,  160,32,  -10,32,  -10,-5};
struct Border ad_border = {0,0,1,0,JAM1,5,ad_box,&c2_border};

	/* Grid to enclose channel settings */
SHORT grid[] = {ZX,93, ZX,0,  570,0,  570,93,  ZX,93,  0,93,  0,0,
	50,0,  50,93,  76,93,  76,0,  102,0,  102,93,  144,93,  144,0,
	ZX,0,  ZX,13,  570,13,  570,33,  ZX,33,  ZX,53,  570,53, 570,73, ZX,73 };
struct Border g_border = {GG,14,1,0,JAM1,24,grid,NULL};

struct IntuiText stext_request = {0,2,JAM1,15,5,NULL,NULL,NULL};
struct IntuiText sok_request = {0,2,JAM1,6,3,NULL,"OK",NULL};

	/* Channel 0 gadget */
struct Gadget ch0_gadget = {NULL,GG,CGY,50,20,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Channel 1 gadget */
struct Gadget ch1_gadget = {&ch0_gadget,GG,CGY+20,50,20,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Channel 2 gadget */
struct Gadget ch2_gadget = {&ch1_gadget,GG,CGY+40,50,20,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Channel 3 gadget */
struct Gadget ch3_gadget = {&ch2_gadget,GG,CGY+60,50,20,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Key gadget */
struct IntuiText key_tex = {1,0,JAM1,-34,2,NULL,"Key:",NULL};
struct Gadget key_gadget = {&ch3_gadget, KGX,KGY,24,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c2_border,NULL,&key_tex,NULL,NULL,0,NULL};

	/* Key2 gadget -- #, b, _ (sharp, flat, or neither) */
struct Gadget key2_gadget = {&key_gadget, KGX+30,KGY,24,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c2_border,NULL,NULL,NULL,NULL,0,NULL};

	/* Cycle gadget */
struct IntuiText cycle_tex = {1,0,JAM1,-44,2,NULL,"Cycle",NULL};
struct Gadget cycle_gadget = {&key2_gadget, KGX+CYXI,KGY,24,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c2_border,NULL,&cycle_tex,NULL,NULL,0,NULL};

	/* Clear channel gadget */
struct Gadget clear_gadget = {&cycle_gadget,GG+ZX,27,55,80,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Note gadget */
struct Gadget note_gadget = {&clear_gadget,GG+50,27,26,80,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Octave gadget */
struct Gadget oct_gadget = {&note_gadget,GG+76,27,26,80,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* TimeValue gadget */
struct Gadget time_gadget = {&oct_gadget,GG+102,27,42,80,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		NULL,NULL,NULL,NULL,NULL,0,NULL};

	/* Left AD Edit gadget */
UBYTE lad_char = '<';
struct IntuiText lad_tex1 = {1,0,JAM1,44,-14,NULL,"ADR+ Edit",NULL};
struct IntuiText lad_tex2 = {1,0,JAM1,8,2,NULL,&lad_char,&lad_tex1};
struct Gadget lad_gadget = {&time_gadget, AGX,AGY,24,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&ad_border,NULL,&lad_tex2,NULL,NULL,0,NULL};

	/* Right AD Edit gadget */
UBYTE rad_char = '>';
struct IntuiText rad_tex = {1,0,JAM1,8,2,NULL,&rad_char,NULL};
struct Gadget rad_gadget = {&lad_gadget, AGX+30,AGY,24,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c2_border,NULL,&rad_tex,NULL,NULL,0,NULL};

	/* Ascend/Descend/Rest/Repeat (ADR+) Edit gadget */
struct IntuiText adr_tex = {1,0,JAM1,5,2,NULL,"ADR+",NULL};
struct Gadget adr_gadget = {&rad_gadget, AGX+60,AGY,40,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c3_border,NULL,&adr_tex,NULL,NULL,0,NULL};

	/* Count ADR Edit gadget */
struct IntuiText cad_tex = {1,0,JAM1,8,2,NULL,"1-4",NULL};
struct Gadget cad_gadget = {&adr_gadget, AGX+110,AGY,40,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c3_border,NULL,&cad_tex,NULL,NULL,0,NULL};

	/* Insert AD Edit gadget */
struct IntuiText ins_tex = {1,0,JAM1,5,2,NULL,"Insert",NULL};
struct Gadget ins_gadget = {&cad_gadget, AGX,AGY+15,60,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c6_border,NULL,&ins_tex,NULL,NULL,0,NULL};

	/* Delete AD Edit gadget */
struct IntuiText dad_tex = {1,0,JAM1,5,2,NULL,"Delete",NULL};
struct Gadget dad_gadget = {&ins_gadget, AGX+80,AGY+15,60,11,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c6_border,NULL,&dad_tex,NULL,NULL,0,NULL};

	/* Tempo gadget (proportional) */
struct IntuiText tempo_tex1 = {1,0,JAM1,46,-9,NULL,"Tempo=",NULL};
struct IntuiText tempo_tex2 = {1,0,JAM1,-15,-9,NULL,"Slow",&tempo_tex1};
struct IntuiText tempo_tex3 = {1,0,JAM1,185,-9,NULL,"Fast",&tempo_tex2};
struct Image tempo_image;
struct PropInfo tempo_info = {FREEHORIZ | AUTOKNOB,0,0,
		MAXBODY * 1/400, 0,0,0,0,0,0,0};
struct Gadget tempo_gadget = {&dad_gadget,TGX,TGY,200,12,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, PROPGADGET,
		&tempo_image,NULL,&tempo_tex3,NULL,&tempo_info,0,NULL};

	/* Play gadget */
struct IntuiText play_tex = {3,0,JAM1,4,4,NULL,"PLAY",NULL};
struct Gadget play_gadget = {&tempo_gadget,PGX,PGY,80,15,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c4_border,NULL,&play_tex,NULL,NULL,0,NULL};

	/* Stop gadget */
struct IntuiText stop_tex = {2,3,JAM2,4,4,NULL,"STOP Play",NULL};
struct Gadget stop_gadget = {NULL,PGX,PGY,80,15,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c4_border,NULL,&stop_tex,NULL,NULL,0,NULL};

	/* Quit gadget */
struct IntuiText quit_tex = {3,0,JAM1,20,4,NULL,"QUIT",NULL};
struct Gadget quit_gadget = {&play_gadget,PGX+100,PGY,80,15,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY, BOOLGADGET,
		&c4_border,NULL,&quit_tex,NULL,NULL,0,NULL};

	/* 5th menu item */
struct IntuiText mtext5 = {2,0,JAM1,0,1,NULL,"Quit",NULL};
struct MenuItem mitem5 = {NULL,0,40,150,10,
		ITEMTEXT | ITEMENABLED | HIGHCOMP,0,&mtext5,NULL,0,NULL,MENUNULL};

	/* 4th menu item */
struct IntuiText mtext4 = {2,0,JAM1,0,1,NULL,"About",NULL};
struct MenuItem mitem4 = {&mitem5,0,30,150,10,
		ITEMTEXT | ITEMENABLED | HIGHCOMP,0,&mtext4,NULL,0,NULL,MENUNULL};

	/* 3rd menu item */
struct IntuiText mtext3 = {2,0,JAM1,0,1,NULL,"Save",NULL};
struct MenuItem mitem3 = {&mitem4,0,20,150,10,
		ITEMTEXT | ITEMENABLED | HIGHCOMP,0,&mtext3,NULL,0,NULL,MENUNULL};

	/* 2nd menu item */
struct IntuiText mtext2 = {2,0,JAM1,0,1,NULL,"Load",NULL};
struct MenuItem mitem2 = {&mitem3,0,10,150,10,
		ITEMTEXT | ITEMENABLED | HIGHCOMP,0,&mtext2,NULL,0,NULL,MENUNULL};

	/* 1st menu item */
struct IntuiText mtext1 = {2,0,JAM1,0,1,NULL,"Help",NULL};
struct MenuItem mitem1 = {&mitem2,0,0,150,10,
		ITEMTEXT | ITEMENABLED | HIGHCOMP,0,&mtext1,NULL,0,NULL,MENUNULL};

	/* The menu (only 1) */
struct Menu smenu = {NULL,0,0,50,0,MENUENABLED,"Project",&mitem1};

struct MenuItem *item;

	/* ABOUT Requester */
#define BOXW  80		/* Req gadget box width */
#define BOXH  15		/* Req gadget box height */

		/* Use boxR1 for About Req gadget */
SHORT boxR1[] = {0,0,  BOXW-1,0,  BOXW-1,BOXH-1,  0,BOXH-1,  0,0};

struct Border borderR1 = {0,0,1,0,JAM1,5,boxR1,NULL};
		/* About Reqester -- OK gadget structures */

struct IntuiText ok_text = {1,0,JAM1,25,4,NULL,"OK",NULL};

struct Gadget ok_gadget =
	{	NULL,25,70,BOXW,BOXH,GADGHCOMP,
		GADGIMMEDIATE | RELVERIFY | ENDGADGET,
		BOOLGADGET | REQGADGET,
		&borderR1,NULL,&ok_text,NULL,NULL,0,NULL};

		/* About Requester structures */

SHORT areq_box[] = {0,0,  599,0,  599,99,  0,99,  0,0};

struct Border areq_border = {0,0,1,0,JAM1,5,areq_box,NULL,};

struct IntuiText areq_tex1 = {2,3,JAM2,100,8,NULL,
		"SCALE Program by --",NULL,};
struct IntuiText areq_tex2 = {2,3,JAM2,50,26,NULL,
		"Dick Taylor   Tel (203) 633-0100",&areq_tex1,};
struct IntuiText areq_tex3 = {2,3,JAM2,80,38,NULL,
		"99 Valley View Road",&areq_tex2,};
struct IntuiText areq_tex4 = {2,3,JAM2,50,50,NULL,
		"Glastonbury Connecticut 06033 USA",&areq_tex3,};

struct Requester areq =
	{	NULL,10,20,600,100,0,0,&ok_gadget,&areq_border,&areq_tex4,
		NULL,2,NULL,NULL,NULL,NULL,NULL};

struct IntuiText sp_text = {1,0,JAM2,0,0,NULL,"           ",NULL};

struct Window *w;
struct NewWindow nw = {0,0,640,200,0,1, CLOSEWINDOW | GADGETUP | MENUPICK,
		SMART_REFRESH | WINDOWCLOSE | 
		WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | ACTIVATE, &quit_gadget,NULL,
		"SCALE",NULL,NULL,140,50,640,200,WBENCHSCREEN};

struct IntuiMessage *msg;

char Key,Key2,Note[4], TimeV[4], cyc = 'N',ktext[2],ttext[4],PrevChar;
int  Octave[4], Tempo=500,
	TicksPerSec;	/* Clock ticks/second -- NTSC (American) = 3579545 */
						/* or PAL (European) = 3546895 */
struct			/* Ascend/Descend/Rest 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];
BOOL fin = FALSE, cycle = FALSE;

int c,		/* Current channel = 0, 1, 2, or 3 */
	kAD[4],	/* No. of ad/ct entries, per chan; 0 - 14 */
	yULine = 0,	/* y-offset for drawing 'ADR+' underline */
	iAD = 0;	/* For current chan, position in ad/ct array of zChan; 0-13 */
char ptext[6];
struct IntuiText int_text = {1,0,JAM1,GG+60,32,NULL,ptext,NULL};
struct IntuiText tv_text = {1,0,JAM1,GG+112,32,NULL,"1/",NULL};
struct IntuiText uln_text = {1,0,JAM1,GG+154,40,NULL,"^^",NULL};
struct IntuiText ky_text = {1,0,JAM1,KGX+8,KGY+2,NULL,NULL,NULL};
 struct IntuiText tp_text = {1,0,JAM1,TGX+100,TGY-9,NULL,NULL,NULL};
 char ctex[3];
 struct IntuiText cal_text = {1,0,JAM1,TGX-8,TGY+20,NULL,ctex,NULL};
 SHORT cal[] = {0,0,  0,5,  1,5,  1,0,  2,0,  2,5};
 struct Border calborder = {TGX,TGY+12,1,0,JAM1,6,cal,NULL};


main()
{
 ULONG class;
 USHORT code, menu_number;
 struct Gadget *address;
 int  val, i,j;
 char a;
 BOOL result;

 ctex[0] = '.'; ctex[2] = '\0';
 Key = 'C'; Key2 = '_';
 Note[0] = 'C';		/* Init chan 0 to middle C scale, ascend */
 Octave[0] = 4;
 TimeV[0] = '1';
 for (i = 1; i < 15; ++i)
 {
	zChan[0].ad[i] = ' ';
	zChan[0].ct[i] = 0;
 }
 zChan[0].ad[0] = 'A';
 zChan[0].ct[0] = 1;
 kAD[0] = 1;
 for (i = 1; i < 4; ++i)	/* Init chan's 1-3 to not play */
 {
	Note[i] = ' ';
	Octave[i] = 0;
	TimeV[i] = ' ';
	for (j = 0; j < 15; ++j)
	{
		zChan[i].ad[j] = ' ';
		zChan[i].ct[j] = 0;
	}
	kAD[i] = 0;
 }
 ktext[1] = '\0';
 strcpy (ttext,".50");
 tp_text.IText = ttext;
 ky_text.IText = ktext;

 IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0);
 if (IntuitionBase == NULL)
	{printf ("Module scale error--can't open Intuition, exit.\n");  exit(1); }

 w = (struct Window *) OpenWindow(&nw);
 if (w == NULL)
 {	printf ("Module scale error--can't open Window, exit.\n");
	CloseLibrary(IntuitionBase);
	exit(2);
 }

 InitWindow();		/* Check for NTSC (American) or PAL (European), */
						/* Initialize window display:  draw grid, enter text, */
						/* initialize menu */

 while (!fin)
 {									/* Wait for user input -- menu or gadgets */

	Wait(1 << w->UserPort->mp_SigBit);
	while (msg = (struct IntuiMessage *) GetMsg(w->UserPort))
	{
		class = msg->Class;
		address = msg->IAddress;
		code = msg->Code;
		ReplyMsg(msg);

		switch(class)
		{
			case CLOSEWINDOW:
				fin = TRUE;
				break;
			case MENUPICK:
				menu_number = code;
				while (menu_number != MENUNULL)
				{
					item = (struct MenuItem *) ItemAddress(&smenu,menu_number);
					if (item == &mitem1)				/* Help */
						help();
					else if (item == &mitem2 ||	/* Load */
							   item == &mitem3)		/* Save */
						UseFileWindow();
					else if (item == &mitem4)		/* About */
					{
						result = Request(&areq,w);
						if (result)
						{
							Wait(1 << w->UserPort->mp_SigBit);
							while (msg = (struct IntuiMessage *) GetMsg(w->UserPort))
							ReplyMsg(msg);				/* Clean out messages & finish up */
						}
						else
						{
							printf("Can't activate About requester.\n");
						}
					}
					else if (item == &mitem5)		/* Quit */
						fin = TRUE;
					menu_number = item->NextSelect;
				}
				break;
			case GADGETUP:
				if (address == &quit_gadget)				/* Quit gadget */
					fin = TRUE;
				else if (address == &play_gadget)		/* Play gadget */
				{
					RemoveGadget(w,&play_gadget);
					PrintIText(w->RPort,&sp_text,420,PGY);	/* Erase PLAY */
					PrintIText(w->RPort,&sp_text,420,PGY+8);	/* Erase PLAY */
					AddGadget(w,&stop_gadget,-1);
					RefreshGadgets(&quit_gadget,w,NULL);
					PlayScale();
					RemoveGadget(w,&stop_gadget);
					PrintIText(w->RPort,&sp_text,420,PGY);	/* Erase STOP */
					PrintIText(w->RPort,&sp_text,420,PGY+8);	/* Erase STOP */
					AddGadget(w,&play_gadget,-1);
					RefreshGadgets(&quit_gadget,w,NULL);
				}
				else if (address == &ch0_gadget)		/* Chan 0 gadget */
				{	c = 0;	yULine = 0; iAD = 0;	
					if (Note[0] == ' ') InitChan();	/* Init Chan 0 */
					else ULine(0,0);
				}
				else if (address == &ch1_gadget)		/* Chan 1 gadget */
				{	c = 1;	yULine = CIN; iAD = 0;
					if (Note[c] == ' ') InitChan();	/* Init Chan 1 */
					else ULine(0,yULine);
				}
				else if (address == &ch2_gadget)		/* Chan 2 gadget */
				{	c = 2;	yULine = 2*CIN; iAD = 0;
					if (Note[c] == ' ') InitChan();	/* Init Chan 2 */
					else ULine(0,yULine);
				}
				else if (address == &ch3_gadget)		/* Chan 3 gadget */
				{	c = 3;	yULine = 3*CIN; iAD = 0;
					if (Note[c] == ' ') InitChan();	/* Init Chan 3 */
					else ULine(0,yULine);
				}
				else if (address == &key_gadget)		/* Key gadget */
				{
					if (Key2 != '_')
					{	PrevChar = Key2;
						Key2 = '_';
						ErasWriteA(PrevChar,Key2,30,0);
					}
					PrevChar = Key;
					Key += 1;
					if (Key > 'G') Key = 'A';
					ErasWriteA(PrevChar,Key,0,0);
				}
				else if (address == &key2_gadget)	/* _#b gadget */
				{
					PrevChar = Key2;
					if (Key2 == '_')
					{	Key2 = '#';
						if (Key == 'B' || Key == 'E') Key2 = 'b';
					}
					else if (Key2 == '#')
					{	Key2 = 'b';
						if (Key == 'C' || Key == 'F') Key2 = '_';
					}
					else Key2 = '_';
					ErasWriteA(PrevChar,Key2,30,0);
				}
				else if (address == &cycle_gadget)	/* Cycle gadget */
				{
					PrevChar = cyc;
					if (cycle) {cycle = FALSE; cyc = 'N';}
					else	   {cycle = TRUE;  cyc = 'Y';}
					ErasWriteA(PrevChar,cyc,CYXI,0);
				}
				else if (address == &clear_gadget)	/* Clear gadget */
				{
					ErasWriteB(Note[c],' ',0,yULine);
					ErasWriteB(Octave[c]+'0',' ',25,yULine);
					tv_text.FrontPen = 0;
					PrintIText(w->RPort,&tv_text,0,yULine);
					tv_text.FrontPen = 1;
					ErasWriteB(TimeV[c],' ',69,yULine);
					for (i = 0; i < 14; ++i)
					{
						if (zChan[c].ad[i] != ' ')
						{
							ErasWriteB(zChan[c].ad[i],' ',ADX+30*i,yULine);
							ErasWriteB(zChan[c].ct[i]+'0',' ',CTX+30*i,yULine);
						}
					}
					Note[c] = ' ';
					Octave[c] = 0;
					TimeV[c] = ' ';
					for (i = 0; i < 14; ++i)
					{
						zChan[c].ad[i] = ' ';
						zChan[c].ct[i] = 0;
					}
					iAD = 0;
					kAD[c] = 0;
					ActiveCh();		/* Select non-blank chan to be active */
				}
				else if (address == &note_gadget)	/* Note gadget */
				{
					PrevChar = Note[c];
					Note[c] += 1;
					if (Note[c] > 'G') Note[c] = 'A';
					if (Note[c] < 'A') Note[c] = 'C';
					ErasWriteB(PrevChar,Note[c],0,yULine);
				}
				else if (address == &oct_gadget)	/* Octave gadget */
				{
					PrevChar = Octave[c] + '0';
					Octave[c] += 1;
					if (Octave[c] < 1) Octave[c] = 1;
					if (Octave[c] > 6) Octave[c] = 1;
					ErasWriteB(PrevChar,Octave[c]+'0',25,yULine);
				}
				else if (address == &time_gadget)	/* TimeV gadget */
				{
					PrevChar = TimeV[c];
					TimeV[c] += 1;			/* OK val's are 1, 2, 4 */
					if (TimeV[c] == '3') TimeV[c] = '4';
					if (TimeV[c] > '4') TimeV[c] = '1';
					if (TimeV[c] < '1') TimeV[c] = '1';
					ErasWriteB(PrevChar,TimeV[c],69,yULine);
				}
				else if (address == &lad_gadget)		/* < gadget */
				{
					iAD -= 1;
					if (iAD < 0 || iAD > 13) iAD = 0;
					ULine(30*iAD,yULine);
				}
				else if (address == &rad_gadget)		/* > gadget */
				{
					iAD += 1;
					if (iAD > 13) iAD = 13;
					if (iAD < 0) iAD = 0;
					ULine(30*iAD,yULine);
					if (zChan[c].ad[iAD] == ' ')
					{
						zChan[c].ad[iAD] = 'A';
						ErasWriteB(' ','A',ADX+30*iAD,yULine);
						zChan[c].ct[iAD] = 1;
						ErasWriteB(' ',1+'0',CTX+30*iAD,yULine);
						kAD[c] += 1;
					}
				}
				else if (address == &adr_gadget)		/* ADR+ gadget */
				{
					PrevChar = zChan[c].ad[iAD];
					if (zChan[c].ad[iAD] == 'A') zChan[c].ad[iAD] = 'D';
					else if (zChan[c].ad[iAD] == 'D') zChan[c].ad[iAD] = 'R';
					else if (zChan[c].ad[iAD] == 'R')
					{
						zChan[c].ad[iAD] = '+';
						a = zChan[c].ct[iAD] + '0';
						zChan[c].ct[iAD] = 0;		/* Set count = 0 & write blank*/
						ErasWriteB(a,' ',CTX+30*iAD,yULine);
					}
					else 
					{	zChan[c].ad[iAD] = 'A';
						zChan[c].ct[iAD] = 1;		/* Set count = 1 and write */
						ErasWriteB(' ',1+'0',CTX+30*iAD,yULine);
					}
					ErasWriteB(PrevChar,zChan[c].ad[iAD],ADX+30*iAD,yULine);
				}
				else if (address == &cad_gadget && zChan[c].ad[iAD] != '+')
				{
					PrevChar = zChan[c].ct[iAD] + '0';
					zChan[c].ct[iAD] += 1;
					if (zChan[c].ct[iAD] > 4) zChan[c].ct[iAD] = 1;
					if (zChan[c].ct[iAD] < 1) zChan[c].ct[iAD] = 1;
					ErasWriteB(PrevChar,zChan[c].ct[iAD]+'0',CTX+30*iAD,yULine);
				}
				else if (address == &ins_gadget)	/* Insert AD entry gadget */
				{
					if (kAD[c] < 14)		/* Insert OK if line is not full */
					{						/* Insert at position iAD of ADR+ line */
						for (i = kAD[c]-1; i > iAD-1; --i)
						{
						/* For each AD entry including the insert and following, */
							/* move the entry one position to right (higher). */
					ErasWriteB(zChan[c].ad[i+1],zChan[c].ad[i],ADX+30*(i+1),yULine);
					if (zChan[c].ad[i] != '+')
					ErasWriteB(zChan[c].ct[i+1]+'0',zChan[c].ct[i]+'0',CTX+30*(i+1),yULine);
					else	/* No count for '+', just erase old count */
					ErasWriteB(zChan[c].ct[i+1]+'0',' ',CTX+30*(i+1),yULine);
							zChan[c].ad[i+1] = zChan[c].ad[i];
							zChan[c].ct[i+1] = zChan[c].ct[i];
						}
								/* Erase the insert position and initialize */
						ErasWriteB(zChan[c].ad[iAD],'A',ADX+30*iAD,yULine);
						ErasWriteB(zChan[c].ct[iAD]+'0','1',CTX+30*iAD,yULine);
						zChan[c].ad[iAD] = 'A';
						zChan[c].ct[iAD] = 1;
						kAD[c] += 1;		/* Increm count for this line */
					}
				}
				else if (address == &dad_gadget)	/* Delete AD entry */
				{
					if (iAD > 0 || kAD[c] > 1)
					{
						for (i = iAD; i < kAD[c]-1; ++i)
						{
							/* For each AD entry following the delete, */
							/* move the entry one position to left (lower). */
					ErasWriteB(zChan[c].ad[i],zChan[c].ad[i+1],ADX+30*i,yULine);
					if (zChan[c].ad[i+1] != '+')
					ErasWriteB(zChan[c].ct[i]+'0',zChan[c].ct[i+1]+'0',CTX+30*i,yULine);
					else	/* No count for '+', just erase old count */
					ErasWriteB(zChan[c].ct[i]+'0',' ',CTX+30*i,yULine);
							zChan[c].ad[i] = zChan[c].ad[i+1];
							zChan[c].ct[i] = zChan[c].ct[i+1];
						}
								/* Erase the last AD entry */
						i = kAD[c] - 1;
						ErasWriteB(zChan[c].ad[i],' ',ADX+30*i,yULine);
						ErasWriteB(zChan[c].ct[i]+'0',' ',CTX+30*i,yULine);
						zChan[c].ad[i] = ' ';
						zChan[c].ct[i] = 0;
						if (iAD == i) {iAD -= 1; ULine(30*iAD,yULine);}
						kAD[c] -= 1;
					}
				}
				else if (address == &tempo_gadget)		/* Tempo gadget */
				{
					tp_text.FrontPen = 0;
					PrintIText (w->RPort,&tp_text,0,0);
					Tempo = 500 - (float)tempo_info.HorizPot/MAXPOT * 400;
					/* Tempo:  value xyz in range 500--100 (= .5 sec--.1 sec) */
					val = (Tempo + 5)/ 10;	/* Save xy rounded */
					for (i = 2; i > 0; --i)	/* Convert to char -- .xy */
					{
						ttext[i] = val%10 + '0';
						val = val/10;
					}
					tp_text.FrontPen = 1;
					PrintIText (w->RPort,&tp_text,0,0);
				}
		}	/* close switch(class) */
	}		/* close while(msg...) */
 }			/* close while(!fin) */

 ClearMenuStrip(w);
 CloseWindow(w);
 CloseLibrary(IntuitionBase);
}



InitWindow()		/* Check for NTSC (American) or PAL (European), */
						/* Initialize window display:  draw grid, enter text, */
						/* initialize menu */
{
	int i;

GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0);
if (!GfxBase)
{
	stext_request.IText = 
	"Can't open Graphics Library for NTSC/PAL test -- assume NTSC";
	AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
	goto SetNTSC;
}

if (GfxBase->DisplayFlags & NTSC)
{
SetNTSC:
	TicksPerSec = 3579545;	/* NTSC -- American */
}
else TicksPerSec = 3546895;	/* PAL -- European */

if (GfxBase) CloseLibrary(GfxBase);

SetMenuStrip(w,&smenu);

DrawBorder(w->RPort,&g_border,0,0);		/* Draw grid */
strcpy(ptext,"Clear");
PrintIText(w->RPort,&int_text,-106,-14);	/* Put text on screen */
strcpy(ptext,"Chan");
PrintIText(w->RPort,&int_text,-56,-14);
ptext[1] = '\0';
for (i = 0; i < 4; ++i)
{	ptext[0] = i + '0';
	PrintIText(w->RPort,&int_text,-34,i*CIN);
}
ptext[0] = 'N';
PrintIText(w->RPort,&int_text,0,-14);
ptext[0] = 'O';
PrintIText(w->RPort,&int_text,25,-14);
ptext[0] = 'T';
PrintIText(w->RPort,&int_text,60,-14);
strcpy(ptext,"ADR+");
PrintIText(w->RPort,&int_text,ADX,-14);
ptext[1] = '\0';

 ErasWriteB(' ',Note[0],0,0);			/* Put chan 0 startup val's on screen*/
 ErasWriteB(' ',Octave[0]+'0',25,0);
 ErasWriteB(' ',TimeV[0],69,0);
 ErasWriteB(' ',zChan[0].ad[0],ADX,0);
 ErasWriteB(' ',zChan[0].ct[0]+'0',CTX,0);
 ktext[0] = Key;
 PrintIText(w->RPort,&ky_text,0,0);
 ktext[0] = Key2;
 PrintIText(w->RPort,&ky_text,30,0);
 ktext[0] = cyc;
 PrintIText(w->RPort,&ky_text,CYXI,0);
 PrintIText(w->RPort,&tp_text,0,0);
 for (i = 0; i < 5; ++i)
 {									/* Add Tempo gadget calibration markers */
	DrawBorder(w->RPort,&calborder,i*46+6,0);
	ctex[1] = 5 - i + '0';
	PrintIText(w->RPort,&cal_text,i*46+6,0);
 }
 PrintIText(w->RPort,&tv_text,0,0);
 ULine(0,0); iAD = 0;

}		/* Close function InitWindow */



InitChan()		/* Initialize chan 'c' values & display */
{
int i;

if (Note[0] != ' ') Note[c] = Note[0];
else Note[c] = 'C';
Octave[c] = 1;
TimeV[c] = '1';
zChan[c].ad[0] = 'A';
zChan[c].ct[0] = 1;
ErasWriteB(' ',Note[c],0,CIN*c);
ErasWriteB(' ',Octave[c]+'0',25,CIN*c);
PrintIText(w->RPort,&tv_text,0,CIN*c);
ErasWriteB(' ',TimeV[c],69,CIN*c);
ULine(0,CIN*c);
ErasWriteB(' ','A',ADX,CIN*c);
ErasWriteB(' ','1',CTX,CIN*c);
kAD[c] = 1;
}

ErasWriteA(pchar,nchar,x,y)	/* Erase a char, write a new char */
  char pchar,nchar;
  int x,y;
{
ktext[0] = pchar;
ky_text.FrontPen = 0;
PrintIText(w->RPort,&ky_text,x,y);
ktext[0] = nchar;
ky_text.FrontPen = 1;
PrintIText(w->RPort,&ky_text,x,y);
}

ErasWriteB(pchar,nchar,x,y)	/* Erase a char, write a new char */
  char pchar,nchar;
  int x,y;
{
ptext[0] = pchar;
int_text.FrontPen = 0;
PrintIText(w->RPort,&int_text,x,y);
ptext[0] = nchar;
int_text.FrontPen = 1;
PrintIText(w->RPort,&int_text,x,y);
}


		/* Function ULine -- Underline (^^) for ADR+ display */
		/* Also draws the orange box enclosing the selected chan, if needed */

SHORT sbox[] = {0,0,  617,0,  617,16,  0,16,  0,0};
struct Border sborder = {GG+ZX+4,29,3,0,JAM1,5,sbox,NULL};

ULine(x,y)		/* Display underline (^^):  erase old, write new */
  int x,y;		/* If x < 0, just erase, do not write new one. */
					/* If a new chan is selected, erase the old orange box,*/
					/* draw the new orange box. */
{
static int sx=-1, sy=-1;

 if (sx > -1)
 {				/* Erase previous underline */
	uln_text.FrontPen = 0;
	PrintIText(w->RPort,&uln_text,sx,sy);
	if (y != sy)
	{			/* Erase previous select box */
		sborder.FrontPen = 0;
		DrawBorder(w->RPort,&sborder,0,sy);
	}
 }
 if (x > -1)
 {				/* Write new underline */
	uln_text.FrontPen = 1;
	PrintIText(w->RPort,&uln_text,x,y);
	if (y != sy)
	{			/* Draw new select box */
		sborder.FrontPen = 3;
		DrawBorder(w->RPort,&sborder,0,y);
	}
 }
 sx = x; sy = y;
}



WriteScale(file)		/* Write scale specs to output */
	UBYTE file[];
{
 int i,j,k,m;
 char cbuf[136],tempoC[3];
 FILE *out;

 out = fopen (file,"w");
 if (out == NULL)
 {
	stext_request.IText = "Can't open output file.";
	AutoRequest (w,&stext_request,NULL,&sok_request,NULL,NULL,320,72);
	return;
 }

 cbuf[0] = Key;
 cbuf[1] = Key2;
 cbuf[2] = cyc;
 itoa (Tempo,tempoC);
 cbuf[3] = tempoC[0];
 cbuf[4] = tempoC[1];
 cbuf[5] = tempoC[2];
 cbuf[6] = '\n';

 for (i = 0; i < 4; ++i)
 {
	k = 32*i + 7;
	cbuf[k] = Note[i];
	cbuf[k+1] = Octave[i] + '0';
	cbuf[k+2] = TimeV[i];

	for (j = 0; j < 14; ++j)
	{
		m = k + 3 + 2*j;
		cbuf[m] = zChan[i].ad[j];
		cbuf[m+1] = zChan[i].ct[j] + '0';
	}
	cbuf[k+31] = '\n';
 }
 cbuf[135] = '\0';

 fputs(cbuf,out);
 fclose(out);
}		/* Close WriteScale */

itoa(integ,ascii)		/* Integer to Ascii */
  int integ;			/* 3-digit integer */
  char ascii[];
{
 int i, n;

 n = integ;
 for (i = 2; i > -1; --i)
 {
	if (n > 0) 
	{	ascii[i] = (n % 10) + '0';
		n = n / 10;
	}
	else ascii[i] = ' ';
 }
}

ReadScale(file)		/* Read saved scale, reconstruct & display components */
	UBYTE file[];
{
 int i,j,k,val;
 char cbuf[35];
 FILE *in;

 in = fopen(file,"r");
 if (in == NULL)
 {
	stext_request.IText = "Can't find/open input file.";
	AutoRequest (w,&stext_request,NULL,&sok_request,NULL,NULL,320,72);
	return;
 }

 fgets((char *)cbuf,8,in);

 PrevChar = Key;				/* Key */
 Key = cbuf[0];
 ErasWriteA(PrevChar,Key,0,0);

 PrevChar = Key2;				/* Key2 (# or b) */
 Key2 = cbuf[1];
 ErasWriteA(PrevChar,Key2,30,0);

 PrevChar = cyc;				/* cycle */
 cyc = cbuf[2];
 if (cyc == 'Y') cycle = TRUE; else cycle = FALSE;
 ErasWriteA(PrevChar,cyc,CYXI,0);

 tp_text.FrontPen = 0;				/* Tempo */
 PrintIText(w->RPort,&tp_text,0,0);
 cbuf[0] = cbuf[3]; cbuf[1] = cbuf[4]; cbuf[2] = cbuf[5]; cbuf[3] = '\0';
 Tempo = atoi(cbuf);
 val = (Tempo+5)/10;		/* Round to 2 digits */
 ttext[2] = val%10 + '0';
 ttext[1] = val/10 + '0';
 ttext[0] = '.';
 ttext[3] = '\0';
 tp_text.FrontPen = 1;
 PrintIText(w->RPort,&tp_text,0,0);
		/* Reposition slider knob for current value of Tempo */
 ModifyProp(&tempo_gadget,w,NULL, FREEHORIZ | AUTOKNOB,
				MAXPOT * (500 - Tempo) / 400,		/* Slider position */
				0,MAXBODY * 1/400,0);

 for (i = 0; i < 4; ++i)
 {
	k = i*CIN;
	fgets((char *)cbuf,33,in);		/* Read in a channel */

	PrevChar = Note[i];
	Note[i] = cbuf[0];
	ErasWriteB(PrevChar,Note[i],0,k);

	PrevChar = Octave[i] + '0';
	Octave[i] = cbuf[1] - '0';
	if (cbuf[1] == '0') cbuf[1] = ' ';
	ErasWriteB(PrevChar,cbuf[1],25,k);

	PrevChar = TimeV[i];
	TimeV[i] = cbuf[2];
	ErasWriteB(PrevChar,TimeV[i],69,k);
	if (TimeV[i] == ' ') tv_text.FrontPen = 0;
	else tv_text.FrontPen = 1;
	PrintIText(w->RPort,&tv_text,0,k);	/* This does the "1/" for Time */
	tv_text.FrontPen = 1;

	kAD[i] = 0;
	for (j = 0; j < 14; ++j)
	{
		PrevChar = zChan[i].ad[j];
		zChan[i].ad[j] = cbuf[2*j+3];
		ErasWriteB(PrevChar,zChan[i].ad[j],ADX+30*j,k);
		if (zChan[i].ad[j] != ' ') kAD[i] += 1;

		PrevChar = zChan[i].ct[j] + '0';
		zChan[i].ct[j] = cbuf[2*j+4] - '0';
		if (cbuf[2*j+4] == '0') cbuf[2*j+4] = ' ';
		ErasWriteB(PrevChar,cbuf[2*j+4],CTX+30*j,k);
	}
 }		/* Close for(i=... */
 ActiveCh();		/* Find first non-blank chan for active */
}		/* Close ReadScale() */



UseFileWindow()	/* Invoke function FileWindow to find the file name */
{						/* for reads and writes. */
 UBYTE file[TOTAL_LENGTH];
 USHORT operation;

 operation = FileWindow(file);

 switch (operation)
 {
	case LOAD:
		ReadScale(file);
		break;
	case SAVE:
		WriteScale(file);
		break;
	case CANCEL:
	case QUIT:
	case PANIC1:
		break;
	case PANIC2:
		printf ("System error--can't open window for FileWindow\n");
		break;
	default:
		printf ("FileWindow serious problem, cause unknown.  GET HELP!\n");
 }
}

ActiveCh()		/* Find the 1st non-blank chan, make it active */
{
 int i;
 for (i = 0; i < 4; ++i)
 {
	if (Note[i] != ' ')
	{
		iAD = 0;
		c = i;
		yULine = i*CIN;
		ULine(0,yULine);
		return;
	}
 }
	/* No active channel--erase old marker, no new one */
 ULine(-1,0);
}
