[comp.sources.misc] v06i115: glib part 15 of 15

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (05/22/89)

Posting-number: Volume 6, Issue 115
Submitted-by: lee@uhccux.uhcc.Hawaii.Edu (Greg Lee )
Archive-name: glib/part13

[Parts 13 and 14 are uuencoded .arc files.  Doesn't *ANYBODY* read the
guidelines???  (A copy follows this message, to remind you.)  I'm going
to figure out what they are and dump them elsewhere.  In the meantime,
don't look for them here.  ++bsa]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 15 (of 15)."
# Contents:  glib.c
# Wrapped by lee@uhccux on Sun May  7 00:40:21 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'glib.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'glib.c'\"
else
echo shar: Extracting \"'glib.c'\" \(41661 characters\)
sed "s/^X//" >'glib.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: glib.c,v 1.6 89/05/06 17:13:24 lee Exp $";
X#endif
X/*
X * GLIB - a Generic LIBrarian and editor for synths
X *
X * Tim Thompson's original with modifications by Michael Kesti,
X *	Greg Lee, Alan Bland, Scott Snyder, Mark Rinfret
X * $Log:	glib.c,v $
X * Revision 1.6  89/05/06  17:13:24  lee
X * rel. to comp.sources.misc
X * 
X */
X
X#include "glib.h"
X#include <ctype.h>
X
Xchar *Reason = "";
X
Xint Currrow = 0;	/* at top of screen, for messages */
Xint Libbank = 0;	/* from 0 to LIBBANKS-1, is the current library bank*/
Xint Nsynths = 0;
X
Xint Lastvalue = 0;
X
Xchar *Currdata;
Xchar *Yankdata;		/* current 'yank' buffer (middle of screen) */
X
Xstruct peredinfo *PE;	/* array of per-editor miscellany */
X
Xchar Buff[BUFSIZ];
Xint Redraw = 0;		/* if non-0, edit screen is completely redrawn. */
X			/* parameter functions can make use of this. */
Xint Changed = 0;
Xint DataID = 0;		/* Data Id for file write and read operations */
X
X/* All the global values below are set as appropriate for the */
X/* synthesizer currently being dealt with. */
X
Xint Nvoices = 0;
Xint Voicesize =0;
Xint Namesize = 0;
Xint Libindex;		/* from 0 to Nvoices-1 */
Xint Synindex;		/* from 0 to Nvoices-1 */
Xint Channel;
Xint Editrow;		/* from 0 to NUMONSCREEN-1 */
Xint Editcol;		/* 0==synth, 1==library */
Xchar *Libdata;		/* current library data (includes all LIBBANKS) */
X			/* ie. the stuff on the right side of the screen */
Xchar *Syndata;		/* current synth data (1 bank), ie. the left side */
Xstruct paraminfo *P;	/* list of parameter info */
Xstruct labelinfo *L;	/* arbitrary screen labels for edit screen */
Xchar *Synthname;
X#ifdef SSS
Xint *scr_p;
Xint NParams;
X#endif
X#ifdef KAWAIK1
Xchar sngnames[64][11];
X#endif
X
Xint synthinfileflag = 0;
Xint synthoutfileflag = 0;
Xchar Syinfname[100], Syofname[100];
X
Xint (*Sendedit)();	/* function to send parameters to synth's edit buffer*/
Xint (*Datain)();	/* convert data from file-storage format to the */
X			/* format stored in the P[] parameter array (p_val) */
Xint (*Dataout)();	/* reverse of Datain */
Xint (*Sendone)();	/* function to send one (permanent) voice to synth */
Xint (*Sendbulk)();	/* function to send bulk dump to synth */
Xint (*Getbulk)();	/* reverse of Sendbulk */
Xchar *(*Nameof)();	/* pulls voice name out of file-storage data */
Xint (*Setnameof)();	/* reverse of Nameof */
Xchar *(*Numof)();	/* convert voice number to on-screen text */
Xint (*Cvtnum)();	/* convert visible voice number to std. format */
Xint (*Cvtanum)();	/* convert alphanumeric voice number to std. format */
X			/* should never define both Cvtnum and Cvtanum */
X
X#ifdef SSS
X# define PARAMAT(r, c) (*(scr_p + Cols*(r) + (c)))
X#endif
X
Xmain()
X{
X	int n;
X
X	hello();
X	windinit();
X	initstuff();
X
X	if ( Nsynths == 0 )
X		windstr("Hey, the E array is empty?");
X	else if ( Nsynths == 1 ) {
X		/* If there's only 1 synth, don't bother asking */
X		setedit(0);
X		libinteract();
X	}
X	else {
X		while ( (n=choosesynth()) >= 0 ) {
X			setedit(n);
X			libinteract();
X			unsetedit(n);
X		}
X	}
X	bye();
X}
X
X/* choose a synth, returning its position in the E array */
Xchoosesynth()
X{
X	int n, pick;
X
X    retry:
X	flushconsole();
X	windclear();
X	windgoto(2,23);
X#ifdef KAWAIK1
X	windstr("Kawai K1 Librarian/Editor");
X#else
X#ifdef ROLANDD10
X	windstr("Roland D-10 Librarian/Editor");
X#else
X	windstr("GLIB - A Generic Librarian/Editor");
X#endif
X#endif
X
X	for ( n=1; n<=Nsynths; n++ )
X		libchoice(n);
X	windgoto(8+Nsynths,27);
X	windstr("q  -  Quit");
X	windgoto(11+Nsynths,27);
X	windstr("Make selection --> ");
X	windrefresh();
X	pick = mouseorkey();
X	if ( pick == 'q' || pick == EOF )
X		return(-1);
X	if ( pick != MOUSE )
X		pick = pick - '0';
X	else {
X		int row, col;
X		getmouse(&row,&col);
X		/* wait until mouse goes down */
X		while ( statmouse() > 0 )
X			;
X		pick = row - 6; 
X	}
X	if ( pick < 1 || pick > Nsynths )
X		goto retry;
X	return(pick-1);
X}
X
Xlibchoice(n)
X{
X	windgoto(6+n,27);
X	(void)sprintf(Buff,"%d  -  %s",n,E[n-1].ed_name);
X	windstr(Buff);
X}
X
X#ifndef SINGLEDATA
X
Xinitstuff()
X{
X	int n, banksize, maxvsize;
X	
X	maxvsize = 0;
X	for ( n=0; E[n].ed_name != NULL; n++ ) {
X		if ( maxvsize < E[n].ed_vsize )
X			maxvsize = E[n].ed_vsize;
X	}
X	Nsynths = n;
X	Currdata = alloc( maxvsize );
X
X	/* allocate an array of peredinfo structs */
X	PE =(struct peredinfo *)alloc((int)(Nsynths*sizeof(struct peredinfo)));
X	for ( n=0; n<Nsynths; n++ ) {
X		banksize =  E[n].ed_nvoices * E[n].ed_vsize;
X
X		PE[n].ed_libdata = alloc(LIBBANKS * banksize);
X		clrdata(PE[n].ed_libdata, LIBBANKS * banksize);
X
X		PE[n].ed_syndata = alloc(banksize);
X		clrdata(PE[n].ed_syndata, banksize);
X
X		PE[n].ed_yankdata = alloc(E[n].ed_vsize);
X		clrdata(PE[n].ed_yankdata, E[n].ed_vsize);
X
X		PE[n].ed_libindex = 0;
X		PE[n].ed_synindex = 0;
X		PE[n].ed_channel = 1;
X		PE[n].ed_erow = 0;
X		PE[n].ed_ecol = 0;
X	}
X}
X
X#else
X
Xinitstuff()
X{
X	int n, banksize, maxvsize;
X	char *lib, *syn, *yank;
X	
X	maxvsize = 0;
X	for ( n=0; E[n].ed_name != NULL; n++ ) {
X		if ( maxvsize < E[n].ed_vsize )
X			maxvsize = E[n].ed_vsize;
X	}
X	Nsynths = n;
X	Currdata = alloc( maxvsize );
X
X	PE =(struct peredinfo *)alloc((int)(Nsynths*sizeof(struct peredinfo)));
X
X	/* allocate common data areas */
X	banksize =  E[0].ed_nvoices * E[0].ed_vsize;
X
X	lib = alloc(LIBBANKS * banksize);
X	clrdata(lib, LIBBANKS * banksize);
X
X	syn = alloc(banksize);
X	clrdata(syn, banksize);
X
X	yank = alloc(E[0].ed_vsize);
X	clrdata(yank, E[0].ed_vsize);
X
X	for ( n=0; n<Nsynths; n++ ) {
X		PE[n].ed_libdata = lib;
X		PE[n].ed_syndata = syn;
X		PE[n].ed_yankdata = yank;
X		PE[n].ed_libindex = 0;
X		PE[n].ed_synindex = 0;
X		PE[n].ed_channel = 1;
X		PE[n].ed_erow = 0;
X		PE[n].ed_ecol = 0;
X	}
X}
X
X#endif
X
Xclrdata(data,size)
Xchar *data;
X{
X	register char *p, *endp;
X
X	p = data;
X	endp = data+size;
X
X	while ( p<endp )
X		*p++ = 0;
X}
X
X#ifdef SSS
Xint paramcmp(p1, p2)
Xstruct paraminfo *p1, *p2;
X{
X  return strcmp(p1->p_name, p2->p_name);
X}
X
Xinit_params()
X{
X  int i;
X
X  for (NParams=0; P[NParams].p_name != NULL; NParams++)
X    ;
X  qsort((void *)P, NParams, sizeof(struct paraminfo), paramcmp);
X
X  scr_p = (int *)alloc(Rows * Cols * sizeof(int));
X  clrdata((char *)scr_p, Rows * Cols * sizeof(int));
X  for (i=0; i<NParams; i++) {
X    int r = P[i].p_vrow;
X    int c = P[i].p_vcol;
X
X    if (r >= 0 && r < Rows && c >= 0 && c < Cols)
X      PARAMAT(r, c) = i+1;
X  }
X}
X#endif
X
X#ifndef SINGLEDATA
X
Xsetedit(n)
X{
X	Synthname = E[n].ed_name;
X	Datain = E[n].ed_din;
X	Dataout = E[n].ed_dout;
X	Nvoices = E[n].ed_nvoices;
X	Sendedit = E[n].ed_sedit;
X	Sendone = E[n].ed_sone;
X	Sendbulk = E[n].ed_sbulk;
X	Getbulk = E[n].ed_gbulk;
X	Nameof = E[n].ed_nof;
X	Numof = E[n].ed_numof;
X	Cvtnum = E[n].ed_cvtnum;
X	Cvtanum = E[n].ed_cvtanum;
X	Setnameof = E[n].ed_snof;
X	Voicesize = E[n].ed_vsize;
X	Namesize = E[n].ed_nsize;
X	DataID = E[n].ed_dataid;
X	Libdata = PE[n].ed_libdata;
X	Syndata = PE[n].ed_syndata;
X	Yankdata = PE[n].ed_yankdata;
X	Libindex = PE[n].ed_libindex;
X	Synindex = PE[n].ed_synindex;
X	Channel = PE[n].ed_channel;
X	Editrow = PE[n].ed_erow;
X	Editcol = PE[n].ed_ecol;
X	clrdata(Currdata,Voicesize);
X	P = E[n].ed_params;
X	L = E[n].ed_labels;
X
X#ifdef SSS
X        init_params();
X#endif
X}
X
Xunsetedit(n)
X{
X	int k;
X
X	DataID = 0;
X	PE[n].ed_libindex = Libindex;
X	PE[n].ed_synindex = Synindex;
X	PE[n].ed_channel = Channel;
X	PE[n].ed_erow = Editrow;
X	PE[n].ed_ecol = Editcol;
X	for ( k=0; k<Voicesize; k++ )
X		PE[n].ed_yankdata[k] = Yankdata[k];
X}
X
X#else
X
Xsetedit(n)
X{
X	Synthname = E[n].ed_name;
X	Datain = E[n].ed_din;
X	Dataout = E[n].ed_dout;
X	Nvoices = E[n].ed_nvoices;
X	Sendedit = E[n].ed_sedit;
X	Sendone = E[n].ed_sone;
X	Sendbulk = E[n].ed_sbulk;
X	Getbulk = E[n].ed_gbulk;
X	Nameof = E[n].ed_nof;
X	Numof = E[n].ed_numof;
X	Cvtnum = E[n].ed_cvtnum;
X	Cvtanum = E[n].ed_cvtanum;
X	Setnameof = E[n].ed_snof;
X	Voicesize = E[n].ed_vsize;
X	Namesize = E[n].ed_nsize;
X	DataID = E[n].ed_dataid;
X	Libdata = PE[n].ed_libdata;
X	Syndata = PE[n].ed_syndata;
X	Yankdata = PE[n].ed_yankdata;
X	Libindex = PE[n].ed_libindex;
X	Synindex = PE[n].ed_synindex;
X	Channel = PE[n].ed_channel;
X	Editrow = PE[n].ed_erow;
X	Editcol = PE[n].ed_ecol;
X	clrdata(Currdata,Voicesize);
X	P = E[n].ed_params;
X	L = E[n].ed_labels;
X#ifdef SSS
X        init_params();
X#endif
X}
X
Xunsetedit(n)
X{
X	int j, k;
X
X	DataID = 0;
X	for(j=0; j < Nsynths; j++) {
X		PE[j].ed_libindex = Libindex;
X		PE[j].ed_synindex = Synindex;
X		PE[j].ed_channel = Channel;
X		PE[j].ed_erow = Editrow;
X		PE[j].ed_ecol = Editcol;
X		for ( k=0; k<Voicesize; k++ ) {
X			PE[j].ed_yankdata[k] = Yankdata[k];
X		}
X	}
X}
X
X#endif
X
X/* template - show the boxes and such on the main library screen */
Xtemplate()
X{
X	int n, k, r;
X
X	r = FIRSTROW-1;
X	(void)sprintf(Buff,"%s",Synthname);
X	n = 13 - strlen(Buff)/2;	/* center it */
X	windgoto(r,n<0?0:n);
X	windstr(Buff);
X	r++;
X	windgoto(r,0);
X	for ( n=0; n<25; n++ )
X		windputc('=');
X	windgoto(r,53);
X	for ( n=0; n<25; n++ )
X		windputc('=');
X	for ( n=r+1; n<(r+13); n++ ) {
X		windgoto(n,0);
X		windputc('|');
X		windgoto(n,5);
X		windputc('|');
X		windgoto(n,24);
X		windputc('|');
X
X		k=53;
X		windgoto(n,k);
X		windputc('|');
X		windgoto(n,k+5);
X		windputc('|');
X		windgoto(n,k+24);
X		windputc('|');
X	}
X	windgoto(r+13,0);
X	for ( n=0; n<25; n++ )
X		windputc('=');
X	windgoto(r+13,53);
X	for ( n=0; n<25; n++ )
X		windputc('=');
X
X	windgoto(YANKROW-2,YANKCOL);
X	windstr("  Yank Buffer");
X	windgoto(YANKROW-1,YANKCOL);
X	windstr(" ------------- ");
X	windgoto(YANKROW,YANKCOL);
X	windstr("               ");
X	windgoto(YANKROW+1,YANKCOL);
X	windstr(" ------------- ");
X	windrefresh();
X}
X
X/* clear the message area */
Xclearmess()
X{
X	int n;
X	for(n=1;n<(FIRSTROW-1);n++)
X		winderaserow(n);
X	Currrow = 0;
X}
X
X/* set the current voice (ie. the synth's edit buffer) to the indicated */
X/* voice.  c==0 is the synth (left) side, c==1 is the library (right) side. */
Xeditto(r,c)
X{
X	int voicenum;
X
X	/* Clear the existing '*' */
X	editchar(' ',Editrow,Editcol);
X	editchar('*',Editrow=r,Editcol=c);
X	if ( Editcol==0 ) {
X		/* we're on the synth side */
X		voicenum = Editrow+Synindex;
X		tocurrent(Syndata,voicenum);
X	}
X	else {
X		/* we're on the lib side */
X		voicenum = Editrow+Libindex;
X		tocurrent(bankvoice(0),voicenum);
X	}
X}
X
Xeditchar(ec,r,c)
X{
X	r = r + FIRSTROW + 1;
X	if ( c == 0 )
X		c = LEFTSIDE-1;
X	else
X		c = RIGHTSIDE-1;
X	windgoto(r,c);
X	windputc(ec);
X	windrefresh();
X}
X
X/* control interaction on the main library bank screen */
Xlibinteract()
X{
X	int c, n, swap, voicenum, maxindex, q;
X	char *p, *data;
X
X	flushmidi();
X	drawall();
X	for ( ;; ) {
X		Currrow = 0;
X		winderaserow(Currrow);
X		windgoto(Currrow,0);
X		windstr("Command --> ");
X		windrefresh();
X		
X		c = mouseorkey();
X		if ( c == MOUSE ) {
X			libmouse();
X			continue;
X		}
X
X		if ( isprint(c) )
X			windputc(c);
X		clearmess();
X		switch ( c ) {
X		case ' ':
X			playnote(1);
X			break;
X		case '\n':
X#ifndef macintosh
X		case '\r':
X#endif
X			/* ignore */
X			break;
X		case EOF:
X		case 'q':
X			return;
X		case CH_REDRAW:
X			drawall();
X			break;
X		case 's':
X		case 'p':
X			swap = (c=='s')?1:0;
X			if ( Editcol==0 )
X				tosyn(Synindex+Editrow,Yankdata,swap);
X			else
X				tolib(Libindex+Editrow,Yankdata,swap);
X			updatedisplay();
X			pryankname();
X			break;
X		case 'y':
X			for(n=0;n<Voicesize;n++)
X				Yankdata[n] = Currdata[n];
X			pryankname();
X			break;
X		case '?':
X			helpmessage();
X			break;
X		case SCR_DOWN:
X			if(Nvoices < NUMONSCREEN)
X				q = Nvoices;
X			else
X				q = NUMONSCREEN;
X
X			maxindex = Nvoices - q;
X			if ( Editcol==0 ) {
X				/* we're on the synth side */
X				if ( (Synindex+=q/2) > maxindex )
X					Synindex = maxindex;
X			}
X			else {
X				/* we're on the lib side */
X				if ( (Libindex+=q/2) > maxindex )
X					Libindex = maxindex;
X			}
X			updatedisplay();
X			break;
X		case SCR_UP:
X			if ( Editcol==0 ) {
X				/* we're on the synth side */
X				if ( (Synindex-=NUMONSCREEN/2) < 0 )
X					Synindex = 0;
X			}
X			else {
X				/* we're on the lib side */
X				if ( (Libindex-=NUMONSCREEN/2) < 0 )
X					Libindex = 0;
X			}
X			updatedisplay();
X			break;
X		case '\033':
X		case '`':
X			allnotesoff();
X			break;
X		case 't':
X			transcmd();
X			editto(Editrow,Editcol);
X			break;
X		case 'D':	/* download FROM file */
X			synthinfileflag = 1;
X		case 'd':	/* download FROM synth */
X			clrdata(Syndata,Nvoices*Voicesize);
X			if ( readsynth(Syndata) == 0 ) {
X				syntodisplay(Synindex=0);
X				if(Editcol == 0)
X					editto(Editrow,Editcol);
X			}
X			synthinfileflag = 0;
X			break;
X		case 'U':	/* upload to file */
X			synthoutfileflag = 1;
X		case 'u':	/* upload TO synth */
X			if ( Editcol==0 ) {
X				voicenum = Editrow+Synindex;
X				data = &(VOICEBYTE(Syndata,voicenum,0));
X			}
X			else
X				data = bankvoice(Editrow+Libindex);
X			upload(data);
X			synthoutfileflag = 0;
X			break;
X		case 'r':
X			readall();
X			if(Editcol == 1)
X				editto(Editrow,Editcol);
X			break;
X		case 'R':
X			readprintable();
X			if(Editcol == 1)
X				editto(Editrow,Editcol);
X			break;
X		case 'w':
X			writeall();
X			break;
X		case 'W':
X			writeprintable();
X			break;
X		case 'c':
X			setchan();
X			break;
X		case 'b':
X			/* cycle through banks, from 0 to LIBBANKS-1 */
X			if ( ++Libbank >= LIBBANKS )
X				Libbank = 0;
X			libtodisplay(Libindex);
X			updatedisplay();
X			break;
X		case 'e':
X			if ( Namesize == 0)
X				p = NULL;
X			else
X				p = (*Nameof)(Currdata);
X			if ( Editcol==0 ) {
X				voicenum = Editrow+Synindex;
X				data = &(VOICEBYTE(Syndata,voicenum,0));
X				editdata(p,data);
X				windclear();
X				/* Update Currdata */
X				for ( n=0; n<Voicesize; n++ )
X				    Currdata[n] = VOICEBYTE(Syndata,voicenum,n);
X			}
X			else {
X				data = bankvoice(Editrow+Libindex);
X				editdata(p,data);
X			}
X			drawall();
X			break;
X		case 'g': /* goto a specific voice */
X			do_goto();
X			break;
X		case CH_LEFT:
X		case ALTCH_LEFT:
X			if ( Editcol==1 )
X				editto(Editrow,0);
X			break;
X		case CH_DOWN:
X		case ALTCH_DOWN:
X			if(Nvoices < NUMONSCREEN)
X				q = Nvoices;
X			else
X				q = NUMONSCREEN;
X			if ( Editrow < (q-1) )
X				editto(Editrow+1,Editcol);
X			else {
X				/* we're at the bottom, so try to scroll */
X				if ( Editcol==0 ) {
X					/* we're on the synth side */
X					if (Synindex<(Nvoices-q))
X						Synindex++;
X				}
X				else {
X					/* we're on the lib side */
X					if (Libindex<(Nvoices-q))
X						Libindex++;
X				}
X				updatedisplay();
X			}
X			break;
X		case CH_UP:
X		case ALTCH_UP:
X			if ( Editrow>0 )
X				editto(Editrow-1,Editcol);
X			else {
X				/* we're at the top, so try to scroll */
X				if ( Editcol==0 ) {
X					/* we're on the synth side */
X					if (Synindex>0)
X						Synindex--;
X				}
X				else {
X					/* we're on the lib side */
X					if (Libindex>0)
X						Libindex--;
X				}
X				updatedisplay();
X			}	
X			break;
X		case CH_RIGHT:
X		case ALTCH_RIGHT:
X			if ( Editcol==0 )
X				editto(Editrow,1);
X			break;
X		case 'f':
X			filelist();
X			break;
X		default:
X			message("Unrecognized command!  Press '?' for help.");
X			break;
X		}
X	}
X}
X
Xfilelist()
X{
X	char *p, *q, buff[BUFSIZ];
X	int n, ninline = 0, nprinted = 0;
X
X	clearmess();
X	Currrow = -1;	/* To start message on top line */
X	openls();
X	message("Files in current directory:");
X	strcpy(buff,"  ");
X	while ( (p=nextls()) != NULL ) {
X		/* add the next file to the line being constructed */
X		q = &buff[strlen(buff)];
X		strcpy(q,p);
X		q += (n=strlen(p));
X		while ( n++ < 15 )
X			*q++ = ' ';
X		*q = '\0';
X		if ( ninline++ > 3 ) {
X			message(buff);
X			if ( nprinted++ > 4 ) {
X				message("Press any key to continue ...");
X				(void)getconsole();
X				clearmess();
X				nprinted = 0;
X			}
X			strcpy(buff,"  ");
X			ninline = 0;
X		}
X	}
X	if ( ninline > 0 )
X		message(buff);
X	closels();
X}
X
Xlibmouse()
X{
X	int row, col, q;
X
X	getmouse(&row,&col);
X	if(Nvoices < NUMONSCREEN)
X		q = Nvoices;
X	else
X		q = NUMONSCREEN;
X	if ( row <= FIRSTROW || row > FIRSTROW+q+1 )
X		goto getout;
X	if ( col < Cols/2 )
X		col = 0;
X	else
X		col = 1;
X	row = row - FIRSTROW - 1;
X	editto(row,col);
Xgetout:
X	/* wait until mouse button is released */
X	while ( statmouse() > 0 )
X		;
X}
X
Xdo_goto()
X{
X	int n, r, maxindex, new_ecol,q;
X	char sbuf[100], *sp;
X	
X	message("");
X	message("Where to? ");
X	windgets(sbuf);
X	
X	sp = sbuf;
X	switch(*sp++) {
X	  case 's': /* synth side */
X		new_ecol = 0;
X		break;
X	  case 'l': /* library side */
X		new_ecol = 1;
X		break;
X	  default: /* no change in side */
X	  	new_ecol = Editcol;
X		sp--;	/* but don't trash the first character */
X		break;
X	}
X	
X	clearmess();
X	r = sscanf(sp, "%d", &n); /* this may fail - we handle it later */
X	if(Cvtnum != NULL) { /* convert to internal format if needed */
X		n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
X	}
X	if (Cvtanum != NULL) { /* convert using alphanumeric voice number */
X		n = (*Cvtanum)(sp) + 1;
X		if (n) r = 1;
X	}
X	if(r != 1) {
X		message("type one of: sn, ln, or n");
X		message("  s = synth side (literal character 's')");
X		message("  l = library side (literal character 'l')");
X#ifdef KAWAIK1
X		message("  n = voice number to select (letter + number)");
X#else
X#ifdef KAWAIK5
X		message("  n = voice number to select (letter + number)");
X#else
X		message("  n = voice number to select (an integer)");
X#endif
X#endif
X		return;
X	}
X	if(n <= 0 || n > Nvoices) { /* 1-based */
X		message("Bad voice number!");
X		return;
X	}
X	
X	/* it can be done.  nuke the old '*' and change columes (if needed) */
X	editchar(' ', Editrow, Editcol);
X	Editcol = new_ecol;
X	
X	/* try to center it */
X	if(Nvoices < NUMONSCREEN)
X		q = Nvoices;
X	else
X		q = NUMONSCREEN;
X	maxindex = Nvoices - q;
X	if(Editcol == 0) {
X		Synindex = (n - 1) - q/2; /* 0-based */
X		if(Synindex < 0) { /* impossible to center */
X			Synindex = 0; /* so do your best */
X		} else if(Synindex > maxindex) {
X			Synindex = maxindex;
X		}
X		Editrow = (n - 1) - Synindex; /* and put a '*' on it */
X	} else {
X		Libindex = (n - 1) - q/2; /* 0-based */
X		if(Libindex < 0) {
X			Libindex = 0;
X		} else if(Libindex > maxindex) {
X			Libindex = maxindex;
X		}
X		Editrow = (n - 1) - Libindex;
X	}
X	
X	updatedisplay(); /* do the real work */
X	return;
X}
X
Xupload(data)
Xchar *data;
X{
X	int c, n;
X	char num[16];
X
X	message("");
X	if (synthoutfileflag) {
X		message("Upload to synth file:");
X		message("Output synth file --> ");
X		windgets(Syofname);
X		flushmidi();
X	}
X	else message("Upload TO synth:");
X	message("                 c - current voice");
X	message("                 a - ALL voices");
X	message("Choose --> ");
X	c = getconsole();
X	if ( c == 'c' ) {
X		clearmess();
X		if ( Sendone == NULL ) {
X			if (synthoutfileflag) (*Sendedit)(data);
X			else
X			message("Single voices can't be sent to that synth!");
X			return;
X		}
X		message("What voice number to you want to send it TO? --> ");
X		windgets(num);
X		clearmess();
X		n = atoi(num);
X		if(Cvtnum != NULL) { /* convert to internal format if needed */
X			n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
X		}
X		if (Cvtanum != NULL) { /* howzabout alphanumeric format? */
X			n = (*Cvtanum)(num) + 1;
X		}
X		if ( n > 0 && n <= Nvoices ) {
X			if ( (*Sendone)(n-1,data) != 0 ) { /* 0-based on calls -SAF */
X				message("Unable to write data to synth!");
X				(void)sprintf(Buff,"Reason: %s",Reason);
X				message(Buff);
X				return;
X			}
X		} else {
X			message("Bad voice number!");
X		}
X	}
X	else if ( c == 'a' ) {
X		clearmess();
X		if ( Sendbulk != NULL ) {
X			message("Uploading to synth using bulk routine.");
X			if ( (*Sendbulk)(Syndata) != 0 ) {
X				message("Upload failure!");
X				(void)sprintf(Buff,"Reason: %s\n",Reason);
X				message(Buff);
X				return;
X			}
X		} else {
X			message("Uploading to synth using single routine.");
X			for ( n=0; n<Nvoices; n++ ) {
X				if ( (*Sendone)(n, &(VOICEBYTE(Syndata,n,0)) ) != 0 ) {
X					message("Unable to write data to synth!");
X					(void)sprintf(Buff,"Reason: %s",Reason);
X					message(Buff);
X					return;
X				}
X			}
X		}
X		/* clearmess(); */
X	}
X	else {
X		clearmess();
X		message("Bad choice!");
X	}
X}
X
Xhelpmessage()
X{
Xclearmess();
X(void)sprintf(Buff,"%s,%s,%s,%s - move around              e - edit current voice",
X	STR_LEFT,STR_DOWN,STR_UP,STR_RIGHT);
Xmessage(Buff);
Xmessage("r - read voices from a file        y - yank into buffer");
Xmessage("w - write voices to a file         p - put from buffer");
Xmessage("b - cycle through library banks    s - swap current voice with yank buffer");
Xmessage("t - transfer all voices            f - list files in current directory");
Xmessage("d - download voices from synth     c - set MIDI channel");
Xmessage("u - upload voices to synth         g - 'goto' form of moving around");
Xmessage("q - quit                           <space> - play a note");
X}
X
Xupdatedisplay()
X{
X	if ( Editcol==0 ) {
X		/* we're on the synth side */
X		syntodisplay(Synindex);
X		editto(Editrow,Editcol);
X	}
X	else {
X		/* we're on the lib side */
X		libtodisplay(Libindex);
X		editto(Editrow,Editcol);
X	}
X}
X
Xpryankname()
X{
X	char ybuff[33];
X	char *p;
X
X	if ( Namesize == 0 )
X		return;
X
X	windgoto(YANKROW,YANKCOL-4);
X	windstr("                    ");
X	strcpy(ybuff,(*Nameof)(Yankdata));
X	/* take off trailing blanks */
X	p = ybuff + strlen(ybuff) - 1;
X	while ( p>ybuff && *p == ' ' )
X		*p-- = '\0';
X	windgoto(YANKROW,YANKCOL+7-strlen(ybuff)/2);
X	windstr(ybuff);
X	windrefresh();
X}
X
Xtranscmd()
X{
X	int fromc;
X
X	message("");
X	message("Transfer ALL voices:");
X	message("                       1:   <<-----   from library bank to synth bank");
X	message("                       2:   ----->>   from synth bank to library bank");
X	message("1 or 2 --> ");
X	fromc = getconsole();
X	windputc(fromc);
X	if ( fromc!='1' && fromc!='2' ) {
X		clearmess();
X		return;
X	}
X	switch ( fromc ) {
X	case '1':
X		copyall(bankvoice(0),Syndata);
X		syntodisplay(Synindex);
X		clearmess();
X		message("Use the 'u'pload command to actually send the synth bank voices to the synth.");
X		break;
X	case '2':
X		copyall(Syndata,bankvoice(0));
X		libtodisplay(Libindex);
X		clearmess();
X		break;
X	}
X}
X
Xcopyall(fromdata,todata)
Xchar *fromdata;
Xchar *todata;
X{
X	int n, v;
X
X	for ( v=0; v<Nvoices; v++ )
X		for ( n=0; n<Voicesize; n++ )
X			VOICEBYTE(todata,v,n) = VOICEBYTE(fromdata,v,n);
X}
X
Xmessage(s)
Xchar *s;
X{
X	windgoto(++Currrow,0);
X	windstr(s);
X	windrefresh();
X}
X
Xsetchan()
X{
X	int c;
X
X	message("New MIDI channel --> ");
X	windgets(Buff);
X	if ( (c=atoi(Buff)) <= 0 || c > 16 ) {
X		clearmess();
X		message("Invalid channel!");
X	}
X	else {
X		clearmess();
X		Channel = c;
X		showchan();
X	}
X}
X
Xshowchan()
X{
X	windgoto(20,31);
X	windstr("MIDI Channel: ");
X	(void)sprintf(Buff,"%d ",Channel);
X	windstr(Buff);
X	windrefresh();
X}
X
X#ifdef DX7
X#include <sys/types.h>
X#include <sys/stat.h>
Xlong flength(handle)
Xint handle;
X{
X  struct stat buf;
X  fstat(handle, &buf);
X  return buf.st_size;
X}
X#endif
X
X/* read data from a file, filling the current library bank. */
Xreadall()
X{
X	char fname[100];
X	FILE *f;
X	int v, n, r;
X	char *p;
X
X	message("File name --> ");
X	windgets(fname);
X#ifdef BSD
X	OPENBINFILE(f,fname,"r");
X#else
X	OPENBINFILE(f,fname,"rb");
X#endif
X	if (f == NULL ) {
X		(void)sprintf(Buff,"Can't open '%s'!",fname);
X		message(Buff);
X		return;
X	}
X	/* If the first byte matches DataID, then the format is OK. */
X	if (DataID) n = (getc(f) & 0xff);
X	else n = 0;
X
X#ifndef ROLANDD10
X# ifndef KAWAIIK1
X/* If we are running the Aztec C compiler, it's not yet ANSII.  The
X   abominable kludge that follows is therefore necessary.           */
X#  ifdef AZTEC_C
X#    ifdef DX7
X#     define SKIP_IT
X#    endif
X#    ifdef DX7S
X#     define SKIP_IT
X#    endif
X#    ifndef SKIP_IT
X	if (n != DataID && n <= 31) {
X		(void)ungetc(n,f);
X		n = DataID;
X	}
X#    endif
X#    undef SKIP_IT
X#  else
X#   if !defined(DX7) && !defined(DX7S)
X        if (n != DataID && n <= 31) {
X                (void)ungetc(n,f);
X                n = DataID;
X        }
X#   endif
X#  endif
X# endif
X#endif
X
X#ifdef DX7S
X
X/* check for reading a DX7 file in DX7s mode */
X
X        if ( strcmp(Synthname, "DX7s") == 0 )
X          if (flength(fileno(f)) == 4096) {
X            (void)ungetc(n, f);
X            dx7Sread_dx7(f, bankvoice(0));
X            r = 0;
X            goto done;
X          }
X
X/* check for reading a DX7S file in DX7 mode */
X
X          if ( strcmp(Synthname, "DX7") == 0 ) {
X            n = getc(f) & 0xff;
X            if (n == 0xd7) {	/* DX7s dataID */
X              dx7read_dx7S(f, bankvoice(0));
X              r = 0;
X              goto done;
X            }
X            (void)ungetc(n, f);
X            n = 0;
X          }
X#endif
X
X#ifdef DX7
X
X/* validate a DX7 file based on length */
X
X        if ( strcmp(Synthname, "DX7") == 0 ) {
X          if (flength(fileno(f)) != Nvoices * Voicesize)
X            n = DataID + 1;
X        }
X
X#endif
X
X	if ( n == DataID ) {
X		p = bankvoice(0);
X		for ( v=0; v<Nvoices; v++ ) {
X			for ( n=0; n<Voicesize; n++ )
X#ifdef CZ1
X				*p++ = getc(f);
X#else
X#ifdef CZ101
X				*p++ = getc(f);
X#else
X				*p++ = (getc(f) & 0x7f);
X#endif
X#endif
X		}
X		r = 0;
X	} else {
X		(void)sprintf(Buff, "'%s' is invalid for this function!\n", fname);
X		message(Buff);
X		r = 1;
X	}
X#ifdef DX7S
Xdone:
X#endif
X	(void)fclose(f);
X	if ( r==0 ) {
X		libtodisplay(Libindex=0);
X		clearmess();
X	}
X}
X
X/* read printable data from a textfile, filling the current library bank. */
Xreadprintable()
X{
X	char fname[100];
X	FILE *pfin;
X	int v, n, r, val;
X	char *p = NULL;
X	char vname[20];
X
X	message("File name --> ");
X	windgets(fname);
X#ifdef BSD
X	OPENBINFILE(pfin,fname,"r");
X#else
X	OPENBINFILE(pfin,fname,"rb");
X#endif
X	if (pfin == NULL ) {
X		(void)sprintf(Buff,"Can't open '%s'!",fname);
X		message(Buff);
X		return;
X	}
X	/* If the first byte matches DataID, then the format is OK. */
X	r = fscanf(pfin, "BANK TYPE %d", &n);
X
X	v = -1;
X	if ( r == 1 && n == DataID ) while (r) {
X	    r = fscanf(pfin, " %s ", vname);
X
X	    if (r == 1) {
X		if (strcmp(vname, "voice") == 0) {
X			if (v > 0) (*Dataout)(p);
X			r = fscanf(pfin,"%d = %[ !-~]", &v, vname);
X			if (r == 2 && v > 0) {
X			    p = bankvoice(v-1);
X			    (*Setnameof)(p, vname);
X			}
X		} else {
X			r = fscanf(pfin, "= %d", &val);
X			if (r == 1) setval(vname, val);
X		}
X	    }
X	    if (r == EOF) r = 0;
X	} else {
X		(void)sprintf(Buff, "'%s' is invalid for this function!\n", fname);
X		message(Buff);
X		r = 1;
X	}
X	if (v > 0) (*Dataout)(p);
X	(void)fclose(pfin);
X	if ( r==0 ) {
X		libtodisplay(Libindex=0);
X		clearmess();
X	}
X}
X
X/* write current library bank to a file */
Xwriteall()
X{
X	char fname[100];
X	FILE *f;
X	int v, n;
X	char *p;
X
X	message("File name --> ");
X	windgets(fname);
X#ifdef BSD
X	OPENBINFILE(f,fname,"w");
X#else
X	OPENBINFILE(f,fname,"wb");
X#endif
X	if ( f == NULL ) {
X		(void)sprintf(Buff,"Can't open '%s'!",fname);
X		message(Buff);
X		return;
X	}
X	if (DataID) putc(DataID,f);		/* write data identifier */
X
X	p = bankvoice(0);
X	for ( v=0; v<Nvoices; v++ ) {
X		for ( n=0; n<Voicesize; n++ )
X			putc(*p++,f);
X	}
X	(void)fclose(f);
X	clearmess();
X}
X
X
XFILE *pfout;
Xint pfoutflag = 0;
X
X/* write current library bank to a file in printable form */
Xwriteprintable()
X{
X	char fname[100];
X	int v;
X	char *p, *q;
X
X	message("File name --> ");
X	windgets(fname);
X#ifdef BSD
X	OPENBINFILE(pfout,fname,"w");
X#else
X	OPENBINFILE(pfout,fname,"wb");
X#endif
X	if ( pfout == NULL ) {
X		(void)sprintf(Buff,"Can't open '%s'!",fname);
X		message(Buff);
X		return;
X	}
X	fprintf(pfout, "BANK TYPE %d\n", DataID);
X
X	for (v=0; v<Nvoices; v++) {
X		p = bankvoice(v);
X		q = (*Nameof)(p);
X		if (q[0] > ' ') {
X			(*Datain)(p);
X			fprintf(pfout, "voice %d = %s\n", v+1, q);
X			pfoutflag = 1;
X			(*Dataout)(p);
X			pfoutflag = 0;
X		}
X	}
X	(void)fclose(pfout);
X	clearmess();
X}
X
X/* draw main library/synth voice bank screen */
Xdrawall()
X{
X	windclear();
X	template();
X	libtodisplay(Libindex);
X	syntodisplay(Synindex);
X	editto(Editrow,Editcol);
X	pryankname();
X	showchan();
X}
X
X/*
X * tosyn
X *
X * Store the given 'data' in in voice 'voicenum' (both in Syndata
X * AND on the synth itself).  If swap is non-zero, the voice is swapped
X * with the current voice in Syndata.
X */
X
Xtosyn(voicenum,data,swap)
Xchar *data;
X{
X	int n, t;
X
X	for ( n=0; n<Voicesize; n++ ) {
X		if ( swap ) {
X			t = VOICEBYTE(Syndata,voicenum,n);
X			VOICEBYTE(Syndata,voicenum,n) = data[n];
X			data[n] = t;
X		}
X		else
X			VOICEBYTE(Syndata,voicenum,n) = data[n];
X	}
X}
X
Xtolib(voicenum,data,swap)
Xchar *data;
X{
X	int n, t;
X	char *p = bankvoice(voicenum);
X
X	for ( n=0; n<Voicesize; n++ ) {
X		if ( swap ) {
X			t = *p;
X			*p = data[n];
X			data[n] = t;
X		}
X		else
X			*p = data[n];
X		p++;
X	}
X}
X
Xtocurrent(data,voicenum)
Xchar *data;
Xint voicenum;
X{
X	int n, f = 0;
X
X	for ( n=0; n<Voicesize; n++ )
X		if ( (Currdata[n] = VOICEBYTE(data,voicenum,n)) != 0) f = 1;
X	if( f == 1 && !synthoutfileflag) (*Sendedit)(Currdata);
X}
X
X/*
X * readsynth
X *
X * Read a bulk dump from the synth, with some tolerance for errors.
X */
Xreadsynth(data)
Xchar *data;
X{
X	if ( Getbulk == NULL ) {
X		message("That synth is unable to dump anything!!");
X		return(1);
X	}
X	if (synthinfileflag) {
X		message("Input synth file --> ");
X		windgets(Syinfname);
X		synthoutfileflag = 1;
X		flushmidi();
X		synthoutfileflag = 0;
X	}
X	else message("Downloading from synth");
X
X	if ( (*Getbulk)(data) == 0 )
X		return(0);
X
X	message("Unable to read data from synth!");
X	(void)sprintf(Buff,"Reason: %s",Reason);
X	message(Buff);
X	message("Perhaps connections are amiss?");
X	return(1);
X}
X
Xchar *
Xvnumtext(n)
X{
X	static char vnbuff[6];
X
X	if ( Numof == NULL ) {
X		(void)sprintf(vnbuff,"%2d",n);
X		return(vnbuff);
X	}
X	else
X		return((*Numof)(n - 1)); /* keep this 0-based */
X}
X
X/*
X * syntodisplay(n)
X *
X * Tranfer Syndata names to dialog boxes (Dxvoices) starting at n.
X */
Xsyntodisplay(n)
X{
X	int k, r, q;
X
X	if(Nvoices < NUMONSCREEN)
X		q = Nvoices;
X	else
X		q = NUMONSCREEN;
X	for ( k=0; k<q; k++ ) {
X		r = FIRSTROW+1+k;
X		windgoto(r,LEFTSIDE);
X		(void)sprintf(Buff,"%s |                 ",vnumtext(n+k+1));
X		windstr(Buff);
X		/* pull the name out of the Syndata */
X		if ( Namesize != 0 ) {
X			windgoto(r,LEFTSIDE+5);
X			windstr((*Nameof)( & (VOICEBYTE(Syndata,n+k,0) )) );
X		}
X	}
X	windrefresh();
X#ifdef KAWAIK1
X	synnames();
X#endif
X}
X
X#ifdef KAWAIK1
X/*
X * synnames()
X *
X * Tranfer Syndata names to array.
X */
Xsynnames()
X{	int i, k;
X	char *p, *q;
X
X	if (Nvoices != 64) return;
X
X	for ( k=0; k < 64; k++ ) {
X		p = (*Nameof)( & (VOICEBYTE(Syndata,k,0) ));
X		q = sngnames[k];
X		for (i=0; i < 10; i++) *q++ = *p++;
X		*q = 0;
X	}
X}
X#endif
X
X/*
X * libtodisplay
X *
X * Tranfer Libdata names to the screen, starting at voice 'firstv'.
X */
X
Xlibtodisplay(firstv)
X{
X	int k, r, q;
X
X	windgoto(FIRSTROW-1,RIGHTSIDE+2);
X	(void)sprintf(Buff,"Library (Bank %d)",Libbank+1);
X	windstr(Buff);
X
X	if(Nvoices < NUMONSCREEN)
X		q = Nvoices;
X	else
X		q = NUMONSCREEN;
X	for ( k=0; k<q; k++ ) {
X		r = FIRSTROW+1+k;
X		windgoto(r,RIGHTSIDE);
X		(void)sprintf(Buff,"%s |                 ",vnumtext(firstv+k+1));
X		windstr(Buff);
X		/* pull the name out of the Libdata */
X		if ( Namesize != 0 ) {
X			windgoto(r,RIGHTSIDE+5);
X			windstr((*Nameof)(bankvoice(firstv+k)));
X		}
X	}
X	windrefresh();
X}
X
Xallnotesoff()
X{
X	int n;
X
X	/* Go through all channels. */
X	for ( n=0; n<15; n++ ) {
X		sendmidi(n | 0xb0);
X		sendmidi(0x7b);
X		sendmidi(0x00);
X	}
X}
X
X/*
X * Below are generic edit routines, which manage a screen display
X * showing parameter values, and let you roam around and make changes.
X * The display is managed by the contents of the P array, which
X * contains the name, screen location, min/max values, etc. of
X * each parameter.
X */
X
Xint Prow = 0;
Xint Pcol = 0;
Xint Parm = 0;
X
X/* redraw the parameter screen */
Xshowallparms(name)
Xchar *name;
X{
X	int n;
X	char *s;
X
X	windclear();
X
X	if( Namesize != 0 ) {
X		showname(name);
X		windgoto(1,0);
X		for(n=strlen(name)+6;n>0;n--)
X			windputc('=');
X	}
X
X	/* The L array contains arbitrary screen labels */
X	for ( n=0; L[n].l_text != NULL; n++ ) {
X		windgoto(L[n].l_row,L[n].l_col);
X		windstr(L[n].l_text);
X	}
X	/* Display each parameter value, and a label if there is one. */
X	for ( n=0; P[n].p_name != NULL; n++ ) {
X		if ( P[n].p_flags != 0 )
X			continue;
X		if ( (s=P[n].p_label) != NULL )
X			showstr(s,P[n].p_lrow,P[n].p_lcol,0);
X		showparam(n,0);
X	}
X	windrefresh();
X}
X
Xshowname(name)
Xchar *name;
X{
X	windgoto(0,0);
X	windstr("Name:                 ");
X	windgoto(0,6);
X	windstr(name);
X}
X
Xshowparam(n,eras)
X{
X	char *p;
X
X	/* The p_tovis element of the P array is a function which, given */
X	/* the parameter value as an argument, returns a string which is */
X	/* what should be displayed on the screen. */
X#ifdef DX7
X        if (P[n].p_vrow < 0 || P[n].p_vcol < 0) return;
X	p = (*(P[n].p_tovis))(P[n].p_val, eras);
X#else
X	p = (*(P[n].p_tovis))(P[n].p_val);
X#endif
X	showstr(p,P[n].p_vrow,P[n].p_vcol,eras);
X}
X
X#ifdef DX7
X
X/*
X * define defaults for the graphics characters, if they haven't been specified
X * in machdep.
X */
X
X# ifndef DRAW_VERT
X#  define DRAW_VERT      '|'
X#  define DRAW_HORIZ     '-'
X#  define DRAW_CROSS     '+'
X#  define DRAW_UPTEE     '+'
X#  define DRAW_DOWNTEE   '+'
X#  define DRAW_LEFTTEE   '+'
X#  define DRAW_RIGHTTEE  '+'
X#  define DRAW_UPLEFT    '+'
X#  define DRAW_UPRIGHT   '+'
X#  define DRAW_DOWNLEFT  '+'
X#  define DRAW_DOWNRIGHT '+'
X# endif
X
Xshowstr(p,row,col,eras)
Xregister char *p;
Xregister int col;
X{
X  register int c;
X  int rept, mincol;
X
X  mincol = col;
X
X  windgoto(row,col);
X  while ( (c=(*p++)) != '\0' ) {
X    switch(c){
X      case '~':
X        c = *p++;
X        if (isdigit(c)) {
X          rept = 0;
X          while (isdigit(c)) {
X            rept = 10*rept + (c-'0');
X            c = *p++;
X          }
X        }
X        else
X          rept = 1;
X
X        while (rept--) {
X          switch( c ) {
X            case 'n': row++; col=mincol; goto wgoto;
X            case 'u': row--; goto wgoto;
X            case 'd': row++; goto wgoto;
X            case 'l': col--; if (col < mincol) mincol = col; goto wgoto;
X            case 'r': col++;
X              wgoto:
X                windgoto(row,col);
X                break;
X            case '|': c=DRAW_VERT;      goto wput;
X            case '-': c=DRAW_HORIZ;     goto wput;
X            case '+': c=DRAW_CROSS;     goto wput;
X            case 'T': c=DRAW_UPTEE;     goto wput;
X            case '^': c=DRAW_DOWNTEE;   goto wput;
X            case '<': c=DRAW_RIGHTTEE;  goto wput;
X            case '>': c=DRAW_LEFTTEE;   goto wput;
X            case '{': c=DRAW_UPLEFT;    goto wput;
X            case '}': c=DRAW_UPRIGHT;   goto wput;
X            case '[': c=DRAW_DOWNLEFT;  goto wput;
X            case ']': c=DRAW_DOWNRIGHT;
X              wput:
X                windputc(eras?' ':c);
X                col++;
X                break;
X            default:
X              windputc(eras?' ':c);
X              col++;
X              break;
X          }
X        }
X        break;
X      default:
X        windputc(eras?' ':c);
X        col++;
X        break;
X    }
X  }
X}
X
X#else  /* DX7 */
X
Xshowstr(p,row,col,eras)
Xregister char *p;
Xregister int col;
X{
X	register int c;
X
X	windgoto(row,col);
X	while ( (c=(*p++)) != '\0' ) {
X		switch(c){
X		case '~':
X			switch( (c=(*p++)) ) {
X			case 'u': row--; goto wgoto;
X			case 'd': row++; goto wgoto;
X			case 'l': col--; goto wgoto;
X			case 'r': col++;
X			    wgoto:
X				windgoto(row,col);
X				break;
X			default:
X				windputc(eras?' ':c);
X				col++;
X				break;
X			}
X			break;
X		default:
X			windputc(eras?' ':c);
X			col++;
X			break;
X		}
X	}
X}
X#endif
X
X/* Allow roaming around and changing of parameter values. */
Xeditdata(name,data)
Xchar *name;
Xchar *data;	/* vmem format */
X{
X	int c, n;
X
X	windclear();
X	windrefresh();
X	/* enable all the parameters */
X	for ( n=0; P[n].p_name != NULL; n++ )
X		enableparm(n);
X
X	/* Take the voice data and put it into P */
X	(*Datain)(data);
X
X	Prow = Pcol = 0;
X	Changed = 0;
X	Redraw = 1;
X	Lastvalue = 0;
X	gotoparm(CH_RIGHT);	/* Get to the first parameter */
X	for ( ;; ) {
X		if ( Redraw ) {
X			showallparms(name);
X			Redraw = 0;
X		}
X		windgoto(Prow,Pcol);
X		windrefresh();
X		c = mouseorkey();
X		if ( c == MOUSE ) {
X			editmouse();
X			continue;
X		}
X		switch(c){
X		case CH_RIGHT:
X		case ALTCH_RIGHT:
X		case CH_UP:
X		case ALTCH_UP:
X		case CH_DOWN:
X		case ALTCH_DOWN:
X		case CH_LEFT:
X		case ALTCH_LEFT:
X			gotoparm(c);
X			break;
X		case CH_SAME:
X			sameparm();
X			break;
X		case CH_REDRAW:
X			showallparms(name);
X			break;
X		case 'N':
X			if ( Namesize != 0 ) {
X			/* Allow changing of voice name */
X				windgoto(0,5);
X				windstr("                ");
X				windgoto(0,6);
X				windrefresh();
X				windgets(Buff);
X				if ( Buff[0]!='\0' && Buff[0]!='\n' )
X					(*Setnameof)(data,Buff);
X				showname(name=(*Nameof)(data));
X				Changed = 1;
X			}
X			break;
X
X		case CH_INC:
X			adjuparm(1);
X			break;
X		case CH_INC2:
X			adjuparm(4);
X			break;
X		case CH_INC3:
X			adjuparm(P[Parm].p_max - P[Parm].p_min);
X			break;
X		case CH_DEC:
X			adjuparm(-1);
X			break;
X		case CH_DEC2:
X			adjuparm(-4);
X			break;
X		case CH_DEC3:
X			adjuparm(P[Parm].p_min - P[Parm].p_max);
X			break;
X#ifdef OLDSTUFF
X		case 'a':
X			sendaced(data);
X			playnote(0);
X			break;
X#endif
X		case ' ':
X		case '\n':
X#ifndef macintosh
X		case '\r':
X#endif
X			if ( Changed ) {
X				(*Dataout)(data);
X				(*Sendedit)(data);
X				Changed = 0;
X			}
X			playnote(0);
X			break;
X		case '\033':
X		case '`':
X			allnotesoff();
X			break;
X		case 'q':
X		case EOF:
X			if ( Changed ) {
X				(*Dataout)(data);
X				(*Sendedit)(data);
X			}
X			return;
X		default:
X			break;
X		}
X	}
X}
X
Xadjuparm(incdec)
X{
X	int v, n;
X
X	v = P[Parm].p_val + incdec;
X	if ( v < (n=P[Parm].p_min) )
X		v = n;
X	if ( v > (n=P[Parm].p_max) )
X		v = n;
X	Lastvalue = v;
X	Changed = 1;
X	showparam(Parm,1);	/* erase the old val */
X	P[Parm].p_val = v;
X	showparam(Parm,0);	/* show the new val */
X}
X
Xsameparm()
X{
X	int v, n;
X
X	v = Lastvalue;
X	if ( v < (n=P[Parm].p_min) )
X		v = n;
X	if ( v > (n=P[Parm].p_max) )
X		v = n;
X	Changed = 1;
X	showparam(Parm,1);	/* erase the old val */
X	P[Parm].p_val = v;
X	showparam(Parm,0);	/* show the new val */
X}
X
Xeditmouse()
X{
X	int row, col, thisparm;
X
X	getmouse(&row,&col);
X	thisparm = closeparm(row,col);
X	if ( thisparm == Parm ) {
X		if ( statmouse() > 1 )
X			adjuparm(-1);	/* right button */
X		else if ( statmouse() == 1 ) /* added by mab - bug fix */
X			adjuparm(1);	/* left button */
X	}
X	else {
X		Parm = thisparm;
X		Prow = P[Parm].p_vrow;
X		Pcol = P[Parm].p_vcol;
X	}
X}
X
X/* closeparm - Find the closest parameter */
Xcloseparm(row,col)
X{
X	register struct paraminfo *pp;
X	register int n;
X	int dist, mindist, minparm, dr, dc;
X
X	minparm = 0;
X	mindist = Rows + Cols;
X	for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
X		if ( pp->p_flags != 0 )
X			continue;
X		if ( (dr=row-(pp->p_vrow)) < 0 )
X			dr = -dr;
X		if ( (dc=col-(pp->p_vcol)) < 0 )
X			dc = -dc;
X		if ( (dist=dr*dr+dc*dc) < mindist ) {
X			minparm = n;
X			mindist = dist;
X		}
X	}
X	return(minparm);
X}
X
X/* playnote - play the 'auto' note */
Xplaynote(i)
X{
X	int pitch, vol, dur, chan;
X	long endtime;
X
X	pitch = getval("autopitch");
X	if(i == 0) { /* called from inside edit-mode */
X		chan = getval("autochan");
X	} else { /* called from the top level */
X		chan = Channel;
X	}
X	vol = getval("autovol");
X	dur = getval("autodur");
X	endtime = milliclock() + dur * 100;
X	midinote(1,chan,pitch,vol);
X	while ( milliclock() < endtime )
X		;
X	midinote(0,chan,pitch,vol);
X}
X
X/* gotoparm - search for the next parameter in the specified direction */
Xgotoparm(dir)
X{
X	int n, k, inc, pm, orig, r = Prow, c = Pcol;
X
X	switch(dir) {
X	case ALTCH_UP:		dir = CH_UP;	break;
X	case ALTCH_DOWN:	dir = CH_DOWN;	break;
X	case ALTCH_LEFT:	dir = CH_LEFT;	break;
X	case ALTCH_RIGHT:	dir = CH_RIGHT;	break;
X	}
X
X	if ( dir==CH_LEFT || dir==CH_RIGHT ) {
X		if ( dir==CH_LEFT )
X			c--;
X		else
X			c++;
X		orig = c;
X		inc = 0;
X		pm = -1;
X		/* look up and down, alternately */
X		for ( n=2*Rows; n>0; n-- ) {
X			r += (pm * inc++);
X			pm = -pm;
X			if ( r < 0 || r >= Rows )
X				continue;
X			if ( dir == CH_LEFT ) {
X				for ( c=orig; c>=0; c-- ) {
X					if ( parmat(r,c) )
X						return;
X				}
X			}
X			else {
X				for ( c=orig; c<Cols; c++ ) {
X					if ( parmat(r,c) )
X						return;
X				}
X			}
X		}
X		return;
X	}
X	if ( dir==CH_DOWN || dir==CH_UP ) {
X		if ( dir==CH_DOWN )
X			r++;
X		else
X			r--;
X		orig = c;
X		while ( r >= 0 && r < Rows ) {
X			/* look toward both sides at the same time */
X			inc = 0;
X			pm = -1;
X			for ( k=2*Cols; k>0; k-- ) {
X				c += (pm * inc++);
X				pm = -pm;
X				if ( c < 0 || c >= Cols )
X					continue;
X				if ( parmat(r,c) )
X					return;
X			}
X			if ( dir==CH_DOWN )
X				r++;
X			else
X				r--;
X			c = orig;
X		}
X		return;
X	}
X}
X
X/* paramat - return non-zero if a parameter value is at position r,c */
Xparmat(r,c)
Xregister int r, c;
X{
X#ifdef SSS
X  int p = PARAMAT(r, c);
X
X  if (p == 0 || P[p-1].p_flags)
X    return 0;
X  else {
X    Parm = p-1;
X    Prow = r;
X    Pcol = c;
X    return 1;
X  }
X#else
X	register int n;
X	register struct paraminfo *pp;
X
X	for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
X		if ( pp->p_flags != 0 )
X			continue;
X		if ( pp->p_vrow==r && pp->p_vcol==c ) {
X			Prow = r;
X			Pcol = c;
X			Parm = n;
X			return(1);
X		}
X	}
X	return(0);
X#endif
X}
X
X/* parmindex - return index (in P) of a given parameter name. */
Xparmindex(name)
Xchar *name;
X{
X#ifdef SSS
X  struct paraminfo key, *p;
X  extern char *bsearch();
X
X  key.p_name = name;
X  p = (struct paraminfo *)bsearch((void *)&key, (void *)P, NParams,
X		sizeof(struct paraminfo), paramcmp);
X  if (p == 0) {
X    (void)sprintf(Buff,"HEY, PARMINDEX(%s) NOT FOUND!\n",name);
X    windstr(Buff);
X    windrefresh();
X    return(-1);
X  }
X  else
X    return p-P;
X#else
X	int n;
X	char *s;
X
X	for ( n=0; (s=P[n].p_name) != NULL; n++ ) {
X		if ( strcmp(s,name) == 0 )
X			return(n);
X	}
X	(void)sprintf(Buff,"HEY, PARMINDEX(%s) NOT FOUND!\n",name);
X	windstr(Buff);
X	windrefresh();
X	return(-1);
X#endif
X}
X
Xvoid
Xsetval(name,v)
XINT16 v;
Xchar *name;
X{
X	int n;
X
X	if ( (n=parmindex(name)) < 0 )
X		return;
X	P[n].p_val = v;
X}
X
Xint
Xgetval(name)
Xchar *name;
X{
X	int n;
X
X	if ( (n=parmindex(name)) < 0 )
X		return(0);
X
X	if (pfoutflag)
X		fprintf(pfout, "%s = %d\n", name, P[n].p_val);
X
X	return(P[n].p_val);
X}
X
X
Xenableparm(n)
X{
X	if ( P[n].p_flags != 0 )
X		P[n].p_flags = 0;
X}
X
Xdisableparm(n)
X{
X	if ( P[n].p_flags == 0 )
X		P[n].p_flags = 1;
X}
X
Xmidinote(onoff,chan,pitch,vol)
X{
X	sendmidi( ((onoff==1)?(0x90):(0x80)) | ((chan-1)&0xf) );
X	sendmidi( pitch & 0x7f );
X	sendmidi( vol & 0x7f );
X}
X
Xstatic char Nbuff[16];
X
Xchar *visnum(v)
X{
X	(void)sprintf(Nbuff,"%d",v);
X	return(Nbuff);
X}
Xchar *visonoff(v)
X{
X	if ( v==0 )
X		return("OFF");
X	else
X		return("ON ");
X}
X
Xchar *
Xbankvoice(voice)
X{
X	int offset = Libbank * Nvoices * Voicesize + voice * Voicesize;
X	return(Libdata + offset);
X}
END_OF_FILE
if test 41661 -ne `wc -c <'glib.c'`; then
    echo shar: \"'glib.c'\" unpacked with wrong size!
fi
# end of 'glib.c'
fi
echo shar: End of archive 15 \(of 15\).
cp /dev/null ark15isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 15 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0