#
/*
 *		M O Z A R T . C
 *
 * This is an implementation of the "Melody Dicer," attributed to Mozart
 * that generates an "infinite" number of short minuettes.  The note
 * tables have not been included as I have not been able to find a
 * public-domain source.  If you are interested, you should try to find
 * a copy of the "Melody Dicer" game, available at music stores everywhere.
 *
 * As implemented, this program generated music tables that were used to
 * drive a home-made synthesizer board attached to an RT-11 system.
 * Converting to other synthesizers should not be too great a chore.
 *
 * The documentation file, mozart.rno, describes a similar algorithm by
 * Kirnberger.  Unfortunately, we haven't gotten around to typing in
 * the notes yet.
 *
 * [And you thought programmers weren't sadistic.]
 *
 */

#define	NMEASURE	200	/* Measures				*/
#define	NVOICES		1800	/* Voice information (n_voice * m_meas)	*/
#define	NNOTES		4000	/* Notes in compiled music		*/
#define	NPNOTES		256	/* Play notes in each voice		*/
#define	NPBYTES		768	/* Bytes in each voice (NPNOTES * 3)	*/
#define NPVOICE		6	/* Voices for each measure		*/
#define	MULTIPLIER	12	/* Multiply duration to get play dur.	*/

/*
 * Special "notes"
 */

#define	REST	192		/* "Rest" note 				*/
#define	GAP	193		/* Descriptor for voice header		*/
#define	XPOSE	194		/*	""				*/
#define	ATACK	195		/*	""				*/
#define	DECAY	196		/*	""				*/
#define	VOL	197		/*	""				*/
#define	SUSTN	198		/*	""				*/
#define	RELSE	199		/*	""				*/
#define	STOP	203		/* End of other voice tables		*/
#define	END	205		/* End of first voice table		*/

/*
 * RT11 definitions
 */
#define	JSW		   044	/* Job status word			*/
#define	SPECMODE	010100	/* Bit 12, console special mode		*/

struct {
	int	mem_word;
}

/*
 * Structure definitions
 */

struct measure {
	struct voice	*m_voice[2];	/* Points to NPVOICE voices	*/
	int		m_vcount[2];	/* Number of voices for measure	*/
};

struct voice {
	struct note	*v_note;	/* Notes for this voice		*/
	int		v_count;	/* Number of notes for voice	*/
};

struct note {
	char	n_note;
	char	n_dur;
};

/*
 * Tables for compilation
 */

char *special[] {
"REST ", "GAP  ", "XPOSE", "ATACK", "DECAY",
"VOL  ", "SUSTN", "RELSE", "?200 ", "?201 ",
"?202 ", "STOP ", "?204 ", "END  ",
};

/*
 * ttab translates notes (A-G) to numbers.
 */

int ttab[] {
	 0,  1,	/* A	A#	*/
	 2, -1,	/* B		*/
	 3,  4,	/* C	C#	*/
	 5,  6,	/* D	D#	*/
	 7, -1,	/* E		*/
	 8,  9,	/* F	F#	*/
	10, 11,	/* G	G#	*/
};

/*
 * dtab translates durations to length codes
 */

struct dtab {
	int	d_val;
	int	d_dur;
} dtab[] {
	{ 64, 1 },
	{ 32, 3 },
	{ 16, 6 },
	{  8,12 },
	{  4,24 },
	{  2,48 },
	{  1,96 },
	{  0, 0 },
};

#define	RESTDUR	(3 * 12)	/* A missing voice = 3 1/8 note rest	*/
				/* 1/8 notes have 12 duration in dtab[]	*/
int	restword = (RESTDUR)*MULTIPLIER;
char	*restbyte = &restword;	/* Pointer to restword as two bytes	*/

char	*ntext[] {
  "AN", "AS", "BN", "CN", "CS", "DN", "DS", "EN", "FN", "FS", "GN", "GS"
};

/*
 * Mtab has measure numbers (from the text).  It is stored as printed.
 * I.e, first all numbers for dice 2, then for dice 3, etc.
 */

int	mtab[11][16] {
 96, 22,141, 41,105,122, 11, 30,   70,121, 26,  9,112, 49,109, 14,
 32,  6,128, 63,146, 46,134, 81,  117, 39,126, 56,174, 18,116, 83,
 69, 95,158, 13,153, 55,110, 24,   66,139, 15,132, 73, 58,145, 79,
 40, 17,113, 85,161,  2,159,100,   90,176,  7, 34, 67,160, 52,170,
148, 74,163, 45, 80, 97, 36,107,   25,143, 64,125, 76,136,  1, 93,
104,157, 27,167,154, 68,118, 91,  138, 71,150, 29,101,162, 23,151,
152, 60,171, 53, 99,133, 21,127,   16,155, 57,175, 43,168, 89,172,
119, 84,114, 50,140, 86,169, 94,  120, 88, 48,166, 51,115, 72,111,
 98,142, 42,156, 75,129, 62,123,   65, 77, 19, 82,137, 38,149,  8,
  3, 87,165, 61,135, 47,147, 33,  102,  4, 31,164,144, 59,173, 78,
 54,130, 10,103, 28, 37,106,  5,   35, 20,108, 92, 12,124, 44,131
};

struct voice	voice[NVOICES];
struct voice	*p_voice = voice;	/* Free pointer into voice	*/
struct measure	measure[NMEASURE];	/* Voices for this measure	*/
struct note	note[NNOTES];
struct note	*p_note = note;		/* Free pointer into note[]	*/
char voice0[NPBYTES];		/* Voices are stored here	*/
char voice1[NPBYTES];
char voice2[NPBYTES];
char voice3[NPBYTES];
char voice4[NPBYTES];
char voice5[NPBYTES];
char **voices[NPVOICE] {
	&voice0, &voice1, &voice2, &voice3, &voice4, &voice5
};
char	**pvoices[NPVOICE];		/* -> voice's current note	*/
char	**voicetop[NPVOICE] {
	&voice0[NPBYTES], &voice1[NPBYTES], &voice2[NPBYTES],
	&voice3[NPBYTES], &voice4[NPBYTES], &voice5[NPBYTES] 
};

struct psetup {
	int	ps_note;		/* Funny note to do		*/
	int	ps_value;		/* Default value		*/
	int	ps_index;		/* index into psetval[]		*/
	char	*ps_text;		/* Name of this parameter	*/
} psetup[] {
	{ GAP,		65535,	0,	"Gap"		},
	{ XPOSE,	65024,	1,	"Transpose"	},
	{ ATACK,	 8192,	2,	"Attack"	},
	{ DECAY,	   50,	3,	"Decay"		},
	{ VOL,		55000,	4,	"Volume"	},
	{ SUSTN,	20000,	5,	"Sustain"	},
	{ RELSE,	   50,	6,	"Release"	},
	{ 0,		    0,	0,	""		},
};

int	psetval[7][NPVOICE];	/* First index is value, 2nd voice	*/

/*
 * Handy variables for byte <-> word conversion
 */

int	intword;
char	*byteword = &intword;

int	iobuf[260];			/* 520 byte i/o buffer		*/
char	line[133];			/* Input buffer			*/
int	end_file	= 0;		/* End file marker		*/
int	line_count	= 0;
int	curr_meas	= 0;
int	curr_voice	= 0;
int	echoflag	= 0;

main()
{
	extern int	play();
	int	dmusic;
	int	pmusic;
	int	doctal;

	printf("Mozart Dice Dance composer, compiling grammar\n");
	if (fopen("mozart.txt", iobuf) == -1) {
		printf("Can't open mozart.txt\n");
		exit();
	}
	echoflag = getyesno("Echo input lines", "No");
	compile();			/* Compile the music		*/
	if (getyesno("Dump measure tables", "No"))
	 	d_meas();		/* Dump the buffers		*/
	setpreset();			/* Initialize preset buffer	*/
	for (;;) {
		dmusic = getyesno("Dump music", "No");
		if (dmusic)
			doctal = getyesno("Dump in octal", "No");
		pmusic = getyesno("Play music", "Yes");
		getsetup();
		printf("Type any key to stop playing\n");
		for (;;) {
			JSW->mem_word |= SPECMODE;
			if (ittinr() >= 0)
				break;
			getplay();
			if (dmusic)
				dump(doctal);	/* Dump the music	*/
			if (pmusic) {
				/*
				 * play runs the synthesizer.
				 */
				call(&play, 6, &voice0, &voice1, &voice2,
						&voice3, &voice4, &voice5);
			}
		}
		JSW->mem_word &= (~SPECMODE);
	}
}

setpreset()
/*
 * Called once to initialize the voicing parameters
 */
{
	register struct psetup	*ps;
	register int		vindex;

	for (ps = psetup; ps->ps_note; ps++)
		for (vindex = 0; vindex < NPVOICE; vindex++)
			psetval[ps->ps_index][vindex] = ps->ps_value;	
}

getsetup()
/*
 * Modify the playing parameters
 */
{
	register struct psetup	*ps;
	register int		vindex;
	
	for (;;) {
		printf("Enter voice number (0 .. %d), <CR> exits: ",
				NPVOICE - 1);
		if (getcommand())
			exit();
		if (line[0] == '\0')
			return;
		vindex = atoi(line);
		if (vindex < 0 || vindex >= NPVOICE) {
			printf("Illegal voice %d\n", vindex);
			continue;
		}
		printf("Current control values, enter <CR> to retain\n");
		for (ps = psetup; ps->ps_note; ps++) {
			printf("%s = %l ? ", ps->ps_text,
					psetval[ps->ps_index][vindex]);
			if (getcommand())
				exit();
			if (line[0] != '\0') {
				psetval[ps->ps_index][vindex] = atoi(line);
			}
		}
	}
}

		
getplay()
/*
 * Compile music into the playing buffers
 */
{
	register int	meas;		/* Which measure		*/
	register int	vindex;		/* Voice index for finish	*/
	int		saveroll[17];	/* Saves dice rolls		*/
	int		mindex[17];	/* Measure index		*/

	getinit();			/* Initialize voices		*/
	printf("\nMeasure:      ");
	for (meas = 1; meas <= 16; meas++) {
		vindex = roll();
		saveroll[meas] = vindex;
		mindex[meas] = mtab[vindex-2][meas-1];
		printf("%4d", meas);
	}
	printf("\nDice:         ");
	for (meas = 1; meas <= 16; meas++)
		printf("%4d", saveroll[meas]);
	printf("\nTable measure:");
	for (meas = 1; meas <= 16; meas++)
		printf("%4d", mindex[meas]);
	printf("\n");
	for (meas = 1; meas <= 8; meas++)
		p_meas(mindex[meas], meas, 0, saveroll[meas]);
	for (meas = 1; meas <= 7; meas++)
		p_meas(mindex[meas], meas, 0, saveroll[meas]);
	p_meas(mindex[8], 8, 1, saveroll[8]);	/* Get alternate ending */
	for (meas = 9; meas <= 16; meas++)
		p_meas(mindex[meas], meas, 0, saveroll[meas]);
	pstuff(0, REST, restbyte[1], restbyte[0], 17);
	pstuff(0, END, 0, 0, 17);	/* Stuff the end signals	*/
	for (vindex = 1; vindex < NPVOICE; vindex++) {
		pstuff(vindex, REST, restbyte[1], restbyte[0], 17);
		pstuff(vindex, STOP, 0, 0, 17);
	}
}

getinit()
/*
 * Initialize the playing field
 */
{
	register int		vindex;
	register struct psetup	*ps;

	for (vindex = 0; vindex < NPVOICE; vindex++) {
		pvoices[vindex] = voices[vindex];
		for (ps = psetup; ps->ps_note; ps++) {
			intword = psetval[ps->ps_index][vindex];
			pstuff(vindex, ps->ps_note,
					byteword[1], byteword[0], 0);
		}
	}
}

p_meas(mindex, meas, altvoice)
int		mindex;		/* Which measure table to output	*/
int		meas;		/* Which measure we're doing now	*/
int		altvoice;	/* Alternate voice index (0 or 1)	*/
/*
 * Output all voices for this measure
 */
{
	register struct voice	*vp;	/* Voice table pointer		*/
	register struct measure	*mp;	/* Minuette measure to do	*/
	register int		vcount;	/* Voices for this measure	*/
	int			mcount;	/* Voices in minuette measure	*/

	mp = &measure[mindex];		/* Here's the one to do		*/
	vp = mp->m_voice[altvoice];
	mcount = mp->m_vcount[altvoice];
	if (mcount != NPVOICE) {
		printf("Wrong number of voices (%d) for table measure, ",
			mcount, mindex);
		printf("alternate %d\n", altvoice+1);
		if (mcount > NPVOICE)
			mcount = NPVOICE;
	}
	for (vcount = 0; vcount < mcount; vcount++) {
		getvoice(vp, vcount, altvoice, meas);
		vp++;
	}
	for (; vcount < NPVOICE; vcount++)
		pstuff(vcount, REST, restbyte[1], restbyte[0], meas);
}

getvoice(vptr, vcount, altvoice, meas)
struct	voice	*vptr;		/* Voice to generate			*/
int		vcount;		/* Which one to stuff it into		*/
int		altvoice;	/* Selector				*/
int		meas;		/* Measure number (for debugging)	*/
/*
 * Output notes for this measure
 */
{
	register struct note	*np;
	register int		ncount;
	register int		count;

	np	= vptr->v_note;
	ncount	= vptr->v_count;
	for (count = 0; count < ncount; count++) {
		intword = (np->n_dur & 255);
		intword = intword * MULTIPLIER;
		pstuff(vcount, np->n_note, byteword[1], byteword[0], meas);
		np++;
	}
}

pstuff(vindex, notebyte, highbyte, lowbyte, meas)
int		vindex;		/* Voice number (0 - 5)			*/
char		notebyte;	/* Note byte				*/
char		highbyte;	/* High byte of duration		*/
char		lowbyte;	/* Low byte of duration			*/
/*
 * Enter the next note for this voice.  This is the only routine to enter
 * data into pvoices[].
 */
{
	register char		*pp;

	pp = pvoices[vindex];
	if (pp >= voicetop[vindex]) {
		printf("Too many notes for voice %d, measure %d\n",
			vindex, meas);
		fatal("Voice", voicetop[vindex] - voices[vindex]);
	}
	*pp++ = notebyte;
	*pp++ = highbyte;
	*pp++ = lowbyte;
	pvoices[vindex] = pp;
}

dump(doctal)
int	doctal;		/* Dump in octal if set				*/
/*
 * Dumb routine to dump some music
 */
{

	register int		vindex;
	int			anything;	/* Set if a note prints	*/
	register int		temp;
	register char		*pp;
	char			**sptr;

	for (vindex = 0; vindex < NPVOICE; vindex++)
		pvoices[vindex] = voices[vindex];	/* Init ptrs	*/

	for (anything = 1; anything;) {
		anything = 0;			/* Nothing yet		*/
		for (vindex = 0; vindex < NPVOICE; vindex++) {		
			pp = pvoices[vindex];	/* Do this one		*/
			temp		= *pp++ & 0377;	/* note		*/
			byteword[1]	= *pp++ & 0377;	/* hidur	*/
			byteword[0]	= *pp++ & 0377;	/* lodur	*/
			if (doctal) {
				printf(":%03o %03o %03o", temp,
					byteword[1] & 0377,
					byteword[0] & 0377);
			}
			else {
				if (temp > REST)
					printf("%s %6l",
						special[temp-REST], intword);
				else if (temp == REST)
					printf("R  %9d",
						intword / MULTIPLIER);
				else {
					temp /= 2;
					printf("%s%d %8d", ntext[temp % 12],
						temp / 12,
						intword / MULTIPLIER);
				}
			}
			printf((vindex == NPVOICE-1) ? "\n" : " ");
			if (temp == STOP || temp == END)
				continue;
			anything = 1;
			pvoices[vindex] = pp;
		}
	}
}

d_meas()
/*
 * Dump the measure table.
 */
{
	register struct measure	*mp;
	register struct voice	*vp;

	if (getyesno("Dump selective measures", "No")) {
		for (;;) {
			printf("Measure, 0 ends: ");
			if (getcommand())
				return;
			curr_meas = atoi(line);
			if (curr_meas <= 0)
				return;
			if (curr_meas >= NMEASURE) {
				printf("Bad measure number %d\n", curr_meas);
				continue;		
			}
			mp = &measure[curr_meas];
			printf(".%d\n", curr_meas);
			if (mp->m_voice[0] == mp->m_voice[1])
				d_voice(mp->m_voice[0], mp->m_vcount[0], 0);
			else {
				d_voice(mp->m_voice[0], mp->m_vcount[0], 1);
				d_voice(mp->m_voice[1], mp->m_vcount[1], 2);
			}
		}
	}
/*
 * Dump all measures
 */
	curr_meas = -1;
	for (mp = measure; mp < &measure[NMEASURE]; mp++) {
		curr_meas++;
		if (mp->m_vcount[0] == 0)
			continue;	/* No entry for this measure	*/
		printf(".%d\n", curr_meas);
		vp = mp->m_voice[0];
		if (vp != mp->m_voice[1]) {
			d_voice(vp, mp->m_vcount[0], 1);
			d_voice(mp->m_voice[1], mp->m_vcount[1], 2);
		}
		else	d_voice(vp, mp->m_vcount[0], 0);
	}
}

d_voice(vptr, mcount, altflag)
struct voice	*vptr;		/* Voice pointer			*/
int		mcount;		/* Number of voices			*/
int		altflag;	/* Alternate signal			*/
/*
 * Dump all voices for the current measure.  altflag =
 *	0	No alternation
 *	1	Dump alternate 1
 *	2	Dump alternate 2
 */
{
	register struct note	*np;
	register int		nvoice;
	register int		ncount;

	if (altflag)
		printf("]%d\n", altflag);
	printf("* measure %d, [%d] %d voices\n",
			curr_meas, altflag, mcount);
	for (nvoice = 0; nvoice < mcount; nvoice++) {
		np = vptr->v_note;
		printf("* voice %d has %d notes\n", nvoice+1, vptr->v_count);
		for (ncount = 0; ncount < vptr->v_count; ncount++)
			d_note(np++);
		vptr++;
	}
	printf("\n");
}

d_note(nptr)
struct note	*nptr;
/*
 * Dump a note
 */
{
	register int		nval;
	register struct	dtab	*dp;

	nval = nptr->n_note & 255;
	if (nval == REST)
		printf("R ,");
	else {
		nval /= 2;
		printf("N %s%d,", ntext[nval % 12], nval / 12);
	}
	for (dp = dtab; dp->d_dur != 0 && dp->d_dur != nptr->n_dur; dp++);
	printf("%d\n", dp->d_val);
}

compile()
/*
 * Compile the music
 */
{
	register struct measure	*mp;	/* Measure pointer		*/
	register int		mcount;
	register int		vcount;	
	char			*skipbl();

	mcount = 0;
	skipline(1);			/* Find first line		*/
	while (!end_file) {
		if (line[0] != '.') {
		bug("Expecting a new measure");
			skipline(1);
			continue;
		}
		curr_meas = atoi(skipbl(&line[1]));
		mcount++;
		if (curr_meas <= 0 || curr_meas >= NMEASURE) {
			bug1("Illegal (or missing) measure [%d]\n",
					curr_meas);
			skipline(1);
			continue;
		}
		mp = &measure[curr_meas];
		if (mp->m_vcount[0] != 0) {
			bug1("You've entered measure %d already\n",
				curr_meas);
		}
		if (skipline(1)) {
			bug("Eof after measure number");
			continue;
		}
		if (line[0] != ']') {			/* No alternate	*/
			mp->m_voice[0] = p_voice;
			mp->m_voice[1] = p_voice;
			vcount = in_voice(0);
			mp->m_vcount[0] = vcount;
			mp->m_vcount[1] = vcount;
			if (vcount != NPVOICE)
				bug1("Wrong number of voices (%d) in measure",
						vcount);
		}
		else {					/* Alternate 1	*/
			if (line[1] != '1') {
				bug1("Expecting ]1, got ]%c", line[1]);
				continue;
			}
			skipline(1);
			mp->m_voice[0] = p_voice;
			vcount = in_voice();
			mp->m_vcount[0] = vcount;
			if (vcount != NPVOICE)
				bug1("Wrong number of voices (%d) in alt 1",
					vcount);
			if (skipline(0)) {
				bug("Eof after alternate 1");
				continue;
			}
			if (line[0] != ']' || line[1] != '2') {
				bug("Illegal alternate, expecting ]2");
				continue;
			}
			skipline(1);
			mp->m_voice[1] = p_voice;
			vcount = in_voice();
			mp->m_vcount[1] = vcount;
			if (vcount != NPVOICE)
				bug1("Wrong number of voices (%d) in alt 2",
					vcount);
		}
	}
	printf("* %d measures entered\n", mcount);
}

in_voice()
/*
 * Enter the next voices for this measure/alternate.  Return
 * the number of voices entered.
 *
 * On entrance, line -> first voice line
 * Return on blank line or . or ] seen.
 * 
 * Warning: the input file must have one of the following formats:
 *	notes (both normal and alternate)
 *	<blank line>
 * or
 *	notes
 *	]alternate
 */
{
	register struct	voice	*vp;
	register int		nnotes;
	char			*skipbl();
	struct	voice		*nextvoice();

	curr_voice = 0;
	while (!skipline(0)) {
		if (line[0] == ']' || line[0] == '.')
			break;
		curr_voice++;
		vp = nextvoice();		/* Vp -> voice box	*/
		vp->v_note = p_note;
		while (!end_file && line[0] != 0 &&
				line[0] != ']' && line[0] != '.') {
			vp->v_count = in_note();
		}
	}
	return(curr_voice);
}

in_note()
/*
 * Read the notes, return the number read.
 */
{
	register char	*lp;
	register struct	dtab	*dp;
	register int	c;
	struct 	note	*np;
	int		ncount;
	struct	note	*nextnote();
	char		*skipbl();
	
	ncount = 0;
/*
 * Note line format:
 *	N AN0,len
 * or
 *	R ,len
 *
 * Where N is note, R is rest.  len is the length (must be in the table)
 * Each note is given as [A-G] followed by N (natural) or S (sharp),
 * followed by the octave number [0-9].  AN0 (the lowest note) is 0.
 */
	while (!end_file && line[0] != 0 &&
				line[0] != ']' && line[0] != '.') {
		np = nextnote();
		ncount++;
		lp = skipbl(line);
		if ((c = *lp++) == 'R') {
			np->n_note = REST;
		}
		else if (c == 'N') {
			lp = skipbl(lp);
			c = *lp++ - 'A';
			if (c < 0 || c > ('G' - 'A')) {
				bug1("Illegal character '%c'\n", c + 'A');
				continue;
			}
			c += c;			/* Times two for index	*/
			if (*lp == 'S') {
				c++;		/* Fix index for sharps	*/
				lp++;		/* Eat the character	*/
			}
			else if (*lp == 'N')
				lp++;		/* Eat natural chars.	*/
			/*
			 * Assuming 7 octaves??
			 */
			if (*lp < '0' || *lp > '7') {
				bug1("Illegal octave '%c'\n", *lp);
				continue;
			}
			np->n_note = (ttab[c] + (12 * (*lp++ - '0'))) * 2;
		}
		else {
			bug1("Expecting note/rest, got '%c'\n", c);
			np->n_note = REST;	/* stuff something	*/
		}
		/*
		 * Got the note, now for the duration.
		 */
		lp = skipbl(lp);
		if (*lp++ != ',')
			bug1("Expecting comma before duration, got '%c'\n",
					*--lp);
		c = atoi(lp);			/* Compile duration	*/
		for (dp = dtab; dp->d_val && dp->d_val != c; dp++);
		if (dp->d_val == 0)
			bug1("Unknown duration %d\n", c);
		np->n_dur = dp->d_dur;
		getline();
	}
	return(ncount);
}

struct voice *nextvoice()
/*
 * Update voice pointer
 */
{
	if (p_voice >= &voice[NVOICES])
		fatal("voice", NVOICES);
	return(p_voice++);
}

struct note *nextnote()
/*
 * Update notes pointer
 */
{
	if (p_note >= &note[NNOTES])
		fatal("note", NNOTES);
	return(p_note++);
}

char *skipbl(lineptr)
char	*lineptr;
/*
 * Skip over blanks, return updated line pointer
 */
{
	register char	*lp;

	for (lp = lineptr; *lp && *lp <= ' '; lp++);
	return(lp);
}

skipline(flag)
int		flag;		/* 1 to read initially			*/
/*
 * Skip blank lines, flag is non-zero to read a line before checking
 * for blanks.  Return 1 on end of file.
 */
{
	if (flag)
		line[0] = 0;
	while (!end_file && line[0] == 0)
		getline();			/* Skip blank lines	*/
	return(end_file);
}

getline()
/*
 * Read text (from iobuf) to global line[].
 * Return 1 on end of file, zero on ok.
 */
{
	register char	*t;
	register char	c;

reread:	t = line;
	line_count++;
	while ((c = getc(iobuf)) >= 0) {
		if (c == 0 || c == '\r')	/* Skip CR or NULL	*/
			continue;		/* Rt11 last block	*/
		if (c == '\n') {
			/*
			 * Squeeze out trailing blanks
			 */
			while (t > line && t[-1] == ' ') t--;
			*t = 0;
			if (line[0] == '*')	/* Allow * comments	*/
				goto reread;
			if (echoflag)
				printf(">> \"%s\"\n", line);
			return(0);
		}
		*t++ = c;
	}
	if (echoflag)
		printf("End of file\n");
	line[0] = 0;
	end_file = 1;
	return(1);
}

getyesno(prompt, normal)
char	*prompt;		/* Prompt string			*/
char	*normal;		/* Default answer "Yes" or "No"		*/
{
	printf("%s? (Yes/No) <%s>: ", prompt, normal);
	if (getcommand())
		return(0);	/* End of file is very false		*/
	if (line[0] == 0)
		line[0] = normal[0];
	return((line[0] | 040) == 'y');
}

getcommand()
/*
 * Read text from keyboard to global line[].
 * Return 1 on end of file, zero on ok.  Note: rt11 probably trashes the
 * job so you'll never see the end of file.
 */
{
	register char	*t;
	register char	c;

	t = line;
	line_count++;
	while ((c = getchar()) >= 0) {
		if (c == 0 || c == '\r')	/* Skip CR or NULL	*/
			continue;		/* Rt11 last block	*/
		if (c == '\n') {
			/*
			 * Squeeze out trailing blanks
			 */
			while (t > line && t[-1] == ' ') t--;
			*t = 0;
			return(0);
		}
		*t++ = c;
	}
	line[0] = 0;
	end_file = 1;
	return(1);
}

bug(s)
char	*s;
/*
 * Bug printout
 */
{
	printf("? %s\n", s);
	printf("? Input line %d \"%s\"\n", line_count, line);
	printf("? Current measure is %d, current voice is %d\n\n",
			curr_meas, curr_voice);
}

bug1(s, i)
char	*s;
int	i;
/*
 * Bug printout
 */
{
	printf(s, i);
	printf("? Input line %d  \"%s\"\n", line_count, line);
	printf("? Current measure is %d, current voice is %d\n\n",
			curr_meas, curr_voice);

}

fatal(s, i)
char	*s;
int	i;
/*
 * Table overflow
 */
{
	printf("%s table overflow, max. is %d\n", s, i);
	printf("Input line is \"%s\"\n", line);
	printf("Measure %d\n", curr_meas);
	exit(1);
}

roll()
/*
 * Roll the dice twice, return their sum.  Note: a number between 2 and
 * 12 is always returned.
 */
{
	return(irand(6) + irand(6) + 2);
}

