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

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

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

#	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:
#	dw8000.c
#	k5.c
#	tx81p.c
# This archive created: Thu Mar 16 11:45:10 1989
cat << \SHAR_EOF > dw8000.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * DW8000 Librarian
 *
 * Code completed 8/24/87 --  Steven A. Falco  moss!saf
 */

#define OVERLAY2

#include "glib.h"

#define DW8VSIZE 51

char *visnum(), *visd8wave(), *visd8oct(), *visd8trk();
char *visd8ival(), *visd8detu(), *visd8asel(), *dw8vnum(), *visd8amod();
char *visd8mgw(), *visd8mode(), *visd8pol(),*visd8sem(), *visonoff();

/* This array contains arbitrary screen labels */
struct labelinfo Ldw800[] = {
 2,0,"+----------------------------------+----------------+------------------+------+",
 3,0,"|         Osc 1     Osc 2     Noise|          ModGen|          AutoBend| Mode |",
 4,0,"|Octave",4,35,"|Waveform",4,52,"|Select",4,71,"|      |",
 5,0,"|Waveform",5,35,"|Frequency",5,52,"|Mode",5,71,"|      |",
 6,0,"|Level",6,35,"|Delay",6,52,"|Time",6,71,"|      |",
 7,0,"|Interval",7,35,"|Osc",7,52,"|Intensity",7,71,"|      |",
 8,0,"|Detune",8,35,"|VCF",8,52,"|",8,71,"|      |",
 9,0,"+------------------+---------------+----------------+------------------+------+",
10,0,"|",10,11,"VCF  VCA|",10,30,"Delay|    Joystick    |     Portamento   |Key   |",
11,0,"|Attack",11,19,"|Time",11,35,"|Osc",11,52,"|Time",11,71,"|Param |",
12,0,"|Decay",12,19,"|Factor",12,35,"|VCF",12,52,"|",12,71,"|      |",
13,0,"|Break Pt.",13,19,"|Feedback",13,35,"+----------------+------------------+------+",
14,0,"|Slope",14,19,"|Frequency      |",
15,0,"|Sustain",15,19,"|Intensity      | +-------------------------+--------------+",
16,0,"|Release",16,19,"|Eff.Level      | |Space = Play Note",16,63,"| Auto-Note    |",
17,0,"|V.Sensitv",17,19,"+---------------+ |",17,63,"|",17,78,"|",
18,0,"|Cutoff",18,19,"|       AftTouch| |h = left   q = quit      |Pitch",18,78,"|",
19,0,"|Resonance",19,19,"|Osc.MG",19,35,"| |j = down   N = Set Name  |Duration      |",
20,0,"|Tracking",20,19,"|VCF",20,35,"| |k = up     J = Decrement |Volume",20,78,"|",
21,0,"|Polarity",21,19,"|VCA",21,35,"| |l = right  K = Increment |Channel       |",
22,0,"|EG.Intens",22,19,"|",22,35,"| |",22,63,"|",22,78,"|",
23,0,"+------------------+---------------+ +-------------------------+--------------+",
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Pdw800[] = {
"autopitch",NULL,	-1,-1, 18, 73, visnum, 		0, 127, 60, 0,
"autovol",	NULL,	-1,-1, 19, 73, visnum, 		0, 127, 63, 0,
"autodur",	NULL,	-1,-1, 20, 73, visnum, 		1,  20,  5, 0,
"autochan",	NULL,	-1,-1, 21, 73, visnum, 		1,  16,  1, 0,

"o1oct",	NULL,	-1,-1,  4, 10, visd8oct,	0,   3, 0, 0,
"o1wave",	NULL,	-1,-1,  5, 10, visd8wave,	0,  15, 0, 0,
"o1lev",	NULL,	-1,-1,  6, 10, visnum,		0,  31, 0, 0,
"o2oct",	NULL,	-1,-1,  4, 20, visd8oct,	0,   3, 0, 0,
"o2wave",	NULL,	-1,-1,  5, 20, visd8wave,	0,  15, 0, 0,
"o2lev",	NULL,	-1,-1,  6, 20, visnum,		0,  31, 0, 0,
"o2ival",	NULL,	-1,-1,  7, 20, visd8ival,	0,   7, 0, 0,
"o2detu",	NULL,	-1,-1,  8, 20, visd8detu,	0,   7, 0, 0,
"noise",	NULL,	-1,-1,  6, 30, visnum,		0,  31, 0, 0,

"mgwave",	NULL,	-1,-1,  4, 46, visd8mgw,	0,   3, 0, 0,
"mgfrew",	NULL,	-1,-1,  5, 46, visnum,		0,  31, 0, 0,
"mgdela",	NULL,	-1,-1,  6, 46, visnum,		0,  31, 0, 0,
"mgosc",	NULL,	-1,-1,  7, 46, visnum,		0,  31, 0, 0,
"mgvcf",	NULL,	-1,-1,  8, 46, visnum,		0,  31, 0, 0,

"abndsel",	NULL,	-1,-1,  4, 63, visd8asel,	0,   3, 0, 0,
"abndmod",	NULL,	-1,-1,  5, 63, visd8amod, 	0,   1, 0, 0,
"abndtim",	NULL,	-1,-1,  6, 63, visnum,		0,  31, 0, 0,
"abndins",	NULL,	-1,-1,  7, 63, visnum,		0,  31, 0, 0,

"mode",		NULL,	-1,-1,  4, 72, visd8mode,	0,   3, 0, 0,

"fatt",		NULL,	-1,-1, 11, 11, visnum,		0,  31, 0, 0,
"fdec",		NULL,	-1,-1, 12, 11, visnum,		0,  31, 0, 0,
"fbrk",		NULL,	-1,-1, 13, 11, visnum,		0,  31, 0, 0,
"fslp",		NULL,	-1,-1, 14, 11, visnum,		0,  31, 0, 0,
"fsus",		NULL,	-1,-1, 15, 11, visnum,		0,  31, 0, 0,
"frel",		NULL,	-1,-1, 16, 11, visnum,		0,  31, 0, 0,
"fsens",	NULL,	-1,-1, 17, 11, visnum,		0,   7, 0, 0,
"fcut",		NULL,	-1,-1, 18, 11, visnum,		0,  63, 0, 0,
"fres",		NULL,	-1,-1, 19, 11, visnum,		0,  31, 0, 0,
"ftrk",		NULL,	-1,-1, 20, 11, visd8trk,	0,   3, 0, 0,
"fpol",		NULL,	-1,-1, 21, 11, visd8pol,	0,   1, 0, 0,
"fegi",		NULL,	-1,-1, 22, 11, visnum,		0,  31, 0, 0,
"aatt",		NULL,	-1,-1, 11, 16, visnum,		0,  31, 0, 0,
"adec",		NULL,	-1,-1, 12, 16, visnum,		0,  31, 0, 0,
"abrk",		NULL,	-1,-1, 13, 16, visnum,		0,  31, 0, 0,
"aslp",		NULL,	-1,-1, 14, 16, visnum,		0,  31, 0, 0,
"asus",		NULL,	-1,-1, 15, 16, visnum,		0,  31, 0, 0,
"arel",		NULL,	-1,-1, 16, 16, visnum,		0,  31, 0, 0,
"asens",	NULL,	-1,-1, 17, 16, visnum,		0,   7, 0, 0,

"dtim",		NULL,	-1,-1, 11, 30, visnum,		0,   7, 0, 0,
"dfact",	NULL,	-1,-1, 12, 30, visnum,		0,  15, 0, 0,
"dfeed",	NULL,	-1,-1, 13, 30, visnum,		0,  15, 0, 0,
"dfreq",	NULL,	-1,-1, 14, 30, visnum,		0,  31, 0, 0,
"dintns",	NULL,	-1,-1, 15, 30, visnum,		0,  31, 0, 0,
"deff",		NULL,	-1,-1, 16, 30, visnum,		0,  15, 0, 0,

"atosc",	NULL,	-1,-1, 19, 27, visnum,		0,   3, 0, 0,
"atvcf",	NULL,	-1,-1, 20, 27, visnum,		0,   3, 0, 0,
"atvca",	NULL,	-1,-1, 21, 27, visnum,		0,   3, 0, 0,

"joyosc",	NULL,	-1,-1, 11, 40, visd8sem,	0,  15, 0, 0,
"joyvcf",	NULL,	-1,-1, 12, 40, visonoff,	0,   1, 0, 0,

"portam",	NULL,	-1,-1, 11, 58, visnum,		0,  31, 0, 0,

"vnumb",	NULL,	-1,-1, 12, 72, dw8vnum,		0,  63, 0, 0,

NULL,		NULL,	-1,-1, -1, -1, visnum, 		0,   0, 0, 0
};

/*
 * dw8vnum
 *
 * Convert a voice number (0 to 63) to the string displayed in the
 * librarian (ie. 11 to 88).
 */

char *
dw8vnum(n)
{
	static char v[3];

	if ( n < 0 || n > 63 )
		return("??");

	v[0] = n/8 + '1';
	v[1] = n%8 + '1';
	v[2] = '\0';
	return(v);
}

/*
 * dw8numv
 *
 * Convert a display-style voice number (11 to 88) to internal
 * format (0 - 63).
 */

dw8numv(n)
int n;
{
	int ld, rd;
	
	/* crack out the digits as octal codes */
	ld = (n / 10) - 1; /* left digit */
	rd = (n % 10) - 1; /* right digit */
	
	if(ld < 0 || ld > 7 || rd < 0 || rd > 7) {
		return(-1);
	} else {
		return(ld * 8 + rd); /* combine as octal */
	}
}

/*
 * dw8din
 *
 * Take library bank 'data' and stuff values in the P array, by using
 * the setval function.
 */

dw8din(data)
char *data;
{
	/* The first 20 bytes are reserved (arbitrarily) for the voice name */
	setval("o1oct",data[20]);
	setval("o1wave",data[21]);
	setval("o1lev",data[22]);
	setval("abndsel",data[23]);
	setval("abndmod",data[24]);
	setval("abndtim",data[25]);
	setval("abndins",data[26]);	
	setval("o2oct",data[27]);
	setval("o2wave",data[28]);
	setval("o2lev",data[29]);
	setval("o2ival",data[30]);
	setval("o2detu",data[31]);
	setval("noise",data[32]);
	setval("mode",data[33]);
	setval("vnumb",data[34]);
	setval("fcut",data[35]);
	setval("fres",data[36]);
	setval("ftrk",data[37]);
	setval("fpol",data[38]);
	setval("fegi",data[39]);
	setval("fatt",data[40]);
	setval("fdec",data[41]);
	setval("fbrk",data[42]);
	setval("fslp",data[43]);
	setval("fsus",data[44]);
	setval("frel",data[45]);
	setval("fsens",data[46]);
	setval("aatt",data[47]);
	setval("adec",data[48]);
	setval("abrk",data[49]);
	setval("aslp",data[50]);
	setval("asus",data[51]);
	setval("arel",data[52]);
	setval("asens",data[53]);
	setval("mgwave",data[54]);
	setval("mgfrew",data[55]);
	setval("mgdela",data[56]);
	setval("mgosc",data[57]);
	setval("mgvcf",data[58]);
	setval("joyosc",data[59]);
	setval("joyvcf",data[60]);
	setval("dtim",data[61]);
	setval("dfact",data[62]);
	setval("dfeed",data[63]);
	setval("dfreq",data[64]);
	setval("dintns",data[65]);
	setval("deff",data[66]);
	setval("portam",data[67]);
	setval("atosc",data[68]);
	setval("atvcf",data[69]);
	setval("atvca",data[70]);

	/* We set the 'auto-note' channel upon entry */
	setval("autochan",Channel);
}

/*
 * dw8dout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into the library bank 'data'.
 */

dw8dout(data)
char *data;
{
	data[20] = getval("o1oct");
	data[21] = getval("o1wave");
	data[22] = getval("o1lev");
	data[23] = getval("abndsel");
	data[24] = getval("abndmod");
	data[25] = getval("abndtim");
	data[26] = getval("abndins");
	data[27] = getval("o2oct");
	data[28] = getval("o2wave");
	data[29] = getval("o2lev");
	data[30] = getval("o2ival");
	data[31] = getval("o2detu");
	data[32] = getval("noise");
	data[33] = getval("mode");
	data[34] = getval("vnumb");
	data[35] = getval("fcut");
	data[36] = getval("fres");
	data[37] = getval("ftrk");
	data[38] = getval("fpol");
	data[39] = getval("fegi");
	data[40] = getval("fatt");
	data[41] = getval("fdec");
	data[42] = getval("fbrk");
	data[43] = getval("fslp");
	data[44] = getval("fsus");
	data[45] = getval("frel");
	data[46] = getval("fsens");
	data[47] = getval("aatt");
	data[48] = getval("adec");
	data[49] = getval("abrk");
	data[50] = getval("aslp");
	data[51] = getval("asus");
	data[52] = getval("arel");
	data[53] = getval("asens");
	data[54] = getval("mgwave");
	data[55] = getval("mgfrew");
	data[56] = getval("mgdela");
	data[57] = getval("mgosc");
	data[58] = getval("mgvcf");
	data[59] = getval("joyosc");
	data[60] = getval("joyvcf");
	data[61] = getval("dtim");
	data[62] = getval("dfact");
	data[63] = getval("dfeed");
	data[64] = getval("dfreq");
	data[65] = getval("dintns");
	data[66] = getval("deff");
	data[67] = getval("portam");
	data[68] = getval("atosc");
	data[69] = getval("atvcf");
	data[70] = getval("atvca");

	/* If the autochan parameter has changed, update Channel */
	Channel = getval("autochan");
}

/*
 * dw8sedit
 *
 * Send a single voice to the edit buffer of the DW8000.  This will be whatever
 * voice is currently selected.
 */

dw8sedit(data)
char *data;
{
	int n;
	
	sendmidi(0xf0);
	sendmidi(0x42);
	sendmidi(0x30 | (Channel - 1));
	sendmidi(0x03);
	sendmidi(0x40);
	for(n = 0; n < DW8VSIZE; n++) {
		sendmidi(data[n + 20] & 0x7f);
	}
	sendmidi(EOX);
}

/*
 * dw8nof
 *
 * Return a pointer to the voice name buried in library bank data.
 */
char *
dw8nof(data)
char *data;
{
	static char currbuff[17];
	char *p;
	int m;

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

/*
 * dw8snof
 *
 * Set the voice name buried in data to name.
 */
dw8snof(data,name)
char *data;
char *name;
{
	char *p;
	int m;

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

/* dw8sone - send a single voice to the DW8000 */
dw8sone(iv, data)
int iv;
char *data;
{
	int c, b2, ret = 1;
	long begin, toolong;

	/* select voice n */
	sendmidi(0xc0 | (Channel - 1));
	sendmidi(iv);
	
	/* send data */
	dw8sedit(data);
	
	/* request write */
	sendmidi(0xf0);
	sendmidi(0x42);
	sendmidi(0x30 | (Channel - 1));
	sendmidi(0x03);
	sendmidi(0x11);	/* write request */
	sendmidi(iv);	/* the now-current voice */
	sendmidi(EOX);
	
	/* read the ack/nack - set up for timeout */
	begin = milliclock();
	toolong = begin + 1000 * TIMEOUT;

	/* wait for the 0x03 byte (dw8000 ID byte) */
	while ( milliclock() < toolong ) {
		if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x03 )
			break;
	}
	if ( c != 0x03 ) {
		Reason = "Timeout waiting for 0x03";
		goto getout;
	}
	
	/* next byte is the result code */
	while((b2 = getmidi() & 0xff) == 0xfe)
		; /* burn active sensing */
	if(b2 != 0x21) {
		Reason = "Write failed - check protect switch!";
		goto getout;
	}

	while((b2 = getmidi() & 0xff) == 0xfe)
		;	/* want EOX - burn active sensing */
	if ( b2 != EOX )
		Reason = "EOX not received";
	else {
		Reason = "";
		ret = 0;	/* all's well */
	}
	
getout:
	return(ret);
}

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

	flushmidi();

	for(v = 0; v < Nvoices; v++) {
		/* select voice */
		sendmidi(0xc0 | (Channel - 1));
		sendmidi(v);
		
		/* request the voice */
		sendmidi(0xf0);
		sendmidi(0x42);
		sendmidi(0x30 | (Channel-1));	/* Channel # */
		sendmidi(0x03);
		sendmidi(0x10);	
		sendmidi(EOX);
	
		/* set up for timeout */
		begin = milliclock();
		toolong = begin + 1000 * TIMEOUT;
	
		/* wait for the x40 byte starting the dump */
		while ( milliclock() < toolong ) {
			if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x40 )
				break;
		}
		if ( c != 0x40 ) {
			Reason = "Timeout waiting for 0x40";
			goto getout;
		}
		
		/* now read 51 bytes of voice data */
		for(n = 0; n < DW8VSIZE; n++) {
			/* twiddle your thumbs, but not forever */
			while ( ! STATMIDI ) {
				if ( milliclock() > toolong )
					goto timeout;	/* the end of an era */
			}
			while((b2 = getmidi() & 0xff) == 0xfe)
				; /* burn active sensing */
			VOICEBYTE(data,v,n + 20) = b2;	
		}

	timeout:
		if ( n != DW8VSIZE ) {
			Reason = "Timeout while reading!";
			goto getout;
		}
		while((b2 = getmidi() & 0xff) == 0xfe)
			;	/* want EOX - burn active sensing */
		if ( b2 != EOX )
			Reason = "EOX not received";
		else {
			Reason = "";
			ret = 0;	/* all's well */
		}
	} /* go back for another voice */
	
getout:
	return(ret);
}

/*
 * Below are functions used for display of parameter values
 */

char *
visd8wave(v)
{
	switch (v) {
	case 0: return("ramp");
	case 1: return("square");
	case 2: return("ac. piano");
	case 3: return("el. piano");
	case 4: return("hd. piano");
	case 5: return("clavinet");
	case 6: return("organ");
	case 7: return("brass");
	case 8: return("sax");
	case 9: return("violin");
	case 10: return("a. guitar");
	case 11: return("d. guitar");
	case 12: return("el. bass");
	case 13: return("dg. bass");
	case 14: return("bell");
	case 15: return("sine");
	}
	return("*");
}

char *
visd8oct(v)
{
	switch(v) {
	case 0: return("16");
	case 1: return("8");
	case 2: return("4");
	case 3: return("*");
	}
	return("*");
}

char *
visd8ival(v)
{	
	switch(v) {
	case 0: return("unison");
	case 1: return("min 3rd");
	case 2: return("maj 3rd");
	case 3: return("4th");
	case 4: return("5th");
	case 5: case 6: case 7: return("*");
	}
	return("*");
}

char *
visd8detu(v)
{
	switch(v) {
	case 0: return("in tune");
	case 1: return("1 cent");
	case 2: return("2 cents");
	case 3: return("3 cents");
	case 4: return("4 cents");
	case 5: return("5 cents");
	case 6: return("6 cents");
	case 7: return("*");
	}
	return("*");
}

char *Semicode[] = {
	"none",
	"1 semitone",
	"2 semitones",
	"3 semitones",
	"4 semitones",
	"5 semitones",
	"6 semitones",
	"7 semitones",
	"8 semitones",
	"9 semitones",
	"10 semitones",
	"11 semitones",
	"1 octave"
};

char *
visd8sem(v)
{
	if(v >= 0 && v <= 12) {
		return(Semicode[v]);
	}
	return("*");
}

char *
visd8asel(v)
{
	switch(v) {
	case 0: return("off");
	case 1: return("Osc 1");
	case 2: return("Osc 2");
	case 3: return("Osc 1+2");
	}
	return("*");
}

char *
visd8amod(v)
{
	switch(v) {
	case 0: return("Up");
	case 1: return("Down");
	}
	return("*");
}

char *
visd8pol(v)
{
	switch(v) {
	case 0: return("/-\\");
	case 1: return("\\_/");
	}
	return("*");
}

char *
visd8mode(v)
{
	switch(v) {
	case 0: return("Poly 1");
	case 1: return("Poly 2");
	case 2: return("Uni 1");
	case 3: return("Uni 2");
	}
	return("*");
}

char *
visd8mgw(v)
{
	switch(v) {
	case 0: return("/\\");
	case 1: return("|\\");
	case 2: return("/|");
	case 3: return("_|-|");
	}
	return("*");
}

char *
visd8trk(v)
{
	switch(v) {
	case 0: return("0");
	case 1: return("1/4");
	case 2: return("1/2");
	case 3: return("1");
	}
	return("*");
}

/* end */
SHAR_EOF
cat << \SHAR_EOF > k5.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Kawai K-5 Librarian - handles SINGLE and MULTI patches.
 * Functions are annotated if they work for SINGLE, MULTI, or both kinds.
 * Full editing not implemented - there are zillions of parameters,
 * and the huge LCD on the K-5 is actually quite easy to read and use.
 *
 * Alan Bland - att!druwy!mab
 */

#define OVERLAY2

#include "glib.h"

#define K5SINGLE	0
#define K5MULTI		1
#define K5MAGIC		0x5a3c

#define NERRS		5

extern char *visnum();

/* This array contains arbitrary screen labels (SINGLE) */
struct labelinfo Lk5sin[] = {
 3,10,"Sorry, no edit capability implemented for the K-5 yet.",
15,2,"+-------------------------+--------------+",
16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
17,2,"|",17,28,"|",17,43,"|",
18,2,"|h = left   q = quit      |Pitch",18,43,"|",
19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
20,2,"|k = up     J = Decrement |Duration      |",
21,2,"|l = right  K = Increment |Channel       |",
22,2,"|",22,28,"|",22,43,"|",
23,2,"+-------------------------+--------------+",
-1,-1,NULL
};

/* This array defines all the editable parameters. (SINGLE) */
struct paraminfo Pk5sin[] = {
"autopitch",	NULL,	-1,-1, 18, 38, visnum, 		0, 127, 60, 0,
"autovol",	NULL,	-1,-1, 19, 38, visnum, 		0, 127, 63, 0,
"autodur",	NULL,	-1,-1, 20, 38, visnum, 		1,  20,  5, 0,
"autochan",	NULL,	-1,-1, 21, 38, visnum, 		1,  16,  1, 0,

NULL,		NULL,	-1,-1, -1, -1, visnum, 		0,   0, 0, 0
};

/* This array contains arbitrary screen labels (MULTI) */
struct labelinfo Lk5mul[] = {
 3,10,"Sorry, no edit capability implemented for the K-5 yet.",
15,2,"+-------------------------+--------------+",
16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
17,2,"|",17,28,"|",17,43,"|",
18,2,"|h = left   q = quit      |Pitch",18,43,"|",
19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
20,2,"|k = up     J = Decrement |Duration      |",
21,2,"|l = right  K = Increment |Channel       |",
22,2,"|",22,28,"|",22,43,"|",
23,2,"+-------------------------+--------------+",
-1,-1,NULL
};

/* This array defines all the editable parameters. (MULTI) */
struct paraminfo Pk5mul[] = {
"autopitch",	NULL,	-1,-1, 18, 38, visnum, 		0, 127, 60, 0,
"autovol",	NULL,	-1,-1, 19, 38, visnum, 		0, 127, 63, 0,
"autodur",	NULL,	-1,-1, 20, 38, visnum, 		1,  20,  5, 0,
"autochan",	NULL,	-1,-1, 21, 38, visnum, 		1,  16,  1, 0,

NULL,		NULL,	-1,-1, -1, -1, visnum, 		0,   0, 0, 0
};

/*
 * k5vnum
 *
 * Convert a voice number (0 to 47) to the string displayed in the
 * librarian (A1-D12)  (SINGLE and MULTI)
 */
char *
k5vnum(n)
register int n;
{
	static char v[4];

	if ( n < 0 || n > 47 )
		return("??");

	sprintf(v, "%c%d", n/12 + 'A', n%12 + 1);
	return(v);
}

/*
 * k5numv
 *
 * Convert an alphanumeric voice number (A1-D12) to internal
 * format (0 - 47).  (SINGLE and MULTI)
 */
k5numv(n)
register char *n;
{
	register int v,j;

	/* first better be [a-dA-D] */
	*n = toupper(*n);
	if (*n == 'A' || *n == 'B' || *n == 'C' || *n == 'D') {
		v = 12 * (*n - 'A');
	} else {
		return(-1);
	}

	/* followed by 1-12 */
	j = atoi(++n);
	if (j<1 || j>12) return(-1);
	return v + j - 1;
}

/*
 * k5sindin
 *
 * Take library bank 'data' and stuff values in the P array, by using
 * the setval function.
 */
k5sindin(data)
char *data;
{
	/* We set the 'auto-note' channel upon entry */
	setval("autochan",Channel);
}

/*
 * k5sindout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into the library bank 'data'.
 */
k5sindout(data)
char *data;
{
	/* If the autochan parameter has changed, update Channel */
	Channel = getval("autochan");
}

/*
 * k5muldin
 *
 * Take library bank 'data' and stuff values in the P array, by using
 * the setval function.
 */
k5muldin(data)
char *data;
{
	/* We set the 'auto-note' channel upon entry */
	setval("autochan",Channel);
}

/*
 * k5muldout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into the library bank 'data'.
 */
k5muldout(data)
char *data;
{
	/* If the autochan parameter has changed, update Channel */
	Channel = getval("autochan");
}

/*
 * k5sinnof
 *
 * Return a pointer to the voice name buried in library bank data. (SINGLE)
 */
char *
k5sinnof(data)
register char *data;
{
	static char currbuff[9];
	register char *p;
	register int m;

	p = currbuff;
	for ( m=0; m<16; m+=2 )
		*p++ = (data[m]<<4) | data[m+1];
	*p = '\0';
	return(currbuff);
}

/*
 * k5nameok
 *
 * Convert an ascii string to the ascii subset used for K5 names.
 */
char*
k5nameok(name)
char *name;
{
	static char okname[9];
	register int m;

	for (m=0; m<9 && name[m]; ++m) {
		okname[m] = toupper(name[m]);
		if (!isalnum(okname[m])) {
			switch (okname[m]) {
			case '-': case ':': case '/': case '*': case '?':
			case '!': case '#': case '&': case '(': case ')':
			case '"': case '+': case '.': case '=': case ' ':
				break;
			default:
				okname[m] = ' ';
				break;
			}
		}
	}
	okname[m] = '\0';
	return okname;
}

/*
 * k5sinsnof
 *
 * Set the voice name buried in data to name. (SINGLE)
 */
k5sinsnof(data,name)
char *data;
char *name;
{
	register char *p;
	register int m;

	for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
		data[m] = (*p & 0xf0) >> 4;
		data[m+1] = *p & 0x0f;
	}
	for ( ; m<17; m+=2 ) {
		data[m] = (' ' & 0xf0) >> 4;
		data[m+1] = ' ' & 0x0f;
	}
}
/*
 * k5mulnof
 *
 * Return a pointer to the voice name buried in library bank data. (MULTI)
 */
char *
k5mulnof(data)
char *data;
{
	static char currbuff[9];
	register char *p;
	register int m;

	p = currbuff;
	for ( m=0; m<16; m+=2 )
		*p++ = (data[m+330]<<4) | data[m+331];
	*p = '\0';
	return(currbuff);
}

/*
 * k5mulsnof
 *
 * Set the voice name buried in data to name. (MULTI)
 */
k5mulsnof(data,name)
char *data;
char *name;
{
	char *p;
	int m;

	for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
		data[m+330] = (*p & 0xf0) >> 4;
		data[m+331] = *p & 0x0f;
	}
	for ( ; m<17; m+=2 ) {
		data[m+330] = (' ' & 0xf0) >> 4;
		data[m+331] = ' ' & 0x0f;
	}
}

/*
 * k5sbulk
 *
 * common function to send all voices to the K-5 (SINGLE and MULTI)
 */
k5sbulk(data, which)
char *data;
int which;	/* K5SINGLE or K5MULTI */
{
	int n, err = 0;
	message("");
	for (n=0; n<Nvoices; ++n) {
		for (err=0; err<NERRS; ++err) {
			if (k5sone(n, &(VOICEBYTE(data,n,0)), which ) == 0 ) {
				windputc('+');
				windrefresh();
				break;
			}
			windputc('-');
			windrefresh();
		}
		if (err == NERRS) return(1);
	}
	return(0);
}

/*
 * k5sinsbulk
 *
 * send all voices to the K-5 (SINGLE)
 */
k5sinsbulk(data)
char *data;
{
	return k5sbulk(data, K5SINGLE);
}

/*
 * k5mulsbulk
 *
 * send all voices to the K-5 (MULTI)
 */
k5mulsbulk(data)
char *data;
{
	return k5sbulk(data, K5MULTI);
}

/*
 * k5sinsone
 *
 * send one voice to the K-5 (SINGLE)
 */
k5sinsone(iv, data)
int iv;
char *data;
{
	return k5sone(iv, data, K5SINGLE);
}

/*
 * k5mulsone
 *
 * send one voice to the K-5 (MULTI)
 */
k5mulsone(iv, data)
{
	return k5sone(iv, data, K5MULTI);
}

/*
 * k5sone
 *
 * common function to send a SINGLE or MULTI voice to the K-5.
 */
k5sone(iv, data, which)
int iv;
register char *data;
int which;	/* K5SINGLE or K5MULTI */
{
	register int i, sum;
	int length;
	int c = 0, ret = 1;
	long begin, toolong;

	flushmidi();

	length = (which == K5SINGLE) ? 984 : 352;

	/* calculate checksum */
	for (sum=0, i=0; i<length-4; ) {
		sum += data[i++] << 4;
		sum += data[i++];
		sum += data[i++] << 12;
		sum += data[i++] << 8;
	}

	sum = K5MAGIC - sum;
	data[length-4] = (sum & 0x00f0) >> 4;
	data[length-3] = (sum & 0x000f);
	data[length-2] = (sum & 0xf000) >> 12;
	data[length-1] = (sum & 0x0f00) >> 8;
	
	sendmidi(0xf0);
	sendmidi(0x40);
	sendmidi(Channel-1);
	sendmidi(0x20);
	sendmidi(0x00);
	sendmidi(0x02);
	sendmidi(which);
	sendmidi(iv);

	for (i=0; i<length; i++) sendmidi(data[i]);

	sendmidi(EOX);

	/* read the ack/nack - set up for timeout */
	begin = milliclock();
	toolong = begin + 1000 * TIMEOUT;

	/* wait for the acknowledgement */
	while ( milliclock() < toolong ) {
		if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
			break;
	}
	if ( c != 0xf0 ) {
		Reason = "Timeout waiting for K-5 response";
		goto getout;
	}
	
	/* third byte after the sysex begin is the result */
	for (i=0; i<3; ) {
		/* wait for midi byte or timeout */
		while ( ! STATMIDI ) {
			if ( milliclock() > toolong ) {
				Reason = "Timeout waiting for K-5 response";
				goto getout;
			}
		}
		/* ignore active sensing */
		if ((c = getmidi() & 0xff) != 0xfe) {
			++i;
		}
	}

	/* check the result */
	switch (c) {
	case 0x40:
		ret = 0;
		Reason = "";
		break;
	case 0x41:
		Reason = "K-5 write error";
		break;
	case 0x42:
		Reason = "K-5 write error (protected)";
		break;
	case 0x43:
		Reason = "K-5 write error (no card)";
		break;
	default:
		Reason = "Wierd response (is that really a K-5 you have?)";
		break;
	}

getout:
	return(ret);
}

k5sinsedit()
{
}

k5mulsedit()
{
}

/*
 * k5singbulk
 *
 * get all internal SINGLE voices from K-5.
 */
k5singbulk(data)
char *data;
{
	return k5gbulk(data, K5SINGLE);
}

/*
 * k5mulgbulk
 *
 * get all internal MULTI voices from K-5.
 */
k5mulgbulk(data)
char *data;
{
	return k5gbulk(data, K5MULTI);
}

/*
 * k5gbulk
 *
 * common routine - get all SINGLE or MULTI voices from K-5.
 */
k5gbulk(data, which)
register char *data;
int which;	/* K5SINGLE or K5MULTI */
{
	int c, v, sumerr = 0;
	register int n, i, sum;
	long begin, toolong;

	message("");
	flushmidi();

	for(v = 0; v < Nvoices; v++) {

retry:		
		if (which == K5MULTI) {
			/* i don't know if this is a K-5 or Amiga problem */
			/* but multi patch download seems to need this delay */
			millisleep(500);
		}
		/* request the voice */
		sendmidi(0xf0);
		sendmidi(0x40);
		sendmidi(Channel-1);
		sendmidi(0x00);
		sendmidi(0x00);
		sendmidi(0x02);
		sendmidi(which);
		sendmidi(v);
		sendmidi(EOX);
	
		/* set up for timeout */
		begin = milliclock();
		toolong = begin + 1000 * TIMEOUT;
	
		/* wait for the xf0 byte starting the dump */
		while ( milliclock() < toolong ) {
			if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
				break;
		}
		if ( c != 0xf0 ) {
			Reason = "Timeout waiting for dump from K-5";
			return 1;
		}
/*printf("%02x ", c);*/
		/* skip the next 7 bytes (remainder of sysex header) */
		for (i=0; i<7; ) {
			/* wait for midi byte or timeout */
			while ( ! STATMIDI ) {
				if ( milliclock() > toolong )
					goto timeout;
			}
			/* ignore active sensing */
			if ((c = getmidi() & 0xff) != 0xfe) {
				++i;
/*printf("%02x ", c);*/
			}
		}

		/* read voice data until EOX */
		n = 0;
		while (1) {
			/* wait for midi byte or timeout */
			while ( ! STATMIDI ) {
				if ( milliclock() > toolong )
					goto timeout;
			}
			if ((c = getmidi() & 0xff) == 0xfe) {
				/* ignore active sensing */
				continue;
			} else if (c == EOX) {
				/* finished */
				break;
			} else {
				/* got a data byte */
				VOICEBYTE(data,v,n) = c;
				++n;
			}
		}
/*printf("got block n=%d\n", n);*/
		/* verify the checksum */
		for (sum=0, i=0; i<n-4; ) {
			sum += data[i++] << 4;
			sum += data[i++];
			sum += data[i++] << 12;
			sum += data[i++] << 8;
		}

		sum = K5MAGIC - sum;
		if ((data[n-4] == (sum & 0x00f0) >> 4) &&
		    (data[n-3] == (sum & 0x000f)) &&
		    (data[n-2] == (sum & 0xf000) >> 12) &&
		    (data[n-1] == (sum & 0x0f00) >> 8)) {
			sumerr = 0;
			windputc('+');
		} else {
			/* retry a few times if checksum failed */
			windputc('-');
			if (sumerr++ >= NERRS) {
				Reason = "Too many checksum errors!";
				return(1);
			}
			goto retry;
		}
		windrefresh();

	} /* go back for another voice */
	Reason = "";
	return(0);

timeout:
	Reason = "Timeout while reading!";
	return(1);
}

SHAR_EOF
cat << \SHAR_EOF > tx81p.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * TX81Z routines for Performance parameters
 */

#define OVERLAY1

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

char *visnum(), *vis1num(), *viseffect(), *visass(), *viskey();
char *vischan(), *visnote(), *vistdetune(), *vistout(), *vislfo();
char *visponoff(), *vispvoice(), *vispshift();

static char Pbuff[17];

#define PMEMSIZE 76
#define PCEDSIZE 110

/* This array contains arbitrary screen labels */
struct labelinfo Ltx81p[] = {
1,17," 1      2      3      4      5      6      7      8",
2,17,"---    ---    ---    ---    ---    ---    ---    ---",
3,2,"Voice",
7,2,"Max Notes",
8,2,"Receive Ch.",
9,2,"Limit Low",
10,2,"Limit High",
11,2,"Detune",
12,2,"Note Shift",
13,2,"Volume",
14,2,"Out Assign",
15,2,"LFO Select",
16,2,"Micro Tune",
21,0,"-------------------------+",
22,0,"Auto-Note:               |",
23,0,"                         |",
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Ptx81p[] = {
"autopitch",	"Pitch",22, 11, 22, 17, visnum, 0, 127, 60, 0,
"autovol",	"Vol",	23, 0, 23, 4, visnum, 0, 127, 63, 0,
"autodur",	"Dur",	23, 8, 23, 12, visnum, 1, 20, 5, 0,
"autochan",	"Chan",	23, 16, 23, 21, visnum, 1, 16, 1, 0,

"op1max",	NULL, -1, -1, 7, 18, visnum, 0, 8, 0, 0,
"op1voice",	NULL, -1, -1, 3, 17, vispvoice, 0, 159, 0, 0,
"op1rec",	NULL, -1, -1, 8, 18, vischan, 0, 16, 0, 0,
"op1liml",	NULL, -1, -1, 9, 18, visnote, 0, 127, 0, 0,
"op1limh",	NULL, -1, -1, 10, 18, visnote, 0, 127, 0, 0,
"op1detune",	NULL, -1, -1, 11, 18, vistdetune, 0, 14, 0, 0,
"op1shift",	NULL, -1, -1, 12, 18, vispshift, 0, 48, 0, 0,
"op1vol",	NULL, -1, -1, 13, 18, visnum, 0, 99, 0, 0,
"op1out",	NULL, -1, -1, 14, 18, vistout, 0, 3, 0, 0,
"op1lfo",	NULL, -1, -1, 15, 18, vislfo, 0, 3, 0, 0,
"op1micro",	NULL, -1, -1, 16, 18, visponoff, 0, 1, 0, 0,

"op2max",	NULL, -1, -1, 7, 25, visnum, 0, 8, 0, 0,
"op2voice",	NULL, -1, -1, 3, 24, vispvoice, 0, 159, 0, 0,
"op2rec",	NULL, -1, -1, 8, 25, vischan, 0, 16, 0, 0,
"op2liml",	NULL, -1, -1, 9, 25, visnote, 0, 127, 0, 0,
"op2limh",	NULL, -1, -1, 10, 25, visnote, 0, 127, 0, 0,
"op2detune",	NULL, -1, -1, 11, 25, vistdetune, 0, 14, 0, 0,
"op2shift",	NULL, -1, -1, 12, 25, vispshift, 0, 48, 0, 0,
"op2vol",	NULL, -1, -1, 13, 25, visnum, 0, 99, 0, 0,
"op2out",	NULL, -1, -1, 14, 25, vistout, 0, 3, 0, 0,
"op2lfo",	NULL, -1, -1, 15, 25, vislfo, 0, 3, 0, 0,
"op2micro",	NULL, -1, -1, 16, 25, visponoff, 0, 1, 0, 0,

"op3max",	NULL, -1, -1, 7, 32, visnum, 0, 8, 0, 0,
"op3voice",	NULL, -1, -1, 3, 31, vispvoice, 0, 159, 0, 0,
"op3rec",	NULL, -1, -1, 8, 32, vischan, 0, 16, 0, 0,
"op3liml",	NULL, -1, -1, 9, 32, visnote, 0, 127, 0, 0,
"op3limh",	NULL, -1, -1, 10, 32, visnote, 0, 127, 0, 0,
"op3detune",	NULL, -1, -1, 11, 32, vistdetune, 0, 14, 0, 0,
"op3shift",	NULL, -1, -1, 12, 32, vispshift, 0, 48, 0, 0,
"op3vol",	NULL, -1, -1, 13, 32, visnum, 0, 99, 0, 0,
"op3out",	NULL, -1, -1, 14, 32, vistout, 0, 3, 0, 0,
"op3lfo",	NULL, -1, -1, 15, 32, vislfo, 0, 3, 0, 0,
"op3micro",	NULL, -1, -1, 16, 32, visponoff, 0, 1, 0, 0,

"op4max",	NULL, -1, -1, 7, 39, visnum, 0, 8, 0, 0,
"op4voice",	NULL, -1, -1, 3, 38, vispvoice, 0, 159, 0, 0,
"op4rec",	NULL, -1, -1, 8, 39, vischan, 0, 16, 0, 0,
"op4liml",	NULL, -1, -1, 9, 39, visnote, 0, 127, 0, 0,
"op4limh",	NULL, -1, -1, 10, 39, visnote, 0, 127, 0, 0,
"op4detune",	NULL, -1, -1, 11, 39, vistdetune, 0, 14, 0, 0,
"op4shift",	NULL, -1, -1, 12, 39, vispshift, 0, 48, 0, 0,
"op4vol",	NULL, -1, -1, 13, 39, visnum, 0, 99, 0, 0,
"op4out",	NULL, -1, -1, 14, 39, vistout, 0, 3, 0, 0,
"op4lfo",	NULL, -1, -1, 15, 39, vislfo, 0, 3, 0, 0,
"op4micro",	NULL, -1, -1, 16, 39, visponoff, 0, 1, 0, 0,

"op5max",	NULL, -1, -1, 7, 46, visnum, 0, 8, 0, 0,
"op5voice",	NULL, -1, -1, 3, 45, vispvoice, 0, 159, 0, 0,
"op5rec",	NULL, -1, -1, 8, 46, vischan, 0, 16, 0, 0,
"op5liml",	NULL, -1, -1, 9, 46, visnote, 0, 127, 0, 0,
"op5limh",	NULL, -1, -1, 10, 46, visnote, 0, 127, 0, 0,
"op5detune",	NULL, -1, -1, 11, 46, vistdetune, 0, 14, 0, 0,
"op5shift",	NULL, -1, -1, 12, 46, vispshift, 0, 48, 0, 0,
"op5vol",	NULL, -1, -1, 13, 46, visnum, 0, 99, 0, 0,
"op5out",	NULL, -1, -1, 14, 46, vistout, 0, 3, 0, 0,
"op5lfo",	NULL, -1, -1, 15, 46, vislfo, 0, 3, 0, 0,
"op5micro",	NULL, -1, -1, 16, 46, visponoff, 0, 1, 0, 0,

"op6max",	NULL, -1, -1, 7, 53, visnum, 0, 8, 0, 0,
"op6voice",	NULL, -1, -1, 3, 52, vispvoice, 0, 159, 0, 0,
"op6rec",	NULL, -1, -1, 8, 53, vischan, 0, 16, 0, 0,
"op6liml",	NULL, -1, -1, 9, 53, visnote, 0, 127, 0, 0,
"op6limh",	NULL, -1, -1, 10, 53, visnote, 0, 127, 0, 0,
"op6detune",	NULL, -1, -1, 11, 53, vistdetune, 0, 14, 0, 0,
"op6shift",	NULL, -1, -1, 12, 53, vispshift, 0, 48, 0, 0,
"op6vol",	NULL, -1, -1, 13, 53, visnum, 0, 99, 0, 0,
"op6out",	NULL, -1, -1, 14, 53, vistout, 0, 3, 0, 0,
"op6lfo",	NULL, -1, -1, 15, 53, vislfo, 0, 3, 0, 0,
"op6micro",	NULL, -1, -1, 16, 53, visponoff, 0, 1, 0, 0,

"op7max",	NULL, -1, -1, 7, 60, visnum, 0, 8, 0, 0,
"op7voice",	NULL, -1, -1, 3, 59, vispvoice, 0, 159, 0, 0,
"op7rec",	NULL, -1, -1, 8, 60, vischan, 0, 16, 0, 0,
"op7liml",	NULL, -1, -1, 9, 60, visnote, 0, 127, 0, 0,
"op7limh",	NULL, -1, -1, 10, 60, visnote, 0, 127, 0, 0,
"op7detune",	NULL, -1, -1, 11, 60, vistdetune, 0, 14, 0, 0,
"op7shift",	NULL, -1, -1, 12, 60, vispshift, 0, 48, 0, 0,
"op7vol",	NULL, -1, -1, 13, 60, visnum, 0, 99, 0, 0,
"op7out",	NULL, -1, -1, 14, 60, vistout, 0, 3, 0, 0,
"op7lfo",	NULL, -1, -1, 15, 60, vislfo, 0, 3, 0, 0,
"op7micro",	NULL, -1, -1, 16, 60, visponoff, 0, 1, 0, 0,

"op8max",	NULL, -1, -1, 7, 67, visnum, 0, 8, 0, 0,
"op8voice",	NULL, -1, -1, 3, 66, vispvoice, 0, 159, 0, 0,
"op8rec",	NULL, -1, -1, 8, 67, vischan, 0, 16, 0, 0,
"op8liml",	NULL, -1, -1, 9, 67, visnote, 0, 127, 0, 0,
"op8limh",	NULL, -1, -1, 10, 67, visnote, 0, 127, 0, 0,
"op8detune",	NULL, -1, -1, 11, 67, vistdetune, 0, 14, 0, 0,
"op8shift",	NULL, -1, -1, 12, 67, vispshift, 0, 48, 0, 0,
"op8vol",	NULL, -1, -1, 13, 67, visnum, 0, 99, 0, 0,
"op8out",	NULL, -1, -1, 14, 67, vistout, 0, 3, 0, 0,
"op8lfo",	NULL, -1, -1, 15, 67, vislfo, 0, 3, 0, 0,
"op8micro",	NULL, -1, -1, 16, 67, visponoff, 0, 1, 0, 0,

"microtune",	"Micro Tune Table", 19, 32, 19, 53, visnum, 0, 12, 0, 0,
"microkey",	"Micro Tune Key", 20, 32, 20, 53, viskey, 0, 11, 0, 0,
"assmode",	"Assign Mode", 21, 32, 21, 53, visass, 0, 1, 0, 0,
"effect",	"Effect Select", 22, 32, 22, 53, viseffect, 0, 3, 0, 0,
NULL,	NULL, -1, -1, -1, -1, visnum, 0, 0, 0, 0
};

char *tx81voices[] = {
	"GrandPiano", "Uprt piano", "Deep Grd", "HonkeyTonk", "Elec Grand",
	"Fuzz Piano", "SkoolPiano", "Thump Pno", "LoTine81Z", "HiTine81Z",
	"ElectroPno", "NewElectro", "DynomiteEP", "DynoWurlie", "Wood Piano",
	"Reed Piano", "PercOrgan", "16 8 4 2 F", "PumpOrgan", "<6 Tease>",
	"Farcheeza", "Small Pipe", "Big Church", "AnalogOrgn", "Thin Clav",
	"EZ Clav", "Fuzz Clavi", "LiteHarpsi", "RichHarpsi", "Celeste",
	"BriteCelst", "Squeezebox",

	"Trumpet81Z", "Full Brass", "Flugelhorn", "ChorusBras", "FrenchHorn",
	"AtackBrass", "SpitBoneBC", "Horns BC", "MelloTenor", "RaspAlto",
	"Flute", "Pan Floot", "Bassoon", "Oboe", "Clarinet",
	"Harmonica", "DoubleBass", "BowCello", "BoxCello", "SoloViolin",
	"HiString 1", "LowString", "Pizzicato", "Harp", "ReverbStrg",
	"SynString", "Voices", "HarmoPad", "FanfarTpts", "HiString 2",
	"PercFlute", "BreathOrgn",

	"NylonGuit", "Guitar #1", "TwelveStrg", "Funky Pick", "AllThatJaz",
	"HeavyMetal", "Old Banjo", "Zither", "ElecBass 1", "SqncrBass",
	"SynFunkBas", "ElecBass 2", "AnalogBass", "Jaco Bass", "LatelyBass",
	"MonophBass", "StadiumSol", "TrumptSolo", "BCSexyPhon", "Lyrisyn",
	"WarmSquare", "Sync Lead", "MellowSqar", "Jazz Flute", "HeavyLead",
	"Java Jive", "Xylophone", "GreatVibes	", "Sitar", "Bell Pad",
	"PlasticHit", "DigiAnnie",

	"BaadBreath", "VocalNuts", "KrstlChoir", "Metalimba", "WaterGlass",
	"BowedBell", ">>WOW<<", "Fuzzy Koto", "Spc Midiot", "Gurgle",
	"Hole in 1", "Birds", "MalibuNite", "Helicopter", "Flight Sim",
	"Brthbells", "Storm Wind", "Alarm Call", "Racing Car", "Whistling",
	"Space Talk", "Space Vibe", "Timpani", "FM Hi-Hats", "Bass Drum",
	"Tube Bells", "Noise Shot", "Snare 1", "Snare 2", "Hand Drum",
	"Synballs", "Efem Toms"
};

/*
 * tx8pdin
 *
 * Take info from 'data' and stuff values in the P array, by using
 * the setval (and setopval) functions.  The data is in PMEM format.
 */

tx8pdin(data)
char *data;
{
	int dop, n, msb;

	for ( n=1; n<=8; n++ ) {
		dop = (n-1)*8;
		setopval(n,"max",data[0+dop] & 017);
		msb = (data[0+dop]>>4)&01;
		setopval(n,"voice",128*msb + (data[1+dop]&0177));
		setopval(n,"rec",data[2+dop] & 037);
		setopval(n,"liml",data[3+dop] & 0177);
		setopval(n,"limh",data[4+dop] & 0177);
		setopval(n,"detune",data[5+dop] & 017);
		setopval(n,"shift",data[6+dop] & 077);
		setopval(n,"vol",data[7+dop] & 0177);
		setopval(n,"out",(data[0+dop]>>5) & 03);
		setopval(n,"lfo",(data[2+dop]>>5) & 03);
		setopval(n,"micro",(data[6+dop]>>6) & 01);
	}
	setval("microtune",data[64] & 017);
	setval("assmode",data[65] & 01);
	setval("effect",(data[65]>>1) & 03);
	setval("microkey",(data[65]>>3) & 017);

	setval("autochan",Channel);
}

/*
 * tx8pdout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into 'data'.
 */

tx8pdout(data)
char *data;
{
	int dop, n, voicenum, msb;

	for ( n=1; n<=8; n++ ) {
		dop = (n-1)*8;
		voicenum = getopval(n,"voice");
		msb = (voicenum>>7)&01;
		data[0+dop] = getopval(n,"max") | (msb<<4)
				| getopval(n,"out")<<5;
		data[1+dop] = voicenum & 0177;
		data[2+dop] = getopval(n,"lfo")<<5 | getopval(n,"rec");
		data[3+dop] = getopval(n,"liml");
		data[4+dop] = getopval(n,"limh");
		data[5+dop] = getopval(n,"detune");
		data[6+dop] = getopval(n,"micro")<<6 | getopval(n,"shift");
		data[7+dop] = getopval(n,"vol");
	}
	data[64] = getval("microtune");
	data[65] = getval("microkey")<<3 | getval("effect")<<1
			| getval("assmode");
	Channel = getval("autochan");
}

tx8psedit(data)
char *data;
{
	char pdata[PCEDSIZE];
	int n, cksum, c;
	char *p;

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

/* Convert PMEM to PCED format */
pmemtopced(indata,outdata)
char *indata, *outdata;
{
	int n, inop, outop;

	for ( n=1; n<=8; n++ ) {
		inop = (n-1)*8;
		outop = (n-1)*12;

		outdata[0+outop] = indata[0+inop] & 017;

		outdata[1+outop] = (indata[0+inop]>>4)&01;
		outdata[2+outop] = indata[1+inop] & 0177;
		outdata[3+outop] = indata[2+inop] & 037;
		outdata[4+outop] = indata[3+inop] & 0177;
		outdata[5+outop] = indata[4+inop] & 0177;
		outdata[6+outop] = indata[5+inop] & 017;
		outdata[7+outop] = indata[6+inop] & 077;
		outdata[8+outop] = indata[7+inop] & 0177;
		outdata[9+outop] = (indata[0+inop]>>5) & 03;
		outdata[10+outop] = (indata[2+inop]>>5) & 03;
		outdata[11+outop] = (indata[6+inop]>>6) & 01;
	}
	outdata[96] = indata[64] & 017;
	outdata[97] = indata[65] & 01;
	outdata[98] = (indata[65]>>1) & 03;
	outdata[99] = (indata[65]>>3) & 017;
	for ( n=0; n<10; n++ )
		outdata[100+n] = indata[66+n];
}

/* send a bulk performance dump to the tx81z */
tx8psbulk(data)
char *data;
{
	int c, v, n, cksum;
	char *p;

	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(Channel-1);	/* Channel # */
	sendmidi(0x7e);
	sendmidi(0x13);
	sendmidi(0x0a);
	p = "LM  8976PM";
	cksum = 0;
	while ( (c=(int)(*p++)) != '\0' ) {
		sendmidi(c);
		cksum += c;
	}
	/* send 32 PMEM's worth of data */
	for ( v=0; v<32; v++ ) {
		for ( n=0; n<PMEMSIZE; n++ ) {
			/* 24 PMEM's are editable, but the bulk dump has 32 */
			if ( v >= 24 )
				c = 0;
			else
				c = VOICEBYTE(data,v,n);
			sendmidi(c & 0xff);
			cksum += c;
		}
	}
	sendmidi((-cksum) & 0x7f);
	sendmidi(0xf7);
}

/* Request and read a bulk performance dump from the TX81Z */
tx8pgbulk(data)
char *data;
{
	int c, n, v, b1, b2, cksum, ret = 1;
	long begin, toolong;
	char *p;

	flushmidi();

	sendmidi(0xf0);
	sendmidi(0x43);
	sendmidi(0x20 | (Channel-1));	/* Channel # */
	sendmidi(0x7e);
	p = "LM  8976PM";
	while ( (c=(int)(*p++)) != '\0' )
		sendmidi(c);
	sendmidi(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;
	}
	/* get the 14 bytes preceeding the data */
	for ( cksum=n=0; n<14; n++ ) {
		/* twiddle your thumbs, but not forever */
		while ( ! STATMIDI ) {
			if ( milliclock() > toolong )
				goto timeout;	/* the end of an era */
		}
		c = getmidi();
		if(n >= 4)
			cksum += c; /* start of LM... keyword */
	}
	/* 32 memories are dumped */
	for ( v=0; v<32; v++ ) {
		for ( n=0; n<PMEMSIZE; 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 memories are used */
			if ( v < 24 )
				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);
}

char *
tx8pnof(data)
char *data;
{
	int n;

	for ( n=0; n<10; n++ )
		Pbuff[n] = data[66+n];
	Pbuff[10] = '\0';
	return(Pbuff);
} 

tx8psnof(data,name)
char *data, *name;
{
	int n;

	for ( n=0; name[n]!='\0' && n<10; n++ )
		data[66+n] = name[n];
	for ( ; n<10; n++ )
		data[66+n] = ' ';
} 

char *
visass(v)
{
	switch(v){
	case 0: return("normal");
	case 1: return("alternate");
	}
	return("");
}

char *
viskey(v)
{
	switch(v){
	case 0: return("C");
	case 1: return("C#");
	case 2: return("D");
	case 3: return("D#");
	case 4: return("E");
	case 5: return("F");
	case 6: return("F#");
	case 7: return("G");
	case 8: return("G#");
	case 9: return("A");
	case 10: return("A#");
	case 11: return("B");
	}
	return("");
}

char *
viseffect(v)
{
	switch(v){
	case 0: return("none");
	case 1: return("delay");
	case 2: return("pan");
	case 3: return("chord");
	}
	return("");
}

char *
vischan(v)
{
	if ( v >= 0 && v <= 15 ) {
		sprintf(Pbuff,"%d",v+1);
		return(Pbuff);
	}
	if ( v == 16 )
		return("omni");
	return("");
}

char *
visnote(v)
{
	int octave;

	octave = (v/12) - 2;
	sprintf(Pbuff,"%s%d",viskey(v%12),octave);
	return(Pbuff);
}

char *
vispshift(v)
{
	sprintf(Pbuff,"%d",v-24);
	return(Pbuff);
}

char *
vistdetune(v)
{
	sprintf(Pbuff,"%d",v-7);
	return(Pbuff);
}

char *
vistout(v)
{
	switch (v) {
	case 0: return("off");
	case 1: return("I");
	case 2: return("II");
	case 3: return("I+II");
	}
	return("");
}

char *
vislfo(v)
{
	switch (v) {
	case 0: return("off");
	case 1: return("inst1");
	case 2: return("inst2");
	case 3: return("vib");
	}
	return("");
}

char *
visponoff(v)
{
	switch(v){
	case 0: return("off");
	case 1: return("on");
	}
	return("");
}

char *
vispvoice(v)
{
	char *p, *prefixes = "IABCD";
	int bank, vnum, vindex;

	bank = v/32;
	vnum = (v%32) + 1;
	sprintf(Pbuff,vnum<10?"%c0%d":"%c%d",prefixes[bank],vnum);
	if ( bank > 0 ) {
		vindex = (bank-1)*32+vnum-1;
		if ( vindex >= 0 && vindex < 128 ) {
			strcat(Pbuff,"~d~l~l~l");
			p = tx81voices[vindex];
			if ( strlen(p) <= 5 )
				strcat(Pbuff,p);
			else {
				char buff[11];
				strcpy(buff,p);
				buff[5] = '\0';
				strcat(Pbuff,buff);
				strcat(Pbuff,"~d~l~l~l~l~l");
				strcat(Pbuff,&p[5]);
			}
		}
	}
	return(Pbuff);
}
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.