[comp.sources.amiga] v89i073: glib - generic librarian/editor for synths, Part03/03

page@swan.ulowell.edu (Bob Page) (03/17/89)

Submitted-by: mab@druwy.att.com (Alan Bland)
Posting-number: Volume 89, Issue 73
Archive-name: audio/glib.3

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	glib.c
#	yama_com.c
# This archive created: Thu Mar 16 11:45:30 1989
cat << \SHAR_EOF > glib.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 */

#include "glib.h"
#include <ctype.h>

char *Reason = "";

int Currrow = 0;	/* at top of screen, for messages */
int Libbank = 0;	/* from 0 to LIBBANKS-1, is the current library bank*/
int Nsynths = 0;

char *Currdata;
char *Yankdata;		/* current 'yank' buffer (middle of screen) */

struct peredinfo *PE;	/* array of per-editor miscellany */

char Buff[BUFSIZ];
int Redraw = 0;		/* if non-0, edit screen is completely redrawn. */
			/* parameter functions can make use of this. */
int Changed = 0;

/* All the global values below are set as appropriate for the */
/* synthesizer currently being dealt with. */

int Nvoices = 0;
int Voicesize =0;
int Namesize = 0;
int Libindex;		/* from 0 to Nvoices-1 */
int Synindex;		/* from 0 to Nvoices-1 */
int Channel;
int Editrow;		/* from 0 to NUMONSCREEN-1 */
int Editcol;		/* 0==synth, 1==library */
char *Libdata;		/* current library data (includes all LIBBANKS) */
			/* ie. the stuff on the right side of the screen */
char *Syndata;		/* current synth data (1 bank), ie. the left side */
struct paraminfo *P;	/* list of parameter info */
struct labelinfo *L;	/* arbitrary screen labels for edit screen */
char *Synthname;

int (*Sendedit)();	/* function to send parameters to synth's edit buffer*/
int (*Datain)();	/* convert data from file-storage format to the */
			/* format stored in the P[] parameter array (p_val) */
int (*Dataout)();	/* reverse of Datain */
int (*Sendone)();	/* function to send one (permanent) voice to synth */
int (*Sendbulk)();	/* function to send bulk dump to synth */
int (*Getbulk)();	/* reverse of Sendbulk */
char *(*Nameof)();	/* pulls voice name out of file-storage data */
int (*Setnameof)();	/* reverse of Nameof */
char *(*Numof)();	/* convert voice number to on-screen text */
int (*Cvtnum)();	/* convert visible voice number to std. format */
int (*Cvtanum)();	/* convert alphanumeric voice number to std. format */
			/* should never define both Cvtnum and Cvtanum */
main()
{
	int n;

	hello();
	windinit();
	initstuff();

	if ( Nsynths == 0 )
		windstr("Hey, the E array is empty?");
	else if ( Nsynths == 1 ) {
		/* If there's only 1 synth, don't bother asking */
		setedit(0);
		libinteract();
	}
	else {
		while ( (n=choosesynth()) >= 0 ) {
			setedit(n);
			libinteract();
			unsetedit(n);
		}
	}
	bye();
}

/* choose a synth, returning its position in the E array */
choosesynth()
{
	int n, pick;

    retry:
	flushconsole();
	windclear();
	windgoto(2,18);
	windstr("GLIB - A Generic Librarian/Editor");

	for ( n=1; n<=Nsynths; n++ )
		libchoice(n);

	windgoto(10+n,16);
	windstr("Choose your synth (or 'q' to quit) --> ");
	windrefresh();
	pick = mouseorkey();
	if ( pick == 'q' || pick == EOF )
		return(-1);
	if ( pick != MOUSE )
		pick = pick - '0';
	else {
		int row, col;
		getmouse(&row,&col);
		/* wait until mouse goes down */
		while ( statmouse() > 0 )
			;
		pick = row - 6; 
	}
	if ( pick < 1 || pick > Nsynths )
		goto retry;
	return(pick-1);
}

libchoice(n)
{
	windgoto(6+n,27);
	sprintf(Buff,"%d  -  %s",n,E[n-1].ed_name);
	windstr(Buff);
}

initstuff()
{
	int n, banksize, maxvsize = 0;
	char *p;
	
	for ( n=0; E[n].ed_name != NULL; n++ ) {
		if ( maxvsize < E[n].ed_vsize )
			maxvsize = E[n].ed_vsize;
	}
	Nsynths = n;
	Currdata = alloc( maxvsize );

	/* allocate an array of peredinfo structs */
	PE =(struct peredinfo *)alloc((int)(Nsynths*sizeof(struct peredinfo)));
	for ( n=0; n<Nsynths; n++ ) {
		banksize =  E[n].ed_nvoices * E[n].ed_vsize;
		p = PE[n].ed_libdata = alloc( LIBBANKS * banksize );
		clrdata(p,LIBBANKS*banksize);
		p = PE[n].ed_syndata = alloc( banksize );
		clrdata(p,banksize);
		p = PE[n].ed_yankdata = alloc( E[n].ed_vsize );
		clrdata(p,E[n].ed_vsize);
		PE[n].ed_libindex = 0;
		PE[n].ed_synindex = 0;
		PE[n].ed_channel = 1;
		PE[n].ed_erow = 0;
		PE[n].ed_ecol = 0;
	}
}

clrdata(data,size)
char *data;
{
	register char *p = data, *endp = data+size;

	while ( p<endp )
		*p++ = 0;
}

setedit(n)
{
	Synthname = E[n].ed_name;
	Datain = E[n].ed_din;
	Dataout = E[n].ed_dout;
	Nvoices = E[n].ed_nvoices;
	Sendedit = E[n].ed_sedit;
	Sendone = E[n].ed_sone;
	Sendbulk = E[n].ed_sbulk;
	Getbulk = E[n].ed_gbulk;
	Nameof = E[n].ed_nof;
	Numof = E[n].ed_numof;
	Cvtnum = E[n].ed_cvtnum;
	Cvtanum = E[n].ed_cvtanum;
	Setnameof = E[n].ed_snof;
	Voicesize = E[n].ed_vsize;
	Namesize = E[n].ed_nsize;
	Libdata = PE[n].ed_libdata;
	Syndata = PE[n].ed_syndata;
	Yankdata = PE[n].ed_yankdata;
	Libindex = PE[n].ed_libindex;
	Synindex = PE[n].ed_synindex;
	Channel = PE[n].ed_channel;
	Editrow = PE[n].ed_erow;
	Editcol = PE[n].ed_ecol;
	clrdata(Currdata,Voicesize);
	P = E[n].ed_params;
	L = E[n].ed_labels;
}

unsetedit(n)
{
	int k;

	PE[n].ed_libindex = Libindex;
	PE[n].ed_synindex = Synindex;
	PE[n].ed_channel = Channel;
	PE[n].ed_erow = Editrow;
	PE[n].ed_ecol = Editcol;
	for ( k=0; k<Voicesize; k++ )
		PE[n].ed_yankdata[k] = Yankdata[k];
}

/* template - show the boxes and such on the main library screen */
template()
{
	int n, k, r;

	r = FIRSTROW-1;
	sprintf(Buff,"%s Voices",Synthname);
	n = 13 - strlen(Buff)/2;	/* center it */
	windgoto(r,n<0?0:n);
	windstr(Buff);
	r++;
	windgoto(r,0);
	for ( n=0; n<26; n++ )
		windputc('=');
	windgoto(r,52);
	for ( n=0; n<26; n++ )
		windputc('=');
	for ( n=r+1; n<(r+13); n++ ) {
		windgoto(n,0);
		windputc('|');
		windgoto(n,6);
		windputc('|');
		windgoto(n,25);
		windputc('|');

		k=52;
		windgoto(n,k);
		windputc('|');
		windgoto(n,k+6);
		windputc('|');
		windgoto(n,k+25);
		windputc('|');
	}
	windgoto(r+13,0);
	for ( n=0; n<26; n++ )
		windputc('=');
	windgoto(r+13,52);
	for ( n=0; n<26; n++ )
		windputc('=');

	windgoto(YANKROW-2,YANKCOL);
	windstr("  Yank Buffer");
	windgoto(YANKROW-1,YANKCOL);
	windstr(" ------------- ");
	windgoto(YANKROW,YANKCOL);
	windstr("               ");
	windgoto(YANKROW+1,YANKCOL);
	windstr(" ------------- ");
	windrefresh();
}

/* clear the message area */
clearmess()
{
	int n;
	for(n=1;n<(FIRSTROW-1);n++)
		winderaserow(n);
	Currrow = 0;
}

/* set the current voice (ie. the synth's edit buffer) to the indicated */
/* voice.  c==0 is the synth (left) side, c==1 is the library (right) side. */
editto(r,c)
{
	int voicenum;

	/* Clear the existing '*' */
	editchar(' ',Editrow,Editcol);
	editchar('*',Editrow=r,Editcol=c);
	if ( Editcol==0 ) {
		/* we're on the synth side */
		voicenum = Editrow+Synindex;
		tocurrent(Syndata,voicenum);
	}
	else {
		/* we're on the lib side */
		voicenum = Editrow+Libindex;
		tocurrent(bankvoice(0),voicenum);
	}
}

