/*
 * 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

#define RESERVESIZE 0

/* This array contains arbitrary screen labels */
struct labelinfo Ltx81p[] = {
#MENU

                  1      2      3      4      5      6      7      8
                 ---    ---    ---    ---    ---    ---    ---    ---
  Voice          %      %      %      %      %      %      %      %



  Max Notes       %      %      %      %      %      %      %      %
  Receive Ch.     %      %      %      %      %      %      %      %
  Limit Low       %      %      %      %      %      %      %      %
  Limit High      %      %      %      %      %      %      %      %
  Detune          %      %      %      %      %      %      %      %
  Note Shift      %      %      %      %      %      %      %      %
  Volume          %      %      %      %      %      %      %      %
  Out Assign      %      %      %      %      %      %      %      %
  LFO Select      %      %      %      %      %      %      %      %
  Micro Tune      %      %      %      %      %      %      %      %


                                Micro Tune Table     %
                                Micro Tune Key       %
-------------------------+      Assign Mode          %
Auto-Note: Pitch %       |      Effect Select        %
Vol %   Dur %   Chan %   |
#END
-1,-1,NULL
};

struct paraminfo  Ptx81p[] =  {
/*
NAME		TYPE	POS	MAX	OFFSET	MASK	SHIFT	ADHOC
 */
#O op1voice	pvoice	%%	159	0
#O op2voice	pvoice	%%	159	0
#O op3voice	pvoice	%%	159	0
#O op4voice	pvoice	%%	159	0
#O op5voice	pvoice	%%	159	0
#O op6voice	pvoice	%%	159	0
#O op7voice	pvoice	%%	159	0
#O op8voice	pvoice	%%	159	0
#O op1max	num	%%	8	0
#O op2max	num	%%	8	0
#O op3max	num	%%	8	0
#O op4max	num	%%	8	0
#O op5max	num	%%	8	0
#O op6max	num	%%	8	0
#O op7max	num	%%	8	0
#O op8max	num	%%	8	0
#O op1rec	chan	%%	16	0
#O op2rec	chan	%%	16	0
#O op3rec	chan	%%	16	0
#O op4rec	chan	%%	16	0
#O op5rec	chan	%%	16	0
#O op6rec	chan	%%	16	0
#O op7rec	chan	%%	16	0
#O op8rec	chan	%%	16	0
#O op1liml	note	%%	127	0
#O op2liml	note	%%	127	0
#O op3liml	note	%%	127	0
#O op4liml	note	%%	127	0
#O op5liml	note	%%	127	0
#O op6liml	note	%%	127	0
#O op7liml	note	%%	127	0
#O op8liml	note	%%	127	0
#O op1limh	note	%%	127	0
#O op2limh	note	%%	127	0
#O op3limh	note	%%	127	0
#O op4limh	note	%%	127	0
#O op5limh	note	%%	127	0
#O op6limh	note	%%	127	0
#O op7limh	note	%%	127	0
#O op8limh	note	%%	127	0
#O op1detune	tdetune	%%	14	0
#O op2detune	tdetune	%%	14	0
#O op3detune	tdetune	%%	14	0
#O op4detune	tdetune	%%	14	0
#O op5detune	tdetune	%%	14	0
#O op6detune	tdetune	%%	14	0
#O op7detune	tdetune	%%	14	0
#O op8detune	tdetune	%%	14	0
#O op1shift	pshift	%%	48	0
#O op2shift	pshift	%%	48	0
#O op3shift	pshift	%%	48	0
#O op4shift	pshift	%%	48	0
#O op5shift	pshift	%%	48	0
#O op6shift	pshift	%%	48	0
#O op7shift	pshift	%%	48	0
#O op8shift	pshift	%%	48	0
#O op1vol	num	%%	99	0
#O op2vol	num	%%	99	0
#O op3vol	num	%%	99	0
#O op4vol	num	%%	99	0
#O op5vol	num	%%	99	0
#O op6vol	num	%%	99	0
#O op7vol	num	%%	99	0
#O op8vol	num	%%	99	0
#O op1out	tout	%%	3	0
#O op2out	tout	%%	3	0
#O op3out	tout	%%	3	0
#O op4out	tout	%%	3	0
#O op5out	tout	%%	3	0
#O op6out	tout	%%	3	0
#O op7out	tout	%%	3	0
#O op8out	tout	%%	3	0
#O op1lfo	lfo	%%	3	0
#O op2lfo	lfo	%%	3	0
#O op3lfo	lfo	%%	3	0
#O op4lfo	lfo	%%	3	0
#O op5lfo	lfo	%%	3	0
#O op6lfo	lfo	%%	3	0
#O op7lfo	lfo	%%	3	0
#O op8lfo	lfo	%%	3	0
#O op1micro	ponoff	%%	1	0
#O op2micro	ponoff	%%	1	0
#O op3micro	ponoff	%%	1	0
#O op4micro	ponoff	%%	1	0
#O op5micro	ponoff	%%	1	0
#O op6micro	ponoff	%%	1	0
#O op7micro	ponoff	%%	1	0
#O op8micro	ponoff	%%	1	0
#O microtune	num	%%	12	0
#O microkey	key	%%	11	0
#O assmode	ass	%%	1	0
#O autopitch	num	%%	127	-60
#O effect	effect	%%	3	0
#O autochan	num	%%	16	-1	*5
#O autodur	num	%%	20	-5	*5
#O autovol	num	%%	127	-63
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);
}
