/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * MicroWave support, by Tim Thompson
 *
 * Function names and other things use the following prefix convention -
 * an 'm' (for MicroWave) followed by 2 characters:
 *
 *    msp - Single Patches
 *    mmp - Multi Patches
 *    muw - User Waves (the waveforms)
 *    mwt - Wave Tables (control tables)
 *
 * These values are also used as the suffixes on file names, e.g.
 * files containing single patches are called *.msp.
 *
 * On UNIX (or any system for which getenv() works), you can
 * set the TABLEOFFSET and WAVEOFFSET variables to get access to
 * the other sections of the tables and waves (the ROM ones).
 * However, you shouldn't have to do that, since I've already done
 * it and stored the results in the following files (which should be
 * in this directory or in the samples directory):
 *
 *	mwave00_11.mwt		The Wave Tables in ROM positions 0-11
 *	mwave12_23.mwt		ditto ...
 *	mwave16_27.mwt		ditto ...
 *
 *	mwave000_060.muw	The Waves in ROM positions 0-60
 *	mwave061_121.muw	ditto ...
 *	mwave122_182.muw	ditto ...
 *	mwave183_243.muw
 *
 * You can also set the WAVEDEVICE variable to control the DeviceID.
 */

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

#define WAVEOFFSET 246
#define TABLEOFFSET 32
#define WAVESIZE 128
#define TABLESIZE 256
#define WAVEDEVICE 0

char *visnum(), *vissamp();
#ifdef unix
char *getenv();
#endif

/* This is the screen setup fo the User Wave editor */
struct labelinfo Lmuw[] = {
5,0,"h = left",
6,0,"l = right",
7,0,"k = up",
8,0,"j = down",
9,0,"K = incr",
10,0,"J = decr",
11,0,"q = quit",
13,0,"Pitch",
14,0,"Vol",
15,0,"Dur",
16,0,"Chan",
17,0,"<sp>=note",
# line 22 "mwave.mnu"
-1,-1,NULL
};

struct paraminfo  Pmuw[] =  {
/*
NAME		TYPE	POS	MAX	OFFSET	MASK	SHIFT	ADHOC
 */
"autopitch",NULL,-1,-1,13,6,visnum,0,127,60,0,
"autovol",NULL,-1,-1,14,5,visnum,0,127,63,0,
"autodur",NULL,-1,-1,15,6,visnum,1,20,5,0,
"autochan",NULL,-1,-1,16,5,visnum,1,16,1,0,
"sample1",NULL,-1,-1,18,13,vissamp,0,255,0,0,
"sample2",NULL,-1,-1,18,14,vissamp,0,255,0,0,
"sample3",NULL,-1,-1,18,15,vissamp,0,255,0,0,
"sample4",NULL,-1,-1,18,16,vissamp,0,255,0,0,
"sample5",NULL,-1,-1,18,17,vissamp,0,255,0,0,
"sample6",NULL,-1,-1,18,18,vissamp,0,255,0,0,
"sample7",NULL,-1,-1,18,19,vissamp,0,255,0,0,
"sample8",NULL,-1,-1,18,20,vissamp,0,255,0,0,
"sample9",NULL,-1,-1,18,21,vissamp,0,255,0,0,
"sample10",NULL,-1,-1,18,22,vissamp,0,255,0,0,
"sample11",NULL,-1,-1,18,23,vissamp,0,255,0,0,
"sample12",NULL,-1,-1,18,24,vissamp,0,255,0,0,
"sample13",NULL,-1,-1,18,25,vissamp,0,255,0,0,
"sample14",NULL,-1,-1,18,26,vissamp,0,255,0,0,
"sample15",NULL,-1,-1,18,27,vissamp,0,255,0,0,
"sample16",NULL,-1,-1,18,28,vissamp,0,255,0,0,
"sample17",NULL,-1,-1,18,29,vissamp,0,255,0,0,
"sample18",NULL,-1,-1,18,30,vissamp,0,255,0,0,
"sample19",NULL,-1,-1,18,31,vissamp,0,255,0,0,
"sample20",NULL,-1,-1,18,32,vissamp,0,255,0,0,
"sample21",NULL,-1,-1,18,33,vissamp,0,255,0,0,
"sample22",NULL,-1,-1,18,34,vissamp,0,255,0,0,
"sample23",NULL,-1,-1,18,35,vissamp,0,255,0,0,
"sample24",NULL,-1,-1,18,36,vissamp,0,255,0,0,
"sample25",NULL,-1,-1,18,37,vissamp,0,255,0,0,
"sample26",NULL,-1,-1,18,38,vissamp,0,255,0,0,
"sample27",NULL,-1,-1,18,39,vissamp,0,255,0,0,
"sample28",NULL,-1,-1,18,40,vissamp,0,255,0,0,
"sample29",NULL,-1,-1,18,41,vissamp,0,255,0,0,
"sample30",NULL,-1,-1,18,42,vissamp,0,255,0,0,
"sample31",NULL,-1,-1,18,43,vissamp,0,255,0,0,
"sample32",NULL,-1,-1,18,44,vissamp,0,255,0,0,
"sample33",NULL,-1,-1,18,45,vissamp,0,255,0,0,
"sample34",NULL,-1,-1,18,46,vissamp,0,255,0,0,
"sample35",NULL,-1,-1,18,47,vissamp,0,255,0,0,
"sample36",NULL,-1,-1,18,48,vissamp,0,255,0,0,
"sample37",NULL,-1,-1,18,49,vissamp,0,255,0,0,
"sample38",NULL,-1,-1,18,50,vissamp,0,255,0,0,
"sample39",NULL,-1,-1,18,51,vissamp,0,255,0,0,
"sample40",NULL,-1,-1,18,52,vissamp,0,255,0,0,
"sample41",NULL,-1,-1,18,53,vissamp,0,255,0,0,
"sample42",NULL,-1,-1,18,54,vissamp,0,255,0,0,
"sample43",NULL,-1,-1,18,55,vissamp,0,255,0,0,
"sample44",NULL,-1,-1,18,56,vissamp,0,255,0,0,
"sample45",NULL,-1,-1,18,57,vissamp,0,255,0,0,
"sample46",NULL,-1,-1,18,58,vissamp,0,255,0,0,
"sample47",NULL,-1,-1,18,59,vissamp,0,255,0,0,
"sample48",NULL,-1,-1,18,60,vissamp,0,255,0,0,
"sample49",NULL,-1,-1,18,61,vissamp,0,255,0,0,
"sample50",NULL,-1,-1,18,62,vissamp,0,255,0,0,
"sample51",NULL,-1,-1,18,63,vissamp,0,255,0,0,
"sample52",NULL,-1,-1,18,64,vissamp,0,255,0,0,
"sample53",NULL,-1,-1,18,65,vissamp,0,255,0,0,
"sample54",NULL,-1,-1,18,66,vissamp,0,255,0,0,
"sample55",NULL,-1,-1,18,67,vissamp,0,255,0,0,
"sample56",NULL,-1,-1,18,68,vissamp,0,255,0,0,
"sample57",NULL,-1,-1,18,69,vissamp,0,255,0,0,
"sample58",NULL,-1,-1,18,70,vissamp,0,255,0,0,
"sample59",NULL,-1,-1,18,71,vissamp,0,255,0,0,
"sample60",NULL,-1,-1,18,72,vissamp,0,255,0,0,
"sample61",NULL,-1,-1,18,73,vissamp,0,255,0,0,
"sample62",NULL,-1,-1,18,74,vissamp,0,255,0,0,
"sample63",NULL,-1,-1,18,75,vissamp,0,255,0,0,
"sample64",NULL,-1,-1,18,76,vissamp,0,255,0,0,
NULL,NULL,-1,-1,-1,-1,visnum,0,0,0,0
};

#define SOUNDSIZE 180
#define MULTISIZE 226

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

	if ( n < 32 )
		sprintf(v,"A%02d",n+1);
	else
		sprintf(v,"B%02d",n+1-32);
	return(v);
}

int
mwchecksum(p,n)
char *p;
int n;
{
	int sum = 0;
	while ( n-- > 0 ) {
		sum += *p++;
		if ( sum >= 0x80 )
			sum -= 0x80;
	}
	return sum;
}

#define NOFFSET 148

char *
mspnof(data)
char *data;
{
	static char currbuff[17];
	char *p;
	int m, c;

	p = currbuff;
	for ( m=0; m<16; m++ ) {
		c = data[NOFFSET+m];
		*p++ = (isprint(c) ? c : ' ');
	}
	*p = '\0';
	return(currbuff);
}

mspsnof(data,name)
char *data;
char *name;
{
	char *p;
	int m;

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

int
mspsbulk(data)
char *data;
{
	int n, c;
	char *p = data;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x50);
	for ( n=0; n<(SOUNDSIZE*64); n++ )
		sendmidi(*p++);
	c = mwchecksum(data,SOUNDSIZE*64);
	sendmidi(c);
	sendmidi(EOX);
	return 0;
}

char *
mwgetit(p,skip,sz,suminit)
char *p;
int skip;
int sz;
int suminit;
{
	static char msg[100];
	char *origp = p;
	int state = 0;
	int nc = 0;
	int sum = suminit;
	long begin = milliclock();
	long toolong = begin + 3 * 1000 * TIMEOUT;
	int csum, c;

	while ( milliclock() < toolong && state < 3 ) {
		while ( STATMIDI ) {
			c = getmidi()&0xff;
			switch (state) {
			case 0:	/* first 'skip' bytes */
				if ( ++nc >= skip ) {
					state = 1;
					nc = 0;
				}
				break;
			case 1:
				*p++ = c;
				sum += c;
				if ( sum >= 0x80 )
					sum -= 0x80;
				if ( ++nc >= sz ) { 
					state = 2;
					nc = 0;
				}
				break;
			case 2:
				if ( ++nc == 1 )
					csum = c;
				if ( nc == 2 )
					state = 3;
				break;
			}
		}
	}
	if ( csum != sum ) {
		sprintf(msg,"Incorrect checksum (sum=0x%x csum=0x%x)",sum,csum);
		return msg;
	}
	if ( c != 0xf7 )
		return "Didn't get 0xf7!?";
	return NULL;
}

int
mspgbulk(data)
char *data;
{
	int c;
	char *p = data;
	char *m;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x10);
	sendmidi(0x00);
	sendmidi(0xf7);

	if ( (m=mwgetit(p,5,SOUNDSIZE*64,0)) != NULL ) {
		Reason = m;
		return 1;
	}
	Reason = "Done.";
	return 0;
}

int
mspsedit(data)
char *data;
{
	int n, c;
	char *p = data;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x42);
	for ( n=0; n<SOUNDSIZE; n++ )
		sendmidi(*p++);
	c = mwchecksum(data,SOUNDSIZE);
	sendmidi(c);
	sendmidi(EOX);
	return 0;
}

#define MNOFFSET 10

char *
mmpnof(data)
char *data;
{
	static char currbuff[17];
	char *p;
	int m, c;

	p = currbuff;
	for ( m=0; m<16; m++ ) {
		c = data[MNOFFSET+m];
		*p++ = (isprint(c) ? c : ' ');
	}
	*p = '\0';
	return(currbuff);
}

mmpsnof(data,name)
char *data;
char *name;
{
	char *p;
	int m;

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

int
mmpsbulk(data)
char *data;
{
	int n, c;
	char *p = data;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x51);
	for ( n=0; n<(MULTISIZE*64); n++ )
		sendmidi(*p++);
	c = mwchecksum(data,MULTISIZE*64);
	sendmidi(c);
	sendmidi(EOX);
	return 0;
}

int
mmpgbulk(data)
char *data;
{
	int c;
	char *p = data;
	char *m;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x11);
	sendmidi(0x00);
	sendmidi(0xf7);

	if ( (m=mwgetit(p,5,MULTISIZE*64,0)) != NULL ) {
		Reason = m;
		return 1;
	}
	Reason = "Done.";
	return 0;
}

int
mmpsedit(data)
char *data;
{
	int n, c;
	char *p = data;

	flushmidi();
	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x43);
	for ( n=0; n<MULTISIZE; n++ )
		sendmidi(*p++);
	c = mwchecksum(data,MULTISIZE);
	sendmidi(c);
	sendmidi(EOX);
	return 0;
}

char *
muwnof(data)
char *data;
{
	static char buff[32];
	sprintf(buff,"%d,%d,%d,%d..",
		(data[0]&0xff)*16 + data[1]&0xff,
		(data[2]&0xff)*16 + data[3]&0xff,
		(data[4]&0xff)*16 + data[5]&0xff,
		(data[6]&0xff)*16 + data[7]&0xff);
	return(buff);
}

/*ARGSUSED*/
muwsnof(data,name)
char *data;
char *name;
{
}

int
muwsendit(wn,p)
int wn;
char *p;
{
	char b[4];
	int n, sum;

	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x44);

	b[0] = (wn >> 12) & 0xf ;
	b[1] = (wn >> 8) & 0xf ;
	b[2] = (wn >> 4) & 0xf ;
	b[3] = wn & 0xf ;
	sendmidi(b[0]);
	sendmidi(b[1]);
	sendmidi(b[2]);
	sendmidi(b[3]);
	sum = mwchecksum(b,4);
	sum += mwchecksum(p,WAVESIZE);
	if ( sum >= 0x80 )
		sum -= 0x80;

	for ( n=0; n<WAVESIZE; n++ )
		sendmidi(*p++);

	sendmidi(sum);
	sendmidi(0xf7);
}

int
muwsbulk(data)
char *data;
{
	int wn, n;
	char *p = data;
	char buff[8];

	flushmidi();
	windstr("       ");
	for ( wn=0; wn<61; wn++ ) {
		n = muwoffset() + wn;
		muwsendit(n,p);
		p += WAVESIZE;
		sprintf(buff,"\b\b\b%03d",n);
		windstr(buff);
		windrefresh();
		millisleep(500);
	}
	return 0;
}

int
muwsone(wn,data)
int wn;
char *data;
{
	flushmidi();
	muwsendit(muwoffset() + wn,data);
	return 0;
}

int
muwgbulk(data)
char *data;
{
	int c, tn, wn, wnsum, woff;
	char *p, *m;
	char b[4];

	woff = muwoffset();
	flushmidi();
	p = data;
	for ( tn=0; tn<61; tn++ ) {
		sendmidi(0xf0);
		sendmidi(0x3e);
		sendmidi(0x00);
		sendmidi(mwdevice());
		sendmidi(0x04);
		wn = woff + tn;
		b[0] = (wn >> 12) & 0xf ;
		b[1] = (wn >> 8) & 0xf ;
		b[2] = (wn >> 4) & 0xf ;
		b[3] = wn & 0xf ;
		sendmidi(b[0]);
		sendmidi(b[1]);
		sendmidi(b[2]);
		sendmidi(b[3]);
		wnsum = mwchecksum(b,4);
		sendmidi(wnsum);
		sendmidi(0xf7);

		if ( (m=mwgetit(p,9,WAVESIZE,wnsum)) != NULL ) {
			Reason = m;
			return 1;
		}
		p += WAVESIZE;
	}
	Reason = "Done.";
	return 0;
}

/*ARGSUSED*/
int
muwsedit(data)
char *data;
{
	return 0;
}

char *
muwvnum(n)
{
	static char v[8];

	sprintf(v,"%03d",n+muwoffset());
	return(v);
}

int
mwtoffset()
{
	static int offset = -1;

	if ( offset < 0 ) {
#ifdef unix
		char *p;
		if ( (p=getenv("TABLEOFFSET")) != NULL )
			offset = atoi(p);
		else
#endif
			offset = TABLEOFFSET;
	}
	return offset;
}

int
muwoffset()
{
	static int offset = -1;

	if ( offset < 0 ) {
#ifdef unix
		char *p;
		if ( (p=getenv("WAVEOFFSET")) != NULL )
			offset = atoi(p);
		else
#endif
			offset = WAVEOFFSET;
	}
	return offset;
}

int
mwdevice()
{
	static int dev = -1;

	if ( dev < 0 ) {
#ifdef unix
		char *p;
		if ( (p=getenv("WAVEDEVICE")) != NULL )
			dev = atoi(p);
		else
#endif
			dev = WAVEDEVICE;
	}
	return dev;
}

int
mwtgbulk(data)
char *data;
{
	int tn, t;
	int toff = mwtoffset();
	char *p, *m;

	flushmidi();
	p = data;
	for ( t=0; t<12; t++ ) {
		sendmidi(0xf0);
		sendmidi(0x3e);
		sendmidi(0x00);
		sendmidi(mwdevice());
		sendmidi(0x05);
		tn = toff + t;
		sendmidi(tn);
		sendmidi(tn);	/* checksum */
		sendmidi(0xf7);

		if ( (m=mwgetit(p,6,TABLESIZE,tn)) != NULL ) {
			Reason = m;
			return 1;
		}
		p += TABLESIZE;
	}
	Reason = "Done.";
	return 0;
}

int
mwtsedit(data)
char *data;
{
	return 0;
}

char *
mwtvnum(n)
{
	static char v[8];

	sprintf(v,"%02d",n+mwtoffset());
	return(v);
}

int
mwtcvtnum(p)
char *p;
{
	int n;
	sscanf(p,"%d",&n);
	n -= mwtoffset();
	return n;
}

int
muwcvtnum(p)
char *p;
{
	int n;
	sscanf(p,"%d",&n);
	n -= muwoffset();
	return n;
}

char *
mwtnof(d)
char *d;
{
	static char buff[16];
	long v1, v2, v3;

	v1 = ((d[0]&0xf)*16*16*16)+((d[1]&0xf)*16*16)+((d[2]&0xf)*16)+(d[3]&0xf);
	if ( v1 == 0xffff )
		v1 = -1;
	v2 = ((d[4]&0xf)*16*16*16)+((d[5]&0xf)*16*16)+((d[6]&0xf)*16)+(d[7]&0xf);
	if ( v2 == 0xffff )
		v2 = -1;
	v3 = ((d[8]&0xf)*16*16*16)+((d[9]&0xf)*16*16)+((d[10]&0xf)*16)+(d[11]&0xf);
	if ( v3 == 0xffff )
		v3 = -1;
	sprintf(buff,"%ld,%ld,%ld...", v1, v2, v3);
	return(buff);
}

mwtsnof(data,name)
char *data;
char *name;
{
}

int
mwtsbulk(data)
char *data;
{
	int t;
	int toff = mwtoffset();
	char *p = data;

	flushmidi();

	for ( t=0; t<12; t++ ) {
		mwtsendit(toff+t,p);
		millisleep(1000);
		p += TABLESIZE;
	}
	return 0;
}

int
mwtsone(t,data)
int t;
char *data;
{
	flushmidi();
	mwtsendit(t+mwtoffset(),data);
	return 0;
}

mwtsendit(tn,p)
int tn;
char *p;
{
	int i, sum, o, n;

	sendmidi(0xf0);
	sendmidi(0x3e);
	sendmidi(0x00);
	sendmidi(mwdevice());
	sendmidi(0x45);
	sendmidi(tn);

	/* force last 3 positions to -1 */
	for ( i=61; i<64; i++ ) {
		o = i*4;
		p[o+0] = 0xf;
		p[o+1] = 0xf;
		p[o+2] = 0xf;
		p[o+3] = 0xf;
	}

	sum = mwchecksum(p,TABLESIZE);
	sum += tn;
	if ( sum >= 0x80 )
		sum -= 0x80;
	for ( n=0; n<TABLESIZE; n++ )
		sendmidi(*p++);
	sendmidi(sum);
	sendmidi(EOX);
}

int
muwdin(data)
char *data;
{
	int n;
	char nm[16];

	for ( n=0; n<64; n++ ) {
		sprintf(nm,"sample%d",n+1);
		setval(nm, data[2*n]*16 + data[2*n+1]);
	}
	return 0;
}

int
muwdout(data)
char *data;
{
	int n, v;
	char nm[16];

	for ( n=0; n<64; n++ ) {
		sprintf(nm,"sample%d",n+1);
    		v = getval(nm);
    		data[2*n] = (v>>4) & 0xf;
    		data[2*n+1] = v & 0xf;
	}
	return 0;
}

int
mwtdin(data)
char *data;
{
	int n;
	long v;
	char nm[16];

	for ( n=0; n<61; n++ ) {
		sprintf(nm,"wave%d",n);
		v = (data[4*n+0]&0xf)*16*16*16 + (data[4*n+1]&0xf)*16*16
			+ (data[4*n+2]&0xf)*16 + (data[4*n+3]&0xf);
		if ( v == 0xffff )
			v = 0;
		else
			v++;
		/* The parameter values are 0 to 506, representing */
		/* real values of -1 to 505. */
		setval(nm,(int)v);
	}
	return 0;
}

int
mwtdout(data)
char *data;
{
	int n, v;
	char nm[16];

	/* Make sure wave #'s 0 and 60 are valid */
	if ( getval("wave0") == 0 )
		setval("wave0", 1);
	if ( getval("wave60") == 0 )
		setval("wave60", 1);
	for ( n=0; n<61; n++ ) {
		sprintf(nm,"wave%d",n);
    		v = getval(nm) - 1;
		if ( v == -1 )
			data[4*n] = data[4*n+1] = data[4*n+2] = data[4*n+3] = 0xf;
		else {
			data[4*n]   = (v>>12) & 0xf;
			data[4*n+1] = (v>>8) & 0xf;
			data[4*n+2] = (v>>4) & 0xf;
			data[4*n+3] = v & 0xf;
		}
	}
	return 0;
}

char *
vissamp(v)
int v;
{
	char num[8];
	static char buff[100];
	int n, hgt;
	char *p, *pn;

	hgt = v / 16 + 1;
	sprintf(num,"%d",v);
	p = buff;
	pn = num;
	for ( n=strlen(num); n>0; n-- ) {
		*p++ = *pn++;
		*p++ = '~'; *p++ = 'l';
		*p++ = '~'; *p++ = 'd';
	}
	*p = '\0';
	for ( n=strlen(num); n>0; n-- ) {
		strcat(buff,"~u");
	}
	strcat(buff,"~u");
	for ( n=0; n<hgt; n++ ) {
		strcat(buff,"~u|~l");
	}
	return buff;
}

char *
vismwave(v)
int v;
{
	static char buff[8];
	/* the wave parameter values are 0 to 506, but the values they */
	/* really represent are -1 to 505 */
	sprintf(buff,"%d",v-1);
	return buff;
}

int
mwheader(f)
FILE *f;
{
	int c, n;

	/* look for 0xf0 that starts bank */
	while ( (c=getc(f)) != EOF && c != 0xf0 )
		;
	/* skip rest of sys-ex header */
	for ( n=0; n<4; n++ )
		getc(f);
}

int
mspfilein(f,p)
FILE *f;
char *p;
{
	int c, n;

	mwheader(f);
	for ( n=0; n<(SOUNDSIZE*64); n++ ) {
		if ( (c=getc(f)) == EOF )
			return 1;
		*p++ = c;
	}
	return 0;
}

int
mspfileout(f,p)
FILE *f;
char *p;
{
	int c, n;
	char *origp = p;

	putc(0xf0,f);
	putc(0x3e,f);
	putc(0x00,f);
	putc(mwdevice(),f);
	putc(0x50,f);
	for ( n=0; n<(SOUNDSIZE*64); n++ )
		putc(*p++,f);
	c = mwchecksum(origp,SOUNDSIZE*64);
	putc(c,f);
	putc(EOX,f);
	return 0;
}

int
mmpfilein(f,p)
FILE *f;
char *p;
{
	int c, n;

	mwheader(f);
	for ( n=0; n<(MULTISIZE*64); n++ ) {
		if ( (c=getc(f)) == EOF )
			return 1;
		*p++ = c;
	}
	return 0;
}

int
mmpfileout(f,p)
FILE *f;
char *p;
{
	int c, n;
	char *origp = p;

	putc(0xf0,f);
	putc(0x3e,f);
	putc(0x00,f);
	putc(mwdevice(),f);
	putc(0x51,f);
	for ( n=0; n<(MULTISIZE*64); n++ )
		putc(*p++,f);
	c = mwchecksum(origp,MULTISIZE*64);
	putc(c,f);
	putc(EOX,f);
	return 0;
}

int
muwfilein(f,p)
FILE *f;
char *p;
{
	int c, n;

	c = getc(f);
	if ( c == 0xdd ) {
		for ( n=0; n<(WAVESIZE*61); n++ ) {
			if ( (c=getc(f)) == EOF )
				return 1;
			*p++ = c;
		}
	}
	else {
		/* Here, we assume we're trying to read a */
		/* user wavetable & waves dump (code 0x53). */
		mwheader(f);
		/* The wavetables are first */
		for ( n=0; n<(TABLESIZE*12); n++ ) {
			if ( (c=getc(f)) == EOF )
				return 1;
		}
		for ( n=0; n<(WAVESIZE*61); n++ ) {
			if ( (c=getc(f)) == EOF )
				return 1;
			*p++ = c;
		}
	}
	return 0;
}

int
muwfileout(f,p)
FILE *f;
char *p;
{
	int c, n, wn;
	char *origp = p;

	putc(0xdd,f);
	for ( wn=0; wn<61; wn++ ) {
		for ( n=0; n<WAVESIZE; n++ )
			putc(*p++,f);
	}
	return 0;
}

int
mwtfilein(f,p)
FILE *f;
char *p;
{
	int c, n;

	c = getc(f);
	if ( c == 0xdd ) {
		for ( n=0; n<(TABLESIZE*12); n++ ) {
			if ( (c=getc(f)) == EOF )
				return 1;
			*p++ = c;
		}
	}
	else {
		/* Here, we assume we're trying to read a */
		/* user wavetable & waves dump (code 0x53). */
		mwheader(f);
		for ( n=0; n<(TABLESIZE*12); n++ ) {
			if ( (c=getc(f)) == EOF )
				return 1;
			*p++ = c;
		}
		/* ignore the waves at the end */
	}
	return 0;
}

int
mwtfileout(f,p)
FILE *f;
char *p;
{
	int c, n, i;
	char *origp = p;

	putc(0xdd,f);
	for ( n=0; n<12; n++ ) {
		for ( i=0; i<TABLESIZE; i++ )
			putc(*p++,f);
	}
	return 0;
}