editchar(ec,r,c)
{
	r = r + FIRSTROW + 1;
	if ( c == 0 )
		c = LEFTSIDE-1;
	else
		c = RIGHTSIDE-1;
	windgoto(r,c);
	windputc(ec);
	windrefresh();
}

/* control interaction on the main library bank screen */
libinteract()
{
	int c, n, swap, voicenum, maxindex;
	char *p, *data;

	flushmidi();
	drawall();
	for ( ;; ) {
		Currrow = 0;
		winderaserow(Currrow);
		windgoto(Currrow,0);
		windstr("Command --> ");
		windrefresh();
		
		c = mouseorkey();
		if ( c == MOUSE ) {
			libmouse();
			continue;
		}

		if ( isprint(c) )
			windputc(c);
		clearmess();
		switch ( c ) {
		case ' ':
			playnote(1);
			break;
		case '\n':
#ifndef macintosh
		case '\r':
#endif
			/* ignore */
			break;
		case EOF:
		case 'q':
			return;
		case CH_REDRAW:
			drawall();
			break;
		case 's':
		case 'p':
			swap = (c=='s')?1:0;
			if ( Editcol==0 )
				tosyn(Synindex+Editrow,Yankdata,swap);
			else
				tolib(Libindex+Editrow,Yankdata,swap);
			updatedisplay();
			pryankname();
			break;
		case 'y':
			for(n=0;n<Voicesize;n++)
				Yankdata[n] = Currdata[n];
			pryankname();
			break;
		case '?':
			helpmessage();
			break;
		case SCR_DOWN:
			maxindex = Nvoices - NUMONSCREEN;
			if ( Editcol==0 ) {
				/* we're on the synth side */
				if ( (Synindex+=NUMONSCREEN/2) > maxindex )
					Synindex = maxindex;
			}
			else {
				/* we're on the lib side */
				if ( (Libindex+=NUMONSCREEN/2) > maxindex )
					Libindex = maxindex;
			}
			updatedisplay();
			break;
		case SCR_UP:
			if ( Editcol==0 ) {
				/* we're on the synth side */
				if ( (Synindex-=NUMONSCREEN/2) < 0 )
					Synindex = 0;
			}
			else {
				/* we're on the lib side */
				if ( (Libindex-=NUMONSCREEN/2) < 0 )
					Libindex = 0;
			}
			updatedisplay();
			break;
		case '\033':
		case '`':
			allnotesoff();
			break;
		case 't':
			transcmd();
			break;
		case 'd':	/* download from synth to display */
			clrdata(Syndata,Nvoices*Voicesize);
			if ( readsynth(Syndata) == 0 )
				syntodisplay(Synindex=0);
			break;
		case 'u':	/* upload TO synth */
			if ( Editcol==0 ) {
				voicenum = Editrow+Synindex;
				data = &(VOICEBYTE(Syndata,voicenum,0));
			}
			else
				data = bankvoice(Editrow+Libindex);
			upload(data);
			break;
		case 'r':
			readall();
			break;
		case 'w':
			writeall();
			break;
		case 'c':
			setchan();
			break;
		case 'b':
			/* cycle through banks, from 0 to LIBBANKS-1 */
			if ( ++Libbank >= LIBBANKS )
				Libbank = 0;
			libtodisplay(Libindex);
			updatedisplay();
			break;
		case 'e':
			p = (*Nameof)(Currdata);
			if ( Editcol==0 ) {
				voicenum = Editrow+Synindex;
				data = &(VOICEBYTE(Syndata,voicenum,0));
				editdata(p,data);
				windclear();
				/* Update Currdata */
				for ( n=0; n<Voicesize; n++ )
				    Currdata[n] = VOICEBYTE(Syndata,voicenum,n);
			}
			else {
				data = bankvoice(Editrow+Libindex);
				editdata(p,data);
			}
			drawall();
			break;
		case 'g': /* goto a specific voice */
			do_goto();
			break;
		case CH_LEFT:
			if ( Editcol==1 )
				editto(Editrow,0);
			break;
		case CH_DOWN:
			if ( Editrow < (NUMONSCREEN-1) )
				editto(Editrow+1,Editcol);
			else {
				/* we're at the bottom, so try to scroll */
				if ( Editcol==0 ) {
					/* we're on the synth side */
					if (Synindex<(Nvoices-NUMONSCREEN))
						Synindex++;
				}
				else {
					/* we're on the lib side */
					if (Libindex<(Nvoices-NUMONSCREEN))
						Libindex++;
				}
				updatedisplay();
			}
			break;
		case CH_UP:
			if ( Editrow>0 )
				editto(Editrow-1,Editcol);
			else {
				/* we're at the top, so try to scroll */
				if ( Editcol==0 ) {
					/* we're on the synth side */
					if (Synindex>0)
						Synindex--;
				}
				else {
					/* we're on the lib side */
					if (Libindex>0)
						Libindex--;
				}
				updatedisplay();
			}	
			break;
		case CH_RIGHT:
			if ( Editcol==0 )
				editto(Editrow,1);
			break;
		case 'f':
			filelist();
			break;
		default:
			message("Unrecognized command!  Press '?' for help.");
			break;
		}
	}
}

filelist()
{
	char *p, *q, buff[BUFSIZ];
	int n, ninline = 0, nprinted = 0;

	clearmess();
	Currrow = -1;	/* To start message on top line */
	openls();
	message("Files in current directory:");
	strcpy(buff,"  ");
	while ( (p=nextls()) != NULL ) {
		/* add the next file to the line being constructed */
		q = &buff[strlen(buff)];
		strcpy(q,p);
		q += (n=strlen(p));
		while ( n++ < 15 )
			*q++ = ' ';
		*q = '\0';
		if ( ninline++ > 3 ) {
			message(buff);
			if ( nprinted++ > 4 ) {
				message("Press any key to continue ...");
				getconsole();
				clearmess();
				nprinted = 0;
			}
			strcpy(buff,"  ");
			ninline = 0;
		}
	}
	if ( ninline > 0 )
		message(buff);
	closels();
}

libmouse()
{
	int row, col;

	getmouse(&row,&col);
	if ( row <= FIRSTROW || row > FIRSTROW+NUMONSCREEN+1 )
		goto getout;
	if ( col < Cols/2 )
		col = 0;
	else
		col = 1;
	row = row - FIRSTROW - 1;
	editto(row,col);
getout:
	/* wait until mouse button is released */
	while ( statmouse() > 0 )
		;
}

do_goto()
{
	int n, r, maxindex, new_ecol;
	char sbuf[100], *sp;
	
	message("");
	message("Where to? ");
	windgets(sbuf);
	
	sp = sbuf;
	switch(*sp++) {
	  case 's': /* synth side */
		new_ecol = 0;
		break;
	  case 'l': /* library side */
		new_ecol = 1;
		break;
	  default: /* no change in side */
	  	new_ecol = Editcol;
		sp--;	/* but don't trash the first character */
		break;
	}
	
	clearmess();
	r = sscanf(sp, "%d", &n); /* this may fail - we handle it later */
	if(Cvtnum != NULL) { /* convert to internal format if needed */
		n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
	}
	if (Cvtanum != NULL) { /* convert using alphanumeric voice number */
		n = (*Cvtanum)(sp) + 1;
	}
	if(r != 1) {
		message("type one of: sn, ln, or n");
		message("  s = synth side (literal character 's')");
		message("  l = library side (literal character 'l')");
		message("  n = voice number to select (an integer)");
		return;
	}
	if(n <= 0 || n > Nvoices) { /* 1-based */
		message("Bad voice number!");
		return;
	}
	
	/* it can be done.  nuke the old '*' and change columes (if needed) */
	editchar(' ', Editrow, Editcol);
	Editcol = new_ecol;
	
	/* try to center it */
	maxindex = Nvoices - NUMONSCREEN;
	if(Editcol == 0) {
		Synindex = (n - 1) - NUMONSCREEN/2; /* 0-based */
		if(Synindex < 0) { /* impossible to center */
			Synindex = 0; /* so do your best */
		} else if(Synindex > maxindex) {
			Synindex = maxindex;
		}
		Editrow = (n - 1) - Synindex; /* and put a '*' on it */
	} else {
		Libindex = (n - 1) - NUMONSCREEN/2; /* 0-based */
		if(Libindex < 0) {
			Libindex = 0;
		} else if(Libindex > maxindex) {
			Libindex = maxindex;
		}
		Editrow = (n - 1) - Libindex;
	}
	
	updatedisplay(); /* do the real work */
	return;
}

upload(data)
char *data;
{
	int c, n;
	char num[16];

	message("");
	message("Upload TO synth:");
	message("                 c - current voice");
	message("                 a - ALL voices");
	message("Choose --> ");
	c = getconsole();
	if ( c == 'c' ) {
		clearmess();
		if ( Sendone == NULL ) {
			message("Single voices can't be sent to that synth!");
			return;
		}
		message("What voice number to you want to send it TO? --> ");
		windgets(num);
		clearmess();
		n = atoi(num);
		if(Cvtnum != NULL) { /* convert to internal format if needed */
			n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
		}
		if (Cvtanum != NULL) { /* howzabout alphanumeric format? */
			n = (*Cvtanum)(num) + 1;
		}
		if ( n > 0 && n <= Nvoices ) {
			if ( (*Sendone)(n-1,data) != 0 ) { /* 0-based on calls -SAF */
				message("Unable to write data to synth!");
				sprintf(Buff,"Reason: %s",Reason);
				message(Buff);
			}
		} else {
			message("Bad voice number!");
		}
	}
	else if ( c == 'a' ) {
		clearmess();
		if ( Sendbulk != NULL )
			(*Sendbulk)(Syndata);
		else {
			for ( n=0; n<Nvoices; n++ ) {
				if ( (*Sendone)(n, &(VOICEBYTE(Syndata,n,0)) ) != 0 ) {
					message("Unable to write data to synth!");
					sprintf(Buff,"Reason: %s",Reason);
					message(Buff);
					break;
				}
			}
		}
		/* clearmess(); */
	}
	else {
		clearmess();
		message("Bad choice!");
	}
}

helpmessage()
{
clearmess();
sprintf(Buff,"%s,%s,%s,%s - move around              e - edit current voice",
	STR_LEFT,STR_DOWN,STR_UP,STR_RIGHT);
message(Buff);
message("r - read voices from a file        y - yank into buffer");
message("w - write voices to a file         p - put from buffer");
message("b - cycle through library banks    s - swap current voice with yank buffer");
message("t - transfer all voices            f - list files in current directory");
message("d - download voices from synth     c - set MIDI channel");
message("u - upload voices to synth         g - 'goto' form of moving around");
message("q - quit                           <space> - play a note");
}

updatedisplay()
{
	if ( Editcol==0 ) {
		/* we're on the synth side */
		syntodisplay(Synindex);
		editto(Editrow,Editcol);
	}
	else {
		/* we're on the lib side */
		libtodisplay(Libindex);
		editto(Editrow,Editcol);
	}
}

pryankname()
{
	char ybuff[33];
	char *p;

	windgoto(YANKROW,YANKCOL-4);
	windstr("                    ");
	strcpy(ybuff,(*Nameof)(Yankdata));
	/* take off trailing blanks */
	p = ybuff + strlen(ybuff) - 1;
	while ( p>ybuff && *p == ' ' )
		*p-- = '\0';
	windgoto(YANKROW,YANKCOL+7-strlen(ybuff)/2);
	windstr(ybuff);
	windrefresh();
}

transcmd()
{
	int fromc;

	message("");
	message("Transfer ALL voices:");
	message("                       1:   <<-----   from library bank to synth bank");
	message("                       2:   ----->>   from synth bank to library bank");
	message("1 or 2 --> ");
	fromc = getconsole();
	windputc(fromc);
	if ( fromc!='1' && fromc!='2' ) {
		clearmess();
		return;
	}
	switch ( fromc ) {
	case '1':
		copyall(bankvoice(0),Syndata);
		syntodisplay(Synindex);
		clearmess();
		message("Use the 'u'pload command to actually send the synth bank voices to the synth.");
		break;
	case '2':
		copyall(Syndata,bankvoice(0));
		libtodisplay(Libindex);
		clearmess();
		break;
	}
}

copyall(fromdata,todata)
char *fromdata;
char *todata;
{
	int n, v;

	for ( v=0; v<Nvoices; v++ )
		for ( n=0; n<Voicesize; n++ )
			VOICEBYTE(todata,v,n) = VOICEBYTE(fromdata,v,n);
}

message(s)
char *s;
{
	windgoto(++Currrow,0);
	windstr(s);
	windrefresh();
}

setchan()
{
	int c;

	message("New MIDI channel --> ");
	windgets(Buff);
	if ( (c=atoi(Buff)) <= 0 || c > 16 ) {
		clearmess();
		message("Invalid channel!");
	}
	else {
		clearmess();
		Channel = c;
		showchan();
	}
}

showchan()
{
	windgoto(20,31);
	windstr("MIDI Channel: ");
	sprintf(Buff,"%d ",Channel);
	windstr(Buff);
	windrefresh();
}

/* read data from a file, filling the current library bank. */
readall()
{
	char fname[100];
	FILE *f;
	int v, n, r;

	message("File name --> ");
	windgets(fname);
	OPENBINFILE(f,fname,"r");
	if (f == NULL ) {
		sprintf(Buff,"Can't open '%s'!",fname);
		message(Buff);
		return;
	}
	/* Check the first byte.  If it's 0xdd, then the format is mine. */
	/* If the first byte is 0-31, it's also mine. */
	n = (getc(f) & 0xff);
	if ( n == 0xdd || n<=31 ) {
		if ( n <= 31 )
			ungetc(n,f);
		/* This is my format, just raw data. */
		for ( v=0; v<Nvoices; v++ ) {
			char *p = bankvoice(v);
			for ( n=0; n<Voicesize; n++ )
				*p++ = getc(f);
		}
		r = 0;
	}
	/* code for other formats would go here */
	else {
		message("Unknown file format");
		r = 1;
	}
	fclose(f);
	if ( r==0 ) {
		libtodisplay(Libindex=0);
		clearmess();
	}
}

/* write current library bank to a file */
writeall()
{
	char fname[100];
	FILE *f;
	int v, n;

	message("File name --> ");
	windgets(fname);
	OPENBINFILE(f,fname,"w");
	if ( f == NULL ) {
		sprintf(Buff,"Can't open '%s'!",fname);
		message(Buff);
		return;
	}
	putc(0xdd,f);	/* magic byte to identify my format */
	for ( v=0; v<Nvoices; v++ ) {
		char *p = bankvoice(v);
		for ( n=0; n<Voicesize; n++ )
			putc(*p++,f);
	}
	fclose(f);
	clearmess();
}

/* draw main library/synth voice bank screen */
drawall()
{
	windclear();
	template();
	libtodisplay(Libindex);
	syntodisplay(Synindex);
	editto(Editrow,Editcol);
	pryankname();
	showchan();
}

/*
 * tosyn
 *
 * Store the given 'data' in in voice 'voicenum' (both in Syndata
 * AND on the synth itself).  If swap is non-zero, the voice is swapped
 * with the current voice in Syndata.
 */

tosyn(voicenum,data,swap)
char *data;
{
	int n, t;

	for ( n=0; n<Voicesize; n++ ) {
		if ( swap ) {
			t = VOICEBYTE(Syndata,voicenum,n);
			VOICEBYTE(Syndata,voicenum,n) = data[n];
			data[n] = t;
		}
		else
			VOICEBYTE(Syndata,voicenum,n) = data[n];
	}
}

tolib(voicenum,data,swap)
char *data;
{
	int n, t;
	char *p = bankvoice(voicenum);

	for ( n=0; n<Voicesize; n++ ) {
		if ( swap ) {
			t = *p;
			*p = data[n];
			data[n] = t;
		}
		else
			*p = data[n];
		p++;
	}
}

tocurrent(data,voicenum)
char *data;
int voicenum;
{
	int n;

	for ( n=0; n<Voicesize; n++ )
		Currdata[n] = VOICEBYTE(data,voicenum,n);
	(*Sendedit)(Currdata);
}

/*
 * readsynth
 *
 * Read a bulk dump from the synth, with some tolerance for errors.
 */
readsynth(data)
char *data;
{
	if ( Getbulk == NULL ) {
		message("That synth is unable to dump anything!!");
		return(1);
	}
	message("Trying to download data from synth...");
	if ( (*Getbulk)(data) == 0 ) {
		clearmess();
		return(0);
	}
	message("Unable to read data from synth!");
	sprintf(Buff,"Reason: %s",Reason);
	message(Buff);
	message("Perhaps connections are amiss?");
	return(1);
}

char *
vnumtext(n)
{
	static char vnbuff[6];

	if ( Numof == NULL ) {
		sprintf(vnbuff,"%2d",n);
		return(vnbuff);
	}
	else
		return((*Numof)(n - 1)); /* keep this 0-based */
}

/*
 * syntodisplay(n)
 *
 * Tranfer Syndata names to dialog boxes (Dxvoices) starting at n.
 */
syntodisplay(n)
{
	int k, r;

	/* for the NUMONSCREEN dialog boxes */
	for ( k=0; k<NUMONSCREEN; k++ ) {
		r = FIRSTROW+1+k;
		windgoto(r,LEFTSIDE);
		sprintf(Buff,"%-3s",vnumtext(n+k+1));
		windstr(Buff);
		windgoto(r,LEFTSIDE+6);
		windstr("                 ");

		/* pull the name out of the Syndata */
		windgoto(r,LEFTSIDE+6);
		windstr((*Nameof)( & (VOICEBYTE(Syndata,n+k,0) )) );
	}
	windrefresh();
}

/*
 * libtodisplay
 *
 * Tranfer Libdata names to the screen, starting at voice 'firstv'.
 */

libtodisplay(firstv)
{
	int k, r;

	windgoto(FIRSTROW-1,RIGHTSIDE-1);
	sprintf(Buff,"Library Voices (Bank %d)",Libbank+1);
	windstr(Buff);

	/* for the NUMONSCREEN dialog boxes */
	for ( k=0; k<NUMONSCREEN; k++ ) {
		r = FIRSTROW+1+k;
		windgoto(r,RIGHTSIDE);
		sprintf(Buff,"%-3s",vnumtext(firstv+k+1));
		windstr(Buff);
		windgoto(r,RIGHTSIDE+6);
		windstr("                 ");

		/* pull the name out of the Libdata */
		windgoto(r,RIGHTSIDE+6);
		windstr((*Nameof)(bankvoice(firstv+k)));
	}
	windrefresh();
}

allnotesoff()
{
	int n;

	/* Go through all channels. */
	for ( n=0; n<15; n++ ) {
		sendmidi(n | 0xb0);
		sendmidi(0x7b);
		sendmidi(0x00);
	}
}

/*
 * Below are generic edit routines, which manage a screen display
 * showing parameter values, and let you roam around and make changes.
 * The display is managed by the contents of the P array, which
 * contains the name, screen location, min/max values, etc. of
 * each parameter.
 */

int Prow = 0;
int Pcol = 0;
int Parm = 0;

/* redraw the parameter screen */
showallparms(name)
char *name;
{
	int n;
	char *s;

	windclear();

	showname(name);
	windgoto(1,0);
	for(n=strlen(name)+6;n>0;n--)
		windputc('=');

	/* The L array contains arbitrary screen labels */
	for ( n=0; L[n].l_text != NULL; n++ ) {
		windgoto(L[n].l_row,L[n].l_col);
		windstr(L[n].l_text);
	}
	/* Display each parameter value, and a label if there is one. */
	for ( n=0; P[n].p_name != NULL; n++ ) {
		if ( P[n].p_flags != 0 )
			continue;
		if ( (s=P[n].p_label) != NULL )
			showstr(s,P[n].p_lrow,P[n].p_lcol,0);
		showparam(n,0);
	}
	windrefresh();
}

showname(name)
char *name;
{
	windgoto(0,0);
	windstr("Name:                 ");
	windgoto(0,6);
	windstr(name);
}

showparam(n,eras)
{
	char *p;

	/* The p_tovis element of the P array is a function which, given */
	/* the parameter value as an argument, returns a string which is */
	/* what should be displayed on the screen. */
	p = (*(P[n].p_tovis))(P[n].p_val);
	showstr(p,P[n].p_vrow,P[n].p_vcol,eras);
}

showstr(p,row,col,eras)
register char *p;
register int col;
{
	register int c;

	windgoto(row,col);
	while ( (c=(*p++)) != '\0' ) {
		switch(c){
		case '~':
			switch( (c=(*p++)) ) {
			case 'u': row--; goto wgoto;
			case 'd': row++; goto wgoto;
			case 'l': col--; goto wgoto;
			case 'r': col++;
			    wgoto:
				windgoto(row,col);
				break;
			default:
				windputc(eras?' ':c);
				col++;
				break;
			}
			break;
		default:
			windputc(eras?' ':c);
			col++;
			break;
		}
	}
}

/* Allow roaming around and changing of parameter values. */
editdata(name,data)
char *name;
char *data;	/* vmem format */
{
	int c, n;

	windclear();
	windrefresh();
	/* enable all the parameters */
	for ( n=0; P[n].p_name != NULL; n++ )
		enableparm(n);

	/* Take the voice data and put it into P */
	(*Datain)(data);

	Prow = Pcol = 0;
	Changed = 0;
	Redraw = 1;
	gotoparm(CH_RIGHT);	/* Get to the first parameter */
	for ( ;; ) {
		if ( Redraw ) {
			showallparms(name);
			Redraw = 0;
		}
		windgoto(Prow,Pcol);
		windrefresh();
		c = mouseorkey();
		if ( c == MOUSE ) {
			editmouse();
			continue;
		}
		switch(c){
		case CH_RIGHT:
		case CH_UP:
		case CH_DOWN:
		case CH_LEFT:
			gotoparm(c);
			break;
		case CH_REDRAW:
			showallparms(name);
			break;
		case 'N':
			/* Allow changing of voice name */
			windgoto(0,5);
			windstr("                ");
			windgoto(0,6);
			windrefresh();
			windgets(Buff);
			if ( Buff[0]!='\0' && Buff[0]!='\n' )
				(*Setnameof)(data,Buff);
			showname(name=(*Nameof)(data));
			Changed = 1;
			break;

		case CH_INC:
			adjuparm(1);
			break;
		case CH_INC2:
			adjuparm(4);
			break;
		case CH_INC3:
			adjuparm(P[Parm].p_max - P[Parm].p_min);
			break;
		case CH_DEC:
			adjuparm(-1);
			break;
		case CH_DEC2:
			adjuparm(-4);
			break;
		case CH_DEC3:
			adjuparm(P[Parm].p_min - P[Parm].p_max);
			break;
#ifdef OLDSTUFF
		case 'a':
			sendaced(data);
			playnote(0);
			break;
#endif
		case ' ':
		case '\n':
#ifndef macintosh
		case '\r':
#endif
			if ( Changed ) {
				(*Dataout)(data);
				(*Sendedit)(data);
			}
			playnote(0);
			break;
		case '\033':
		case '`':
			allnotesoff();
			break;
		case 'q':
		case EOF:
			if ( Changed ) {
				(*Dataout)(data);
				(*Sendedit)(data);
			}
			return;
		default:
			break;
		}
	}
}

adjuparm(incdec)
{
	int v, n;

	v = P[Parm].p_val + incdec;
	if ( v < (n=P[Parm].p_min) )
		v = n;
	if ( v > (n=P[Parm].p_max) )
		v = n;
	Changed = 1;
	showparam(Parm,1);	/* erase the old val */
	P[Parm].p_val = v;
	showparam(Parm,0);	/* show the new val */
}

editmouse()
{
	int row, col, thisparm;

	getmouse(&row,&col);
	thisparm = closeparm(row,col);
	if ( thisparm == Parm ) {
		if ( statmouse() > 1 )
			adjuparm(-1);	/* right button */
		else if ( statmouse() == 1 ) /* added by mab - bug fix */
			adjuparm(1);	/* left button */
	}
	else {
		Parm = thisparm;
		Prow = P[Parm].p_vrow;
		Pcol = P[Parm].p_vcol;
	}
}

/* closeparm - Find the closest parameter */
closeparm(row,col)
{
	register struct paraminfo *pp;
	register int n;
	int dist, mindist, minparm, dr, dc;

	minparm = 0;
	mindist = Rows + Cols;
	for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
		if ( pp->p_flags != 0 )
			continue;
		if ( (dr=row-(pp->p_vrow)) < 0 )
			dr = -dr;
		if ( (dc=col-(pp->p_vcol)) < 0 )
			dc = -dc;
		if ( (dist=dr*dr+dc*dc) < mindist ) {
			minparm = n;
			mindist = dist;
		}
	}
	return(minparm);
}

/* playnote - play the 'auto' note */
playnote(i)
{
	int pitch, vol, dur, chan;
	long endtime;

	pitch = getval("autopitch");
	if(i == 0) { /* called from inside edit-mode */
		chan = getval("autochan");
	} else { /* called from the top level */
		chan = Channel;
	}
	vol = getval("autovol");
	dur = getval("autodur");
	endtime = milliclock() + dur * 100;
	midinote(1,chan,pitch,vol);
	while ( milliclock() < endtime )
		;
	midinote(0,chan,pitch,vol);
}

/* gotoparm - search for the next parameter in the specified direction */
gotoparm(dir)
{
	int n, k, inc, pm, orig, r = Prow, c = Pcol;

	if ( dir==CH_LEFT || dir==CH_RIGHT ) {
		if ( dir==CH_LEFT )
			c--;
		else
			c++;
		orig = c;
		inc = 0;
		pm = -1;
		/* look up and down, alternately */
		for ( n=2*Rows; n>0; n-- ) {
			r += (pm * inc++);
			pm = -pm;
			if ( r < 0 || r >= Rows )
				continue;
			if ( dir == CH_LEFT ) {
				for ( c=orig; c>=0; c-- ) {
					if ( parmat(r,c) )
						return;
				}
			}
			else {
				for ( c=orig; c<Cols; c++ ) {
					if ( parmat(r,c) )
						return;
				}
			}
		}
		return;
	}
	if ( dir==CH_DOWN || dir==CH_UP ) {
		if ( dir==CH_DOWN )
			r++;
		else
			r--;
		orig = c;
		while ( r >= 0 && r < Rows ) {
			/* look toward both sides at the same time */
			inc = 0;
			pm = -1;
			for ( k=2*Cols; k>0; k-- ) {
				c += (pm * inc++);
				pm = -pm;
				if ( c < 0 || c >= Cols )
					continue;
				if ( parmat(r,c) )
					return;
			}
			if ( dir==CH_DOWN )
				r++;
			else
				r--;
			c = orig;
		}
		return;
	}
}

/* paramat - return non-zero if a parameter value is at position r,c */
parmat(r,c)
register int r, c;
{
	register int n;
	register struct paraminfo *pp;

	for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
		if ( pp->p_flags != 0 )
			continue;
		if ( pp->p_vrow==r && pp->p_vcol==c ) {
			Prow = r;
			Pcol = c;
			Parm = n;
			return(1);
		}
	}
	return(0);
}

/* parmindex - return index (in P) of a given parameter name. */
parmindex(name)
char *name;
{
	int n;
	char *s;

	for ( n=0; (s=P[n].p_name) != NULL; n++ ) {
		if ( strcmp(s,name) == 0 )
			return(n);
	}
	sprintf(Buff,"HEY, PARMINDEX(%s) NOT FOUND!",name);
	windstr(Buff);
	windrefresh();
	return(-1);
}

setval(name,v)
char *name;
{
	int n;

	if ( (n=parmindex(name)) < 0 )
		return;
	P[n].p_val = v;
}

getval(name)
char *name;
{
	int n;

	if ( (n=parmindex(name)) < 0 )
		return(0);
	return(P[n].p_val);
}

enableparm(n)
{
	if ( P[n].p_flags != 0 )
		P[n].p_flags = 0;
}

disableparm(n)
{
	if ( P[n].p_flags == 0 )
		P[n].p_flags = 1;
}

midinote(onoff,chan,pitch,vol)
{
	sendmidi( ((onoff==1)?(0x90):(0x80)) | ((chan-1)&0xf) );
	sendmidi( pitch & 0x7f );
	sendmidi( vol & 0x7f );
}

static char Nbuff[16];

char *visnum(v)
{
	sprintf(Nbuff,"%d",v);
	return(Nbuff);
}
char *visonoff(v)
{
	if ( v==0 )
		return("off");
	else
		return("on");
}

char *
bankvoice(voice)
{
	int offset = Libbank * Nvoices * Voicesize + voice * Voicesize;
	return(Libdata + offset);
}
SHAR_EOF
cat << \SHAR_EOF > yama_com.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Yamaha Common Routines
 */

#define OVERLAY1

#include "glib.h"
#include <ctype.h>

#define DX100VSIZE 128
#define DX100NSIZE 17

char *visnum(), *visonoff(), *vism3num(), *viswave(), *vismono();
char *visfreq(), *visdx1a();
extern int Tx81;

int *txindex = NULL;
int txleng = 0;


extern int Dopmap[];

int Tx81 = 0;	/* 1 means we're talking to the TX81Z */
int Dopmap[] = { 3,1,2,0 };

int txfreq[] = {
50, 56, 62, 69, 75, 81, 87, 93,
     100, 106, 112, 118, 124, 131, 137, 143,
71, 80, 88, 97, 106, 115, 123, 132,
     141, 149, 158, 167, 176, 184, 193, 202,
78, 88, 98, 107, 117, 127, 137, 147,
     156, 166, 176, 186, 196, 205, 215, 225,
87, 98, 108, 119, 130, 141, 151, 162,
     173, 183, 194, 205, 216, 226, 237, 248,
100, 106, 112, 119, 125, 131, 137, 143,
     149, 156, 162, 168, 174, 180, 187, 193,
141, 150, 159, 167, 176, 185, 194, 203,
     211, 220, 229, 238, 247, 255, 264, 273,
157, 167, 177, 186, 196, 206, 216, 226,
     235, 245, 255, 265, 275, 284, 294, 304,
173, 184, 195, 205, 216, 227, 238, 249,
     259, 270, 281, 292, 303, 313, 324, 335,
200, 206, 212, 218, 225, 231, 237, 243,
     249, 256, 262, 268, 274, 280, 287, 293,
282, 291, 300, 308, 317, 326, 335, 344,
     352, 361, 370, 379, 388, 396, 405, 414,
300, 306, 312, 318, 325, 331, 337, 343,
     349, 356, 362, 368, 374, 380, 387, 393,
314, 324, 334, 343, 353, 363, 373, 383,
     392, 402, 412, 422, 432, 441, 451, 461,
346, 357, 368, 378, 389, 400, 411, 422,
     432, 443, 454, 465, 476, 486, 497, 508,
400, 406, 412, 418, 425, 431, 437, 443,
     449, 456, 462, 468, 474, 480, 487, 493,
424, 433, 441, 450, 459, 468, 476, 485,
     494, 503, 511, 520, 529, 537, 546, 555,
471, 481, 491, 500, 510, 520, 530, 539,
     549, 559, 569, 579, 588, 598, 608, 618,
500, 506, 512, 519, 525, 531, 537, 543,
     550, 556, 562, 568, 574, 581, 587, 593,
519, 530, 540, 551, 562, 573, 584, 594,
     605, 616, 627, 638, 648, 659, 670, 681,
565, 574, 582, 591, 600, 609, 617, 626,
     635, 644, 652, 661, 670, 678, 687, 696,
600, 606, 612, 619, 625, 631, 637, 643,
     650, 656, 662, 668, 674, 681, 687, 693,
628, 638, 647, 657, 667, 677, 687, 696,
     706, 716, 726, 736, 745, 755, 765, 775,
692, 703, 713, 724, 735, 746, 757, 767,
     778, 789, 800, 811, 821, 832, 843, 854,
700, 706, 712, 719, 725, 731, 737, 743,
     750, 756, 762, 768, 774, 781, 787, 793,
707, 716, 724, 733, 742, 750, 759, 768,
     776, 785, 794, 802, 811, 820, 828, 837,
785, 795, 804, 814, 824, 834, 844, 853,
     863, 873, 883, 893, 902, 912, 922, 932,
800, 806, 812, 819, 825, 831, 837, 843,
     850, 856, 862, 868, 874, 881, 887, 893,
848, 857, 865, 874, 883, 891, 900, 909,
     917, 926, 935, 943, 952, 961, 969, 978,
865, 876, 886, 897, 908, 919, 930, 940,
     951, 962, 973, 984, 994, 1005, 1016, 1027,
900, 906, 912, 919, 925, 931, 937, 943,
     950, 956, 962, 968, 974, 981, 987, 993,
942, 952, 961, 971, 981, 991, 1001, 1010,
     1020, 1030, 1040, 1050, 1059, 1069, 1079, 1089,
989, 998, 1006, 1015, 1024, 1032, 1041, 1050,
     1058, 1067, 1076, 1084, 1093, 1102, 1110, 1119,
1000, 1006, 1012, 1019, 1025, 1031, 1037, 1043,
     1050, 1056, 1062, 1068, 1074, 1081, 1087, 1093,
1038, 1049, 1060, 1070, 1081, 1092, 1103, 1113,
     1124, 1135, 1146, 1157, 1167, 1178, 1189, 1200,
1099, 1109, 1119, 1128, 1138, 1148, 1158, 1167,
     1177, 1187, 1197, 1207, 1216, 1226, 1236, 1246,
1100, 1106, 1112, 1119, 1125, 1131, 1137, 1143,
     1150, 1156, 1162, 1168, 1174, 1181, 1187, 1193,
1130, 1139, 1147, 1156, 1165, 1173, 1182, 1191,
     1199, 1208, 1217, 1225, 1234, 1243, 1251, 1260,
1200, 1206, 1212, 1219, 1225, 1231, 1237, 1243,
     1250, 1256, 1262, 1268, 1274, 1281, 1287, 1293,
1211, 1222, 1233, 1243, 1254, 1265, 1276, 1286,
     1297, 1308, 1319, 1330, 1340, 1351, 1362, 1373,
1256, 1266, 1276, 1285, 1295, 1305, 1315, 1324,
     1334, 1344, 1354, 1364, 1373, 1383, 1393, 1403,
1272, 1281, 1289, 1298, 1306, 1315, 1323, 1332,
     1341, 1349, 1358, 1366, 1375, 1384, 1392, 1401,
1300, 1306, 1312, 1319, 1325, 1331, 1337, 1343,
     1350, 1356, 1362, 1368, 1374, 1381, 1387, 1393,
1384, 1395, 1406, 1416, 1427, 1438, 1449, 1459,
     1470, 1481, 1492, 1503, 1513, 1524, 1535, 1546,
1400, 1406, 1412, 1419, 1425, 1431, 1437, 1443,
     1450, 1456, 1462, 1468, 1474, 1481, 1487, 1493,
1410, 1419, 1428, 1436, 1445, 1454, 1463, 1471,
     1480, 1489, 1498, 1507, 1515, 1524, 1533, 1542,
1413, 1423, 1433, 1442, 1452, 1462, 1472, 1481,
     1491, 1501, 1511, 1521, 1530, 1540, 1550, 1560,
1500, 1506, 1512, 1519, 1525, 1531, 1537, 1543,
     1550, 1556, 1562, 1568, 1574, 1581, 1587, 1593,
1555, 1563, 1572, 1581, 1589, 1598, 1606, 1615,
     1623, 1632, 1640, 1649, 1657, 1666, 1674, 1683,
1557, 1568, 1579, 1589, 1600, 1611, 1622, 1632,
     1643, 1654, 1665, 1676, 1686, 1697, 1708, 1719,
1570, 1580, 1590, 1599, 1609, 1619, 1629, 1638,
     1648, 1658, 1668, 1678, 1687, 1697, 1707, 1717,
1696, 1704, 1713, 1722, 1730, 1739, 1747, 1756,
     1764, 1773, 1781, 1790, 1798, 1807, 1815, 1824,
1727, 1737, 1747, 1756, 1766, 1776, 1786, 1795,
     1805, 1815, 1825, 1835, 1844, 1854, 1864, 1874,
1730, 1741, 1752, 1762, 1773, 1784, 1795, 1805,
     1816, 1827, 1838, 1849, 1859, 1870, 1881, 1892,
1837, 1845, 1854, 1863, 1871, 1880, 1888, 1897,
     1905, 1914, 1922, 1931, 1939, 1948, 1956, 1965,
1884, 1894, 1904, 1913, 1923, 1933, 1943, 1952,
     1962, 1972, 1982, 1992, 2001, 2011, 2021, 2031,
1903, 1914, 1925, 1935, 1946, 1957, 1968, 1978,
     1989, 2000, 2011, 2022, 2032, 2043, 2054, 2065,
1978, 1986, 1995, 2004, 2012, 2021, 2029, 2038,
     2046, 2055, 2063, 2072, 2080, 2089, 2097, 2106,
2041, 2051, 2061, 2070, 2080, 2090, 2100, 2110,
     2119, 2129, 2139, 2149, 2159, 2168, 2178, 2188,
2076, 2087, 2098, 2108, 2119, 2130, 2141, 2152,
     2162, 2173, 2184, 2195, 2206, 2216, 2227, 2238,
2120, 2128, 2137, 2145, 2154, 2162, 2171, 2179,
     2188, 2196, 2205, 2213, 2222, 2230, 2238, 2247,
2198, 2208, 2218, 2227, 2237, 2247, 2257, 2267,
     2276, 2286, 2296, 2306, 2316, 2325, 2335, 2345,
2249, 2260, 2271, 2281, 2292, 2303, 2314, 2325,
     2335, 2346, 2357, 2368, 2379, 2389, 2400, 2411,
2355, 2365, 2375, 2384, 2394, 2404, 2414, 2424,
     2433, 2443, 2453, 2463, 2473, 2482, 2492, 2502,
2422, 2433, 2444, 2454, 2465, 2476, 2487, 2498,
     2508, 2519, 2530, 2541, 2552, 2562, 2573, 2584,
2595, 2606, 2617, 2627, 2638, 2649, 2660, 2671,
     2681, 2692, 2703, 2714, 2725, 2735, 2746, 2757
};

/*
 * dxtxdin
 *
 * Take info from 'data' and stuff values in the P array, by using
 * the setval (and setopval) functions.  'data' is the Yamaha VMEM format.
 * This function works for both the dx100 and tx81z.
 */

dxtxdin(data)
char *data;
{
	int dop, adop, n, crs, fin, v;

	setdxtx();
	if ( Tx81 )
		txinit();
	for ( n=1; n<=4; n++ ) {
		dop = Dopmap[n-1]*10;
		adop = Dopmap[n-1]*2;
		setopval(n,"attack",data[0+dop]);
		setopval(n,"decay1",data[1+dop]);
		setopval(n,"level1",data[4+dop]);
		setopval(n,"decay2",data[2+dop]);
		setopval(n,"release",data[3+dop]);
		setopval(n,"keyscale",data[5+dop]);
		setopval(n,"ampmod",(data[6+dop]>>6)&01);
		setopval(n,"egbias",(data[6+dop]>>3)&07);
		setopval(n,"velocity",data[6+dop]&07);
		setopval(n,"outlevel",data[7+dop]);

		if ( Tx81 ) {
			crs = data[8+dop];
			fin = (data[74+adop]) & 017;
			v = freqin(crs,fin);
			setopval(n,"freq",v);
		}
		else
			setopval(n,"freq",data[8+dop]);

		setopval(n,"keyrate",data[9+dop]>>3);
		setopval(n,"detune",data[9+dop]&07);

		if ( Tx81 ) {
			setopval(n,"egsft",(data[73+adop]>>4)&03);
			setopval(n,"fix",(data[73+adop]>>3)&01);
			setopval(n,"wave",(data[74+adop]>>4)&07);
		}
	}
	setval("lfosync",(data[40]>>6)&01);
	setval("feedback",(data[40]>>3)&07);
	setval("algorithm",data[40]&07);
	setval("lfospeed",data[41]);
	setval("lfodelay",data[42]);
	setval("pmoddepth",data[43]);
	setval("amoddepth",data[44]);
	setval("pmodsens",(data[45]>>4)&07);
	setval("amodsens",(data[45]>>2)&03);
	setval("lfowave",data[45]&03);
	setval("transpose",data[46]);
	setval("pitchbend",data[47]);
	setval("portatime",data[49]);
	setval("modprange",data[51]);
	setval("modarange",data[52]);
	setval("breathprange",data[53]);
	setval("breatharange",data[54]);
	setval("breathpbias",data[55]);
	setval("breathegbias",data[56]);
	setval("playmode",(data[48]>>3)&01);
	setval("susfoot",(data[48]>>2)&01);
	setval("portfoot",(data[48]>>1)&01);
	setval("portmode",data[48]&01);
	setval("autochan",Channel);
	if ( Tx81 ) {
		setval("reverbrate",data[81]&07);
		setval("fcpitch",data[82]);
		setval("fcamp",data[83]);
	}
}

/*
 * dxtxdout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into 'data'.  'data' is in the Yamaha VMEM format.
 * This works for both the dx100 and tx81z.
 */

dxtxdout(data)
char *data;
{
	int dop, n, crs, fin;

	for ( n=1; n<=4; n++ ) {
		dop = Dopmap[n-1]*10;
		data[0+dop] = getopval(n,"attack");
		data[1+dop] = getopval(n,"decay1");
		data[4+dop] = getopval(n,"level1");
		data[2+dop] = getopval(n,"decay2");
		data[3+dop] = getopval(n,"release");
		data[5+dop] = getopval(n,"keyscale");
		data[6+dop] = getopval(n,"ampmod")<<6
				| getopval(n,"egbias")<<3
				| getopval(n,"velocity");
		data[7+dop] = getopval(n,"outlevel");
		data[9+dop] = getopval(n,"keyrate")<<3 | getopval(n,"detune");

		if ( ! Tx81 ) {
			data[8+dop] = getopval(n,"freq");
		}
		else {
			freqout(getopval(n,"freq"),&crs,&fin);
			data[8+dop] = crs;

			dop = Dopmap[n-1]*2;
			data[73+dop] = getopval(n,"egsft")<<4
					| getopval(n,"fix")<<3
					/* | getopval(n,"fixrg") */;
			data[74+dop] = getopval(n,"wave")<<4 | fin;
		}
	}
	data[40] = getval("lfosync")<<6
		| getval("feedback")<<3
		| getval("algorithm");
	data[41] = getval("lfospeed");
	data[42] = getval("lfodelay");
	data[43] = getval("pmoddepth");
	data[44] = getval("amoddepth");
	data[45] = getval("pmodsens")<<4 | getval("amodsens")<<2
		| getval("lfowave");
	data[46] = getval("transpose");
	data[47] = getval("pitchbend");
	data[49] = getval("portatime");
	data[51] = getval("modprange");
	data[52] = getval("modarange");
	data[53] = getval("breathprange");
	data[54] = getval("breatharange");
	data[55] = getval("breathpbias");
	data[56] = getval("breathegbias");
	data[48] = (unsigned) ( getval("playmode")<<3
		| getval("susfoot")<<2
		| getval("portfoot")<<1
		| getval("portmode"));

	if ( Tx81 ) {
		data[81] = getval("reverbrate");
		data[82] = getval("fcpitch");
		data[83] = getval("fcamp");
	}

	Channel = getval("autochan");
}

setdxtx()
{
	if ( strcmp(Synthname,"DX-100")==0 )
		Tx81 = 0;
	else
		Tx81 = 1;
}

setopval(n,str,v)
char *str;
{
	char buff[32];
	sprintf(buff,"op%d%s",n,str);
	setval(buff,v);
}

getopval(n,str)
char *str;
{
	char buff[32];
	sprintf(buff,"op%d%s",n,str);
	return(getval(buff));
}

/*
 * The routines below are used (in the P array) for printing the
 * values of various parameters (e.g. the vism3num routine prints
 * the value-3, which is appropriate for the 'detune' parameter.
 */

char Numbuff[8];

char *visnum();

char *
vis1num(v)
{
	sprintf(Numbuff,"%d",v+1);
	return(Numbuff);
}

char *
vism3num(v)
{
	sprintf(Numbuff,"%d",v-3);
	return(Numbuff);
}

char *visonoff();

char *
vismono(v)
{
	if ( v==0 )
		return("poly");
	else
		return("mono");
}

/*
            4    2  4    2         4                             4
            |    |  |    |         |               4             |
        2---3    ---3    3  4   2  3   1  4     ___|___    1  2  3
        |           |    |  |   |  |   |  |     |  |  |    |__|__|
        1           1    1---   1---   2  3     1  2  3
                                       |__|     |__|__|
                                                             1  2  3  4
                                                             |__|__|__|
 */

char *Algostr[] = {
	"1     ~d2---3~u~l|~u~l4~d~d~d~l~l~l~l~l|~l~d1",
	"2     ~d---3~l~l~l~l~u|  |~l~l~l~l~u2  4~l~d~d~d|~l~d1",
	"3     ~d3  4~l~l~l~l~u|~l~u2~l~d~d~d|  |~d~l~l~l~l1---",
	"4     ~d2  3~l~u|~u~l4~l~d~d~d~l~l~l|  |~l~l~l~l~d1---",
	"5     ~d~u1  4~d~l~l~l~l|  |~d~l~l~l~l2  3~d~l~l~l~l----",
	"6     ~d|  |  |~u~l~l~l~l~l~l~l___|___~u~l~l~l~l4~l~d~d~d~l~l~l1  2  3~d~l~l~l~l~l~l~l|__|__|",
	"7     ~d1  2  3~u~l|~u~l4~l~d~d~d~l~l~l~l~l~l|__|__|",
	"8     ~d1  2  3  4~d~l~l~l~l~l~l~l~l~l~l|__|__|__|"
};

char *
visdx1a(v)
{
	if ( v >= 0 && v <= 7 )
		return(Algostr[v]);
	else
		return("????");
}

char *
viswave(v)
{
	switch(v){
	case 0: return("saw up");
	case 1: return("square");
	case 2: return("triangle");
	case 3: return("s/hold");
	default: return("???");
	}
}

char *Freqstr[] = {	/* values from 0 to 63 */
	"0.50 ", "0.71 ", "0.78 ", "0.87 ", "1.00 ",
	"1.41 ", "1.57 ", "1.73 ", "2.00 ", "2.82 ",
	"3.00 ", "3.14 ", "3.46 ", "4.00 ", "4.24 ",
	"4.71 ", "5.00 ", "5.19 ", "5.65 ", "6.00 ",
	"6.28 ", "6.92 ", "7.00 ", "7.07 ", "7.85 ",
	"8.00 ", "8.48 ", "8.65 ", "9.00 ", "9.42 ",
	"9.89 ", "10.00", "10.38", "10.99", "11.00",
	"11.30", "12.00", "12.11", "12.56", "12.72",
	"13.00", "13.84", "14.00", "14.10", "14.13",
	"15.00", "15.55", "15.57", "15.70", "16.96",
	"17.27", "17.30", "18.37", "18.84", "19.03",
	"19.78", "20.41", "20.76", "21.20", "21.98",
	"22.49", "23.55", "24.22", "25.95"
};

char *
visfreq(v)
{
	if ( v >=0 && v <= 63 )
		return ( Freqstr[v] );
	else
		return("????");
}

/*
 * dx1sedit
 *
 * Send a single voice to the edit buffer of the DX.
 */
dx1sedit(data)
char *data;
{
	setdxtx();
	if ( Tx81 )
		sendaced(data);
	sendvced(data);
}

sendvced(data)
char *data;
{
	char vdata[DX100VSIZE];
	int n, cksum, c;

	clrdata(vdata,DX100VSIZE);
	vmemtovced(data,vdata);
	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(Channel-1);	/* channel # */
	sendmidi(0x03);		/* format type */
	sendmidi(0x00);		/* byte count */
	sendmidi(0x5d);		/* byte count */
	cksum = 0;
	for ( n=0; n<93; n++ ) {
		sendmidi(c = (int)(vdata[n]));
		cksum += c;
	}
	sendmidi((-cksum) & 0x7f);
	sendmidi(EOX);
}

sendaced(data)
char *data;
{
	char *p, vdata[DX100VSIZE];
	int n, cksum, c;

	clrdata(vdata,DX100VSIZE);
	vmemtoaced(data,vdata);
	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(Channel-1);	/* channel # */
	sendmidi(0x7e);		/* format type */
	sendmidi(0x00);		/* byte count */
	sendmidi(0x21);		/* byte count */
	p = "LM  8976AE";
	cksum = 0;
	while ( (c=(int)(*p++)) != '\0' ) {
		sendmidi(c);
		cksum += c;
	}
	for ( n=0; n<23; n++ ) {
		sendmidi(c=(int)(vdata[n]));
		cksum += c;
	}
	sendmidi((-cksum) & 0x7f);
	sendmidi(EOX);
}

/*
 * vmemtovced
 *
 * convert a vmem format voice to vced format.
 */

vmemtovced(data,vdata)
char *data;
char *vdata;
{
	int vop, dop, n;

	for ( n=0; n<4; n++ ) {
		/* vop = Dopmap[n]*13; */
		vop = Dopmap[n]*13;
		dop = Dopmap[n]*10;
		vdata[vop+0] = data[dop+0];	/* attack rate */
		vdata[vop+1] = data[dop+1];	/* decay 1 rate */
		vdata[vop+2] = data[dop+2];	/* decay 2 rate */
		vdata[vop+3] = data[dop+3];	/* release rate */
		vdata[vop+4] = data[dop+4];	/* decal 1 level */
		vdata[vop+5] = data[dop+5];	/* keyboard scaling level */
		vdata[vop+6] = (data[dop+9]>>3);/* keyboard scaling rate */
		vdata[vop+7] = (data[dop+6]>>3)&7;	/* eg bias sens. */
		vdata[vop+8] = (data[dop+6]>>6)&1;	/* amp. mod. enable */
		vdata[vop+9] = (data[dop+6]&7);	/* key velocity */
		vdata[vop+10] = data[dop+7];	/* output level */
		vdata[vop+11] = data[dop+8];	/* osc. frequency */
		vdata[vop+12] = (data[dop+9]&7);	/* detune */
	}
	vdata[52] = (data[40]&7);	/* algorithm */
	vdata[53] = (data[40]>>3)&7;	/* feedback level */
	vdata[54] = data[41];		/* lfo speed */
	vdata[55] = data[42];		/* lfo delay */
	vdata[56] = data[43];		/* pitch modulation depth */
	vdata[57] = data[44];		/* amplitude modulation depth */
	vdata[58] = (data[40]>>6)&1;	/* lfo sync */
	vdata[59] = data[45]&3;		/* lfo wave */
	vdata[60] = (data[45]>>4)&7;		/* pitch modulation sens. */
	vdata[61] = (data[45]>>2)&3;		/* amp. modulation sens. */
	vdata[62] = data[46];		/* transpose */
	vdata[63] = (data[48]>>3)&1;	/* play mode (poly/mono) */
	vdata[64] = data[47];		/* pitch bend range */
	vdata[65] = (data[48]&1);	/* portamento mode */
	vdata[66] = data[49];		/* portamento time */
	vdata[67] = data[50];		/* foot volume range */
	vdata[68] = (data[48]>>2)&1;	/* sustain foot switch */
	vdata[69] = (data[48]>>1)&1;	/* portamento foot switch */
	vdata[70] = (data[48]>>4)&1;	/* chorus switch */
	vdata[71] = data[51];		/* mod. wheel pitch mod. range */
	vdata[72] = data[52];		/* mod. wheel ampli. mod. range */
	vdata[73] = data[53];		/* breath pitch mod. range */
	vdata[74] = data[54];		/* breath ampli. mod. range */
	vdata[75] = data[55];		/* breath control pitch bias range */
	vdata[76] = data[56];		/* breath control EG bias range */
	for ( n=77; n<93; n++ )		/* voice name AND pitch EG rates */
		vdata[n] = data[n-20];
}

/*
 * vmemtoaced
 *
 * Convert a vmem format voice to aced format (TX81Z).
 */

vmemtoaced(data,adata)
char *data;
char *adata;
{
	int vop, aop, n;

	for ( n=0; n<4; n++ ) {
	    vop = 73 + Dopmap[n]*2;
	    aop = Dopmap[n]*5;
	    adata[0+aop] = (data[vop]>>3) & 01;    /* fixed freq (0,1) */
	    adata[1+aop] = data[vop] & 07;	   /* fixed freq range (0-7) */
	    adata[2+aop] = data[vop+1] & 017;	   /* freq range fine (0-15) */
	    adata[3+aop] = (data[vop+1]>>4) & 07;  /* op. waveform (0-7) */
	    adata[4+aop] = (data[vop]>>3) & 03;   /* EG shift (0-3) */
	}
	adata[20] = data[81] & 07;	/* reverb rate */
	adata[21] = data[82];	/* Foot controller pitch */
	adata[22] = data[83];	/* Foot controller amp. */
}

#ifdef OLD
/*
 * Send a single parameter value.
 */
sendparam(param,val)
{
	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(0x10);	/* Channel? */
	sendmidi(0x12);
	sendmidi(param);
	sendmidi(val);
	sendmidi(EOX);
}

/*
 * remotely press a key on the DX
 */
presskey(key,val)
{
	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(0x10);	/* Channel? */
	sendmidi(0x08);
	sendmidi(key);
	sendmidi(val);
	sendmidi(EOX);
}

/*
 * tovmem
 *
 * convert a vced format voice to vmem format.
 */

tovmem(vdata,data)
char *vdata;	/* vced format data */
char *data;	/* vmem format */
{
	int vop, dop, n;

	for ( n=0; n<4; n++ ) {
		vop = Dopmap[n]*13;
		dop = Dopmap[n]*10;
		data[dop+0] = vdata[vop+0];	/* attack rate */
		data[dop+1] = vdata[vop+1];	/* decay 1 rate */
		data[dop+2] = vdata[vop+2];	/* decay 2 rate */
		data[dop+3] = vdata[vop+3];	/* release rate */
		data[dop+4] = vdata[vop+4];	/* decal 1 level */
		data[dop+5] = vdata[vop+5];	/* keyboard scaling level */
				/* amp. mod. enab/eg bias sens/key velocity */
		data[dop+6]=(vdata[vop+8]<<6) | (vdata[vop+7]<<3) | vdata[vop+9];
		data[dop+7] = vdata[vop+10];	/* output level */
		data[dop+8] = vdata[vop+11];	/* osc. frequency */
				/* key scaling rate/detune */
		data[dop+9] = (vdata[vop+6]<<3) | vdata[vop+12];
	}
		/* lfo sync/feedback level/algorithm */
	data[40] = (vdata[58]<<6) | (vdata[53]<<3) | vdata[52];
	data[41] = vdata[54];		/* lfo speed */
	data[42] = vdata[55];		/* lfo delay */
	data[43] = vdata[56];		/* pitch modulation depth */
	data[44] = vdata[57];		/* amplitude modulation depth */
		/* pitch mod. sens/amp. mod. sens/lfo wave */
	data[45] = (vdata[60]<<4) | (vdata[61]<<2) | vdata[59];
	data[46] = vdata[62];		/* transpose */

		/* chorus/playmode/sustain/portamento-foot/portamento-mode */
	data[48] = (vdata[70]<<4)|(vdata[63]<<3)|(vdata[68]<<2)|(vdata[69]<<1)
		| vdata[65];

	data[47] = vdata[64];		/* pitch bend range */
	data[49] = vdata[66];		/* portamento time */
	data[50] = vdata[67];		/* foot volume range */
	data[51] = vdata[71];		/* mod. wheel pitch mod. range */
	data[52] = vdata[72];		/* mod. wheel ampli. mod. range */
	data[53] = vdata[73];		/* breath pitch mod. range */
	data[54] = vdata[74];		/* breath ampli. mod. range */
	data[55] = vdata[75];		/* breath control pitch bias range */
	data[56] = vdata[76];		/* breath control EG bias range */
	for ( n=77; n<93; n++ )		/* voice name AND pitch EG rates */
		data[n-20] = vdata[n];
}
#endif

/* dx1nof - return a pointer to the voice name buried in data */
char *
dx1nof(data)
char *data;
{
	static char currbuff[DX100NSIZE+1];
	char *p;
	int m;

	p = currbuff;
	for ( m=0; m<10; m++ )
		*p++ = data[57+m];
	*p = '\0';
	return(currbuff);
}

/* dx1snof - set the voice name buried in data to name */
dx1snof(data,name)
char *data;
char *name;
{
	char *p;
	int m;

	for ( p=name,m=0; *p!='\0' && m<10; p++,m++ )
		data[57+m] = *p;
	for ( ; m<10; m++ )
		data[57+m] = ' ';
}

/* dx1sbulk - send a bulk dump to the DX-100 */
dx1sbulk(data)
char *data;
{
	int c, v, n, cksum;

	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(Channel-1);	/* Channel # */
	sendmidi(0x04);
	sendmidi(0x20);
	sendmidi(0x00);
	cksum = 0;
	/* send 32 voices worth of data */
	for ( v=0; v<32; v++ ) {
		for ( n=0; n<DX100VSIZE; n++ ) {
			/* The DX100 can only handle 24 voices (but needs */
			/* to have 32 voices worth of data sent, anyway) */
			if ( v >= 24 && ( ! Tx81 ) )
				c = 0;
			else
				c = VOICEBYTE(data,v,n);
			sendmidi(c & 0xff);
			cksum += c;
		}
	}
	sendmidi((-cksum) & 0x7f);
	sendmidi(0xf7);
}

/* dx1gbulk - Request and read a bulk dump from the DX-100 */
dx1gbulk(data)
char *data;
{
	int c, n, v, b1, b2, cksum, ret = 1;
	long begin, toolong;

	setdxtx();
	flushmidi();

	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(0x20 | (Channel-1) );	/* Channel # */
	sendmidi(4);			/* 4 == 32 voice bulk dump */
	sendmidi(EOX);			/* EOX */

	begin = milliclock();
	toolong = begin + 1000 * TIMEOUT;

	/* wait for the x43 byte starting the dump */
	while ( milliclock() < toolong ) {
		if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x43 )
			break;
	}
	if ( c != 0x43 ) {
		Reason = "Timeout waiting for 0x43";
		goto getout;
	}
	getmidi();	/* channel # */
	getmidi();	/* format # */
	getmidi();	/* byte count high byte */
	getmidi();	/* byte count low byte */

	cksum = 0;
	/* 32 voices are dumped */
	for ( v=0; v<32; v++ ) {
		for ( n=0; n<DX100VSIZE; n++ ) {
			/* twiddle your thumbs, but not forever */
			while ( ! STATMIDI ) {
				if ( milliclock() > toolong )
					goto timeout;	/* the end of an era */
			}
			c = (getmidi() & 0xff);
			/* Ignore non-data bytes ? */
			if ( c & 0x80 )
				continue;
			/* compute checksum */
			cksum += c;
			/* Only 24 voices are used on the DX100 */
			if ( v < 24 || Tx81 )
				VOICEBYTE(data,v,n) = c;
		}
	}
timeout:
	if ( v < 32 ) {
		Reason = "Timeout while reading!";
		goto getout;
	}
	b1 = (getmidi() & 0xff);	/* Checksum */
	b2 = (getmidi() & 0xff);	/* EOX */
	cksum = (-cksum) & 0x7f;	/* convert to what we must match */
	if ( b2 != EOX )
		Reason = "EOX not received";
	else if ( b1 != cksum ) {
		static char ckbuff[80];
		sprintf(ckbuff,"Checksum doesn't match (got %d expected %d)",b1,cksum);
		/* Reason = "Checksum doesn't match"; */
		Reason = ckbuff;
	}
	else {
		Reason = "";
		ret = 0;	/* all's well */
	}
getout:
	return(ret);
}

#ifdef OLDSTUFF
dxchecksum(data)
char *data;
{
	int v, n, s=0;

	for ( v=0; v<DX100NVOICES; v++ ) {
		for ( n=0; n<DX100VSIZE; n++ ) {
			s += (int)(VOICEBYTE(data,v,n));
			while ( s > 128 )
				s -= 128;
		}
	}
	return(128-s);
}
#endif

freqin(crs,fin)
{
	int n, f;

	txinit();
	f = txfreq[crs*16+fin];
	for ( n=0; n<txleng; n++ ) {
		if ( txfreq[txindex[n]] == f )
			return(n);
	}
	return(0);
}

freqout(v,acrs,afin)
int *acrs;
int *afin;
{
	int i;

	i = txindex[v];
	*acrs = i/16;
	*afin = i%16;
}

txinit()
{
	int n, k;
	char *parm;

	if ( txindex != NULL )
		return;
	/* create an array of indexes into txfreq, giving a sorted */
	/* list of unique frequencies. */
	txindex = (int *) alloc(sizeof(int) * 64 * 16);
	for ( n=0; n<64; n++ ) {
		for ( k=0; k<16; k++ ) {
			int freq = txfreq[n*16+k];
			register int i, f;
			register int *p, *endp;

			/* insertion sort, starting from top of already */
			/* sorted list, since the values we're inserting */
			/* are almost sorted already. */
			for ( i=txleng-1; i>=0; i-- ) {
				if ( (f=txfreq[txindex[i]]) < freq )
					break;
				if ( f == freq )
					goto dontadd;
			}
			i++;
			/* shift everything up one */
			p = &txindex[txleng];
			endp = &txindex[i];
			for ( ; p>endp; p-- )
				*p = *(p-1);
			txindex[i] = 16*n+k;
			txleng++;
		    dontadd: ;
		}
	}
	/* set the maximum value for the frequency parameters */
	parm = "op#freq";
	for ( n=1; n<=4; n++ ) {
		parm[2] = '0' + n;
		if ( (k=parmindex(parm)) >= 0 )
			P[k].p_max = txleng-1;
	}
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.