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