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

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

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

Glib (one syllable) is a text-screen-oriented librarian AND editor.
Supported synths are TX81Z (patches and performance), DX100, DEP5,
DW8000 and K-5.

[This version has the bugfix for the tx81z bulk dump.  ..Bob]

#	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:
#	README
#	amiga-mach.c
#	amiga-mach.h
#	amiga-make
#	dx100.c
#	glib.h
#	list.c
#	pc-mach.c
#	pc-mach.h
#	st-mach.c
#	st-mach.h
#	tx81z.c
#	unix-mach.c
#	unix-mach.h
#	unix-make
# This archive created: Thu Mar 16 11:42:06 1989
cat << \SHAR_EOF > README
glib (one syllable) - a Generic LIBrarian and editor for synths

Originally written by Tim Thompson, including the basic structure
and support for the TX81Z (patches and performance), DX100, and DEP5.  
Macintosh and DW8000 support by Steve Falco.  Amiga and minimal K-5
support by Alan Bland.

Intro
-----
glib (one syllable) is a text-screen-oriented librarian AND editor.
It is structured in an attempt to make it easy to add support for new
synthesizers.  Info on how to do this can be found later on in this README.
The librarian part of the program manipulates 1 synth bank of voices
(which can be uploaded to or downloaded from the synth), and 3
banks of library voices (which can be read/written to disk).  All synths
are supported simultaneously; you can switch back and forth and the
library banks and other settings (e.g. MIDI channel) for each are retained. 

You can run glib on UNIX (it uses curses), although obviously most UNIX
machines don't have MIDI I/O.  Trying it out on UNIX will give you a
feel for what the program does, so you can decide whether or not it's
worth the trouble to port it to your MIDI-capable PC.

Included is at least 1 bank of voices for each synth type that glib supports.
The bank files (ending in .uu) are uuencoded.  You need to run uudecode to
produce the real binary file for each.  The suffix conventions:

	.dx1 == dx100
	.tx8 == tx81z
	.t8p == tx81performance
	.dw8 == dw8000
	.k5s == K-5 single patches
	.k5m == K-5 multi patches

Compiling
---------
machdep.c and machdep.h are machine-dependent parts.  The *-mach.h and
*-mach.c files are the versions of these files for different machines,
e.g. unix-mach.[ch] is for UNIX, st-mach.[ch] is for the Atari ST.
Copy the proper files to machdep.c and machdep.h before compiling
for a particular machine.   For example, on UNIX, do the following:

	cp unix-mach.c machdep.c
	cp unix-mach.h machdep.h
	make glib

The contents of list.c control which synths are supported; modify
the defines at the beginning of that file appropriately.  When
compiling, you need to include glib.c and the appropriate synth
files (e.g. if you define DW8000 in list.c, then you need to compile
with dw8000.c).  A single version of glib can support as many synths
as you want, although some compilers may have size limitations or
overlay schemes that get in the way.

Using glib - Moving around
--------------------------
Both the librarian and editor parts of glib make use of h/j/k/l
to move the cursor around.  Control-l redraws the screen.  These
keys are #defined in glib.h, so you can change them if you want.
To quit from any mode, use 'q'.  In the librarian screen, '?' gives
a command summary.  'Esc' sends an all-notes-off.

Using glib - The librarian
--------------------------
The screen shows the synth bank on the left, and the current (1 of 3)
library bank on the right.  A '*' identifies the 'current' voice, and
you use h/j/k/l to move it around.  As soon as you move to a different
voice, it is sent to the 'edit buffer' of the synth, so it is very
easy to roam around and see what each voice sounds like.  Commands:

     b - Cycle through the (3) library banks, displayed on the
         right side of the screen.
     c - Set the MIDI channel for sending/receiving voices.
     d - Download from the (real) synthesizer, replacing the current
         contents of the synth bank.
     e - Edit the current voice (see editor description below).
     f - List the files on the disk.
     p - Put the yank buffer, replacing the contents of the current voice.
     q - Quit, going back to 'choose a synth'.
     r - Read a bank of voices from a file, replacing entirely
         the current library bank.
     s - Swap the current voice with the yank buffer.  2 swaps is a no-op.
     t - Transfer all voices, either from the current library bank to
         the synth bank, or vice versa.
     u - Upload the current contents of the synth bank to the synth.
         You are given a choice of sending the entire bank or just
         the current voice.
     w - Write the current library bank to a file.
     y - Yank the current voice into the yank buffer, shown
         in the middle of the screen.

Using glib - The editor
-----------------------
In the editor part, h/j/k/l move the cursor among the parameter
values.  The cursor will only land on parameter values.  Once on
a parameter value, the following keys will affect it:

     K - increase value by 1
     J - decrease value by 1
     I - increase value by 4
     M - decrease value by 4
     < - decrease value to its minimum
     > - increase value to its maximum

These keys are also defined in glib.h, and should be changed to
suit your own tastes.  I'm not thrilled with these choices, myself,
but I had to use something, and at least the hand stays in one place.

The 'auto-note' is played whenever you press the space bar.  This is
a convenient way of playing a note as soon as you make a change (ie.
you can do everything from the computer keyboard).  You can change the
auto-note parameters (pitch, duration, volume, channel) the same way as all
the other parameters.

Hacking glib - Internals
------------------------
The program is written so that support for a new synth can be added by
adding an entry to the array in list.c, describing the various attributes
of the synthesizer and the C functions to be called to control it.  And, of
course, you have to write those C functions.  Adding a new synth, for a
reasonable C programmer, might be described as mostly straightforward but
tedious.  People other than the original author HAVE done it, with no help.
Glib allows you to re-use the front-end interface of the librarian and
editor, but it does not relieve you of having to write C code which
interacts with the synth (which, depending on the synth, can of course be
easy or maddening) and with the raw data formats.  Naturally, using one of
the existing synth files as an example of how to do things is the best way
to start on a new one.

The 'E' array in list.c has the following structure:

struct editinfo {
	char *ed_name;		/* Synth name */
	struct paraminfo *ed_params;	/* list of parameters */
	struct labelinfo *ed_labels;	/* screen labels in edit mode */
	int ed_nvoices;		/* number of voices */
	int ed_vsize;		/* size of each voice data, in bytes */
	int ed_nsize;		/* name size */
	int (*ed_din)();	/* copy voice data into paraminfo array */
	int (*ed_dout)();	/* copy voice data out of paraminfo array */
	int (*ed_sedit)();	/* send 1 voice to synth edit buffer */
	int (*ed_sone)();	/* send 1 voice to a synth (permanent) patch*/
	int (*ed_sbulk)();	/* send bulk voice data */
	int (*ed_gbulk)();	/* get bulk voice data */
	char *(*ed_nof)();	/* get name of a voice out of data */
	int (*ed_snof)();	/* set name of a voice in data */
	char *(*ed_numof)();	/* convert voice number to on-screen text */
	int (*ed_cvtnum)();	/* convert visable voice number to std. format */
	int (*ed_cvtanum)();	/* convert alphanumeric voice number to std. format */
};

In glib, there are several relatively independent representations of
the synth voice data.  First, there is the data that is stored in the
library and synth banks (ie. the data used and manipulated via the
librarian screen).  This is the format of the data that is written to
and read from files (a single byte, '0xdd', is added to the beginning
of the file, to identify it).  The size of a single voice in this data
is 'ed_vsize'.  The number of voices in a bank is 'ed_nvoices', so the
amount of space taken up by a library bank is ed_vsize * ed_nvoices.

When a voice is edited, the voice data is copied into the parameter
array (see below), in p_val.  The 'ed_din' function is called to do this.
After a voice is edited, 'ed_dout' takes the updated parameter values 
and puts them back into the original data format.  Note that this means
that the bytes in the 'raw' voice data and the values in the parameter
array (ie. the values manipulated by the editor) need not be the same.
There are utility functions 'getval' and 'setval' which should be used
for getting and setting the values in the parameter array.  See dx100.c
for usage.

The ed_sedit, ed_sone, ed_sbulk, and ed_gbulk functions are called to
send voices to and get voices from the synthesizer.  Only one of ed_sone
and ed_sbulk need be defined, although ed_sone should be preferred.
(I had trouble getting the DX100 to accept a single permanent voice
change, so it always does a bulk voice transfer.)  The data passed to
these functions is in the library bank format.  The ed_gbulk function is
optional, so that write-only MIDI devices (like the DEP-5) are allowed.

The ed_nof function is called to pull the voice name out of the raw
voice data (as stored in the library banks), and it should return a
C string containing the name.  The ed_snof function is called to
stick a voice name into the raw voice data.  Note that the 'raw'
library bank voice data does NOT have to match the data that is
really sent to the synthesizer (by the ed_sedit and ed_sone functions).
For example, the DEP-5 does not have names as part of the voice data,
but that does not prevent glib from maintaining and storing (in the files)
voice names.  This holds for the DW-8000 as well.

The ed_numof function is called to convert the voice number to the
text that is displayed on the librarian screen.  This can handle
the odd numbering convention of the DW-8000.  If ed_numof==NULL, the
number is used as-is.  Otherwise, ed_numof is called with the voice
number MINUS 1 (i.e. 0-based); ed_numof should return a string
containing the desired display.  Likewise, the ed_cvtnum function is
used to convert user input from an odd numbering system to the standard
sequential internal representation (0 to whatever).

The ed_cvtanum function is an alternative to ed_cvtnum for synths that
use an alphanumeric represenation for patch number (e.g. the K-5 numbers
its patches A1 through D12).  The ed_cvtanum function takes a string
typed by the user and converts it to the standard sequential internal
representation.  You should not define both ed_cvtnum and ed_cvtanum
for the same synth.

The editor screen is controlled by two arrays, ed_labels and ed_params.
ed_labels contains arbitrary screen labels, in the following structure:

struct labelinfo {
	int l_row;	/* 0-based */
	int l_col;	/* 0-based */
	char *l_text;
};

The ed_params array is used to specify the parameters that the user can peruse
and change in the edit screen, and looks like this (one for each parameter):

struct paraminfo {
	char *p_name;		/* the parameter name */
	char *p_label;		/* on-screen label (possibly NULL) */
	int p_lrow;		/* position for printing label */
	int p_lcol;
	int p_vrow;		/* position for printing value */
	int p_vcol;
	char *((*p_tovis)());	/* function converts value to on-screen text*/
	int p_min;		/* minimum parameter value */
	int p_max;		/* maximum parameter value */
	int p_val;		/* parameter value */
	int p_flags;		/* flag to enable/disable parameter */
};

The editor calls p_tovis with a parameter value, and expects that function
to pass back a string which contains what should be displayed on the
screen for that value.  Often, this is just an 'sprintf' of the value,
or perhaps the value offset by something.  Or, it could be some text
that represents the value (e.g. "on" for 1 and "off" for 0).  Or, it could
be something more interesting, e.g. a picture of the voice algorithm.
The parameter value strings can make use of cursor motion, by including the
sequences ~d,~u,~l,~r to go down,up,left,right.  The dx100 and dep5 editors
use this to handle the display of the algorithm drawings.

A parameter can be 'disabled' by setting p_flags to non-zero.  The p_tovis
function can set the external variable 'Redraw' to 1 if it wants to force
the entire editor screen to be redrawn (e.g. after a parameter has been
disabled).

Support for a mouse has been added, although it is currently disabled
for the Atari, since I was having various hassles getting it under control.
It did work, but had various quirks.

Mouse support for the Amiga was added, and appears to work after fixing
a few problems in glib.c, so it may be possible to enable the Atari mouse
support now.

                             ...Tim Thompson...twitch!glimmer!tjt...
SHAR_EOF
cat << \SHAR_EOF > amiga-mach.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Amiga version.
 */

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

#include <dos.h>
#include <intuition/intuition.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <devices/serial.h>

#include <proto/exec.h>
#include <proto/intuition.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Screen *S;
struct Window *W;
struct RastPort *R;

int Rows, Cols;

#define TOPEDGE 8	/* how much of screen bar to show */
int WindowWidth = 640;
int WindowHeight = 200 - TOPEDGE;

/* standard WB colors */
#define BLUE 0
#define WHITE 1
#define BLACK 2
#define ORANGE 3


hello()
{
	windinit();
	openmidi();
}

bye()
{
	closemidi();
	windexit(0);
}

int MouseX, MouseY, MouseButtons;
int Mouseok = 0;

/* getmouse - get current row and column of mouse */
getmouse(amr,amc)
int *amr;
int *amc;
{
	*amr = MouseY / 8;
	*amc = MouseX / 8;
}

/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */
statmouse()
{
	nextevent(MOUSEBUTTONS, 0);
	return MouseButtons;
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
	return nextevent(MOUSEBUTTONS | VANILLAKEY, 1);
}

flushconsole()
{
	while (nextevent(VANILLAKEY, 0) >= 0) ;
}

getconsole()
{
	return nextevent(VANILLAKEY, 1);
}

cursor(state)
int state;
{
	int x, y;
	x = R->cp_x;
	y = R->cp_y - R->Font->tf_Baseline;
	SetDrMd(R, COMPLEMENT);
	RectFill(R, x, y, x+8, y+R->Font->tf_YSize-1);
	SetDrMd(R, JAM2);
}

nextevent(flags, wait)
long flags;
int wait;
{
	register int class, code;
	register struct IntuiMessage *message;
	int result;

	cursor(1);
	ModifyIDCMP(W, CLOSEWINDOW | flags);
	while (1)
	{
		if (wait)
		{
		    /* get next event, waiting if none are available */
		    while ((message = (struct IntuiMessage *)GetMsg(W->UserPort)) == NULL)
		    {
			Wait(1<<W->UserPort->mp_SigBit);
		    }
		}
		else
		{
		    /* get next event, but return if none are available */
		    message = (struct IntuiMessage *)GetMsg(W->UserPort);
		    if (message == NULL)
		    {
			result = -1;
			break;
		    }
		}
		class = message->Class;
		code = message->Code;
		MouseX = message->MouseX;
		MouseY = message->MouseY;
		ReplyMsg((struct Message *)message);

		switch (class)
		{
		case VANILLAKEY:
			result = code;
			break;
		case CLOSEWINDOW:
			result = 'q';
			break;
		case MOUSEBUTTONS:
			switch (code)
			{
			case SELECTDOWN:
				MouseButtons = 1;
				break;
			case MENUDOWN:
				MouseButtons = 2;
				break;
			default:
				MouseButtons = 0;
				break;
			}
			result = MOUSE;
			break;
		default:
			continue;
		}
		break;
	}
	cursor(0);
	return result;
}

/*------------------------------------------------------------------------
 * MIDI I/O Routines for Amiga.
 *
 * Uses low-level serial I/O for simultaneous reads and writes.
 */

struct MsgPort	*MidiInPort, *MidiOutPort;
struct IOExtSer	*MidiIn, *MidiOut;
int	SerOpen = 0;

char	MidiInBuf;
int	MidiDataAvail = 0;

/*
 * start an asynchronous read request from MIDI IN
 */

startmidiread()
{
	MidiIn->IOSer.io_Data = (APTR) &MidiInBuf;
	MidiIn->IOSer.io_Length = 1;
	MidiIn->IOSer.io_Command = CMD_READ;
	MidiIn->IOSer.io_Flags = IOF_QUICK;	/* use quick I/O */
	BeginIO((struct IORequest *) MidiIn);
	/* did I/O complete quickly? */
	if ((MidiIn->IOSer.io_Flags & IOF_QUICK)) {
		/* wow, data's coming in fast! */
		MidiDataAvail = 1;
	} else {
		/* no data this time, it'll arrive later */
		MidiDataAvail = 0;
	}
}

/*
 * get a byte from MIDI IN.
 * assumes startmidiread has been previously done.  if statmidi has been
 * checked, this function will not wait.  otherwise, it will wait for
 * a single byte to arrive if none is available.
 */

getmidi()
{
	register struct Message	*io;
	int result;

	/* return previously-received data, if available */
	if (MidiDataAvail) {
		result = MidiInBuf;
		/* start a new I/O */
		startmidiread();
		return result;
	}

	/* read next available byte */
	io = (struct Message *) CheckIO((struct IORequest *) MidiIn);
	if (io == FALSE) {
		/* wait for next byte */
		WaitIO((struct IORequest *) MidiIn);
		io = &MidiIn->IOSer.io_Message;
	}

	Remove(&io->mn_Node);
	result = MidiInBuf;
	startmidiread();	/* start I/O for next byte */
	return result;
}

/*
 * write a byte to MIDI OUT
 */

sendmidi(c)
int c;
{
	char	buf = c;

	MidiOut->IOSer.io_Data = (APTR) &buf;
	MidiOut->IOSer.io_Length = 1;
	MidiOut->IOSer.io_Command = CMD_WRITE;
	DoIO((struct IORequest *) MidiOut);	/* synchronous request */
}

/*
 * check if any midi data is waiting to be received
 */
statmidi()
{
	/* check if data has previously been received */
	if (MidiDataAvail) return 1;

	/* check if i/o has completed */
	return (CheckIO((struct IORequest *) MidiIn) == FALSE) ? 0 : 1;
}

openmidi()
{
	/* create message port for serial device */
	MidiInPort = (struct MsgPort *) CreatePort(SERIALNAME,0);
	if (MidiInPort == NULL) fatal("Can't create MidiInPort");

	/* create i/o request block for serial device */
	MidiIn = (struct IOExtSer *)
		CreateExtIO(MidiInPort, sizeof(struct IOExtSer));
	if (MidiIn == NULL) fatal("Can't create MidiIn");

	/* open the serial device */
	MidiIn->io_SerFlags = SERF_SHARED;
	SerOpen = OpenDevice(SERIALNAME,0,(struct IORequest *) MidiIn,0) == 0 ? 1 : 0;
	if (SerOpen == 0) fatal("Can't open serial.device");

	/* set serial device parameters */
	MidiIn->io_Baud = 31250;
	MidiIn->io_RBufLen = 8192;	/* large input buffer - if your synth
					 * sends dumps larger than this you
					 * will have to increase it. */
	MidiIn->io_SerFlags = SERF_RAD_BOOGIE;
	MidiIn->IOSer.io_Command = SDCMD_SETPARAMS;
	DoIO((struct IORequest *) MidiIn);

	/* clone MidiIn into MidiOut to allow simultaneous i/o */
	MidiOutPort = (struct MsgPort *) CreatePort("MidiOut",0);
	if (MidiOutPort == NULL) fatal("Can't create MidiOutPort");

	MidiOut = (struct IOExtSer *)
			CreateExtIO(MidiOutPort, sizeof(struct IOExtSer));
	*MidiOut = *MidiIn;
	MidiOut->IOSer.io_Message.mn_ReplyPort = MidiOutPort;

	/* get the MIDI IN port started */
	startmidiread();
}

closemidi()
{
	if (SerOpen) CloseDevice((struct IORequest *)MidiIn);
	if (MidiIn) DeleteExtIO((struct IORequest *)MidiIn);
	if (MidiOut) DeleteExtIO((struct IORequest *)MidiOut);
	if (MidiInPort) DeletePort(MidiInPort);
	if (MidiOutPort) DeletePort(MidiOutPort);
}

flushmidi()
{
	while ( STATMIDI )
		getmidi();
}

long milliclock()
{
	unsigned int clock[2];
	long milli;
	timer(clock);
	milli = clock[0] * 1000 + clock[1] / 1000;
	return milli;
}

millisleep(n)
{
	Delay(n/20);
}

char *
alloc(n)
{
	char *p;

	if ( (p=malloc((unsigned)n)) == (char *)NULL ) {
		fatal("GLIB is out of memory!");
	}
	return(p);
}

struct TextAttr font =
{
	"topaz.font",TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT
};

struct NewScreen ns =
{
	0,0,640,200,2,BLACK,WHITE,HIRES,CUSTOMSCREEN,&font,"",NULL,NULL
};

windinit()
{
	struct NewWindow nw;

	if (S != NULL) return;

	IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0);
	GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0);
	if (IntuitionBase == NULL || GfxBase == NULL) exit(1);

	if ((S = (struct Screen *) OpenScreen(&ns)) == NULL) exit(1);

	nw.LeftEdge = 0;
	nw.TopEdge = TOPEDGE;
	nw.Width = WindowWidth;
	nw.Height = WindowHeight;
	nw.DetailPen = BLACK;
	nw.BlockPen = WHITE;
	nw.Title = NULL;
	nw.Flags = SMART_REFRESH | ACTIVATE | BACKDROP |
		   BORDERLESS | NOCAREREFRESH | RMBTRAP;
	nw.IDCMPFlags = CLOSEWINDOW | VANILLAKEY;
	nw.Type = CUSTOMSCREEN;
	nw.FirstGadget = NULL;
	nw.CheckMark = NULL;
	nw.Screen = S;
	nw.BitMap = NULL;
	if ((W = (struct Window *) OpenWindow(&nw)) == NULL) exit(1);
	R = W->RPort;
	SetAPen(R, ORANGE);
	SetBPen(R, BLACK);
	ShowTitle(S, FALSE);
	Cols=80;
	Rows=24;
}

windgoto(r,c)
int r,c;
{
	Move(R, c*8, r*8 + R->Font->tf_Baseline);
}

windeeol()
{
	int x, y;
	x = R->cp_x;
	y = R->cp_y  - R->Font->tf_Baseline;
	SetAPen(R, BLACK);
	RectFill(R, x, y, WindowWidth, y+R->Font->tf_YSize-1);
	SetAPen(R, ORANGE);
}

winderaserow(r)
{
	windgoto(r,0);
	windeeol();
}

windexit(r)
int r;
{
	if (W) CloseWindow(W);
	if (S) CloseScreen(S);
	exit(r);
}

windclear()
{
	SetAPen(R, BLACK);
	RectFill(R, 0, 0, WindowWidth, WindowHeight);
	SetAPen(R, ORANGE);
}

/* windgets - get a line of input from the console, handling backspaces */
windgets(s)
char *s;
{
	char *origs = s;
	int c;

	SetAPen(R, WHITE);
	while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				wbackspace();
				s--;
			}
		}
		else if (c == 24) {
			while (s > origs) {
				wbackspace();
				s--;
			}
		} else if (isprint(c)) {
			windputc(c);
			*s++ = c;
		}
		windrefresh();
	}
	*s = '\0';
	SetAPen(R, ORANGE);
}

windstr(s)
char *s;
{
	Text(R, s, strlen(s));
}

windputc(c)
int c;
{
	char s = c;
	Text(R, &s, 1);
}

wbackspace()
{
	int x, y;
	x = R->cp_x;
	y = R->cp_y;
	Move(R, x-8, y);
	windputc(' ');
	Move(R, x-8, y);
}

windrefresh()
{
}

beep()
{
	DisplayBeep(S);
}

windhigh()
{
}

windnorm()
{
}

struct IntuiText fataltext = { 1,0,COMPLEMENT,16,32,NULL,NULL,NULL };
struct IntuiText canceltext = { 1,0,COMPLEMENT,2,2,NULL,"cancel",NULL };

fatal(text)
char *text;
{
	fataltext.IText = text;
	AutoRequest(W, &fataltext, NULL, &canceltext, 0, 0, 320, 90);
	bye();
}

/****************
 * openls(), nextls(), and closels() are used to scan the current directory.
 ***************/

struct FileInfoBlock *lsinfo = NULL;

openls()
{
}

char *
nextls()
{
	int error;
	if (lsinfo == NULL) {
		lsinfo = (struct FileInfoBlock *) alloc(sizeof(struct FileInfoBlock));
		error = dfind(lsinfo, "#?", 0);
	} else {
		error = dnext(lsinfo);
	}
	if (error == 0) {
		return lsinfo->fib_FileName;
	} else {
		return NULL;
	}
}

closels()
{
	free(lsinfo);
	lsinfo = NULL;
}
SHAR_EOF
cat << \SHAR_EOF > amiga-mach.h
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Amiga version
 */

#include <string.h>

#define INT16 int

#define STATMIDI	statmidi()
SHAR_EOF
cat << \SHAR_EOF > amiga-make
#
# this makefile is for the AMIGA using the LMK utility and Lattice 5.02
#

OBJ = machdep.o glib.o list.o dx100.o tx81z.o tx81p.o dw8000.o yama_com.o k5.o
# OBJ = machdep.o glib.o list.o k5.o

.c.o :
	lc:lc -cw -cs -v $*

glib : $(OBJ)
	lc:blink from lib:c.o $(OBJ) lib lib:lc.lib lib:amiga.lib \
	batch nodebug to glib
SHAR_EOF
cat << \SHAR_EOF > dx100.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * DX-100 routines
 */

#define OVERLAY1

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

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

/* This array contains arbitrary screen labels */
struct labelinfo Ldx100[] = {
4,0,"           Dcy Lev Dcy              De  Out     Amp Eg  Key Key",
5,0," OP    Atk  1   1   2  Rls   Freq   tun Lvl Vel Mod Bia Rat Scl",
6,0," --    --- --- --- --- ---   ----   --- --- --- --- --- --- ---",
7,0," 1",
8,0," 2",
9,0," 3",
10,0," 4",
13,0,"-------------------------+",
14,0,"N = set name  q = quit   |",
15,0,"h = left      l = right  |",
16,0,"k = up        j = down   |",
17,0,"K = incr      J = decr   |",
18,0,"space = play auto-note   |",
19,0,"                         |",
20,0,"Auto-Note:               |",
21,0,"                         |",
22,0,"                         |",
23,0,"                         |",
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Pdx100[] = {
"autopitch",	"Pitch",21, 3, 21, 9, visnum, 0, 127, 60, 0,
"autovol",	"Vol",	21, 14, 21, 19, visnum, 0, 127, 63, 0,
"autodur",	"Dur",	22, 3, 22, 9, visnum, 1, 20, 5, 0,
"autochan",	"Chan",	22, 14, 22, 19, visnum, 1, 16, 1, 0,

"op1attack",	NULL, -1, -1, 7, 8, visnum, 0, 31, 0, 0,
"op1decay1",	NULL, -1, -1, 7, 12, visnum, 0, 31, 0, 0,
"op1level1",	NULL, -1, -1, 7, 16, visnum, 0, 15, 0, 0,
"op1decay2",	NULL, -1, -1, 7, 20, visnum, 0, 31, 0, 0,
"op1release",	NULL, -1, -1, 7, 24, visnum, 0, 31, 0, 0,
"op1freq",	NULL, -1, -1, 7, 29, visfreq, 0, 63, 0, 0,
"op1detune",	NULL, -1, -1, 7, 37, vism3num, 0, 6, 0, 0,
"op1outlevel",	NULL, -1, -1, 7, 41, visnum, 0, 99, 0, 0,
"op1velocity",	NULL, -1, -1, 7, 45, visnum, 0, 7, 0, 0,
"op1ampmod",	NULL, -1, -1, 7, 48, visonoff, 0, 1, 0, 0,
"op1egbias",	NULL, -1, -1, 7, 53, visnum, 0, 7, 0, 0,
"op1keyrate",	NULL, -1, -1, 7, 57, visnum, 0, 3, 0, 0,
"op1keyscale",	NULL, -1, -1, 7, 61, visnum, 0, 99, 0, 0,
"op2attack",	NULL, -1, -1, 8, 8, visnum, 0, 31, 0, 0,
"op2decay1",	NULL, -1, -1, 8, 12, visnum, 0, 31, 0, 0,
"op2level1",	NULL, -1, -1, 8, 16, visnum, 0, 15, 0, 0,
"op2decay2",	NULL, -1, -1, 8, 20, visnum, 0, 31, 0, 0,
"op2release",	NULL, -1, -1, 8, 24, visnum, 0, 31, 0, 0,
"op2freq",	NULL, -1, -1, 8, 29, visfreq, 0, 63, 0, 0,
"op2detune",	NULL, -1, -1, 8, 37, vism3num, 0, 6, 0, 0,
"op2outlevel",	NULL, -1, -1, 8, 41, visnum, 0, 99, 0, 0,
"op2velocity",	NULL, -1, -1, 8, 45, visnum, 0, 7, 0, 0,
"op2ampmod",	NULL, -1, -1, 8, 48, visonoff, 0, 1, 0, 0,
"op2egbias",	NULL, -1, -1, 8, 53, visnum, 0, 7, 0, 0,
"op2keyrate",	NULL, -1, -1, 8, 57, visnum, 0, 3, 0, 0,
"op2keyscale",	NULL, -1, -1, 8, 61, visnum, 0, 99, 0, 0,
"op3attack",	NULL, -1, -1, 9, 8, visnum, 0, 31, 0, 0,
"op3decay1",	NULL, -1, -1, 9, 12, visnum, 0, 31, 0, 0,
"op3level1",	NULL, -1, -1, 9, 16, visnum, 0, 15, 0, 0,
"op3decay2",	NULL, -1, -1, 9, 20, visnum, 0, 31, 0, 0,
"op3release",	NULL, -1, -1, 9, 24, visnum, 0, 31, 0, 0,
"op3freq",	NULL, -1, -1, 9, 29, visfreq, 0, 63, 0, 0,
"op3detune",	NULL, -1, -1, 9, 37, vism3num, 0, 6, 0, 0,
"op3outlevel",	NULL, -1, -1, 9, 41, visnum, 0, 99, 0, 0,
"op3velocity",	NULL, -1, -1, 9, 45, visnum, 0, 7, 0, 0,
"op3ampmod",	NULL, -1, -1, 9, 48, visonoff, 0, 1, 0, 0,
"op3egbias",	NULL, -1, -1, 9, 53, visnum, 0, 7, 0, 0,
"op3keyrate",	NULL, -1, -1, 9, 57, visnum, 0, 3, 0, 0,
"op3keyscale",	NULL, -1, -1, 9, 61, visnum, 0, 99, 0, 0,
"op4attack",	NULL, -1, -1, 10, 8, visnum, 0, 31, 0, 0,
"op4decay1",	NULL, -1, -1, 10, 12, visnum, 0, 31, 0, 0,
"op4level1",	NULL, -1, -1, 10, 16, visnum, 0, 15, 0, 0,
"op4decay2",	NULL, -1, -1, 10, 20, visnum, 0, 31, 0, 0,
"op4release",	NULL, -1, -1, 10, 24, visnum, 0, 31, 0, 0,
"op4freq",	NULL, -1, -1, 10, 29, visfreq, 0, 63, 0, 0,
"op4detune",	NULL, -1, -1, 10, 37, vism3num, 0, 6, 0, 0,
"op4outlevel",	NULL, -1, -1, 10, 41, visnum, 0, 99, 0, 0,
"op4velocity",	NULL, -1, -1, 10, 45, visnum, 0, 7, 0, 0,
"op4ampmod",	NULL, -1, -1, 10, 48, visonoff, 0, 1, 0, 0,
"op4egbias",	NULL, -1, -1, 10, 53, visnum, 0, 7, 0, 0,
"op4keyrate",	NULL, -1, -1, 10, 57, visnum, 0, 3, 0, 0,
"op4keyscale",	NULL, -1, -1, 10, 61, visnum, 0, 99, 0, 0,

"algorithm",	"Algorithm~l~l~l~l~l~l~l~l~l~d=============",	1, 49, 1, 61, visdx1a, 0, 7, 0, 0,

"feedback",	"Feedback",	12, 33, 12, 45, visnum, 0, 7, 0, 0,
"transpose",	"Transpose",	13, 33, 13, 45, visnum, 0, 45, 0, 0,
"lfospeed",	"LFO Speed",	14, 33, 14, 45, visnum, 0, 99, 0, 0,
"lfodelay",	"LFO Delay",	15, 33, 15, 45, visnum, 0, 99, 0, 0,
"lfowave",	"LFO Wave",	16, 33, 16, 45, viswave, 0, 3, 0, 0,
"lfosync",	"LFO Sync",	17, 33, 17, 45, visonoff, 0, 1, 0, 0,
"pitchbend",	"Pitch Bend",	18, 33, 18, 45, visnum, 0, 12, 0, 0,
"portatime",	"Port. Time",	19, 33, 19, 45, visnum, 0, 99, 0, 0,
"portmode",	"Port. Mode",	20, 33, 20, 45, visnum, 0, 1, 0, 0,
"portfoot",	"Port. Foot",	21, 33, 21, 45, visonoff, 0, 1, 0, 0,
"susfoot",	"Sus. Foot",	22, 33, 22, 45, visonoff, 0, 1, 0, 0,
"playmode",	"Mono/Poly",		12, 55, 12, 74, vismono, 0, 1, 0, 0,
"amoddepth",	"Amp Mod Depth",	13, 55, 13, 74, visnum, 0, 99, 0, 0,
"amodsens",	"Amp Mod Sense",	14, 55, 14, 74, visnum, 0, 3, 0, 0,
"pmoddepth",	"Pitch Mod Depth",	15, 55, 15, 74, visnum, 0, 99, 0, 0,
"pmodsens",	"Pitch Mod Sense",	16, 55, 16, 74, visnum, 0, 7, 0, 0,
"modprange",	"Mod Pitch Range",	17, 55, 17, 74, visnum, 0, 99, 0, 0,
"modarange",	"Mod Amp Range",	18, 55, 18, 74, visnum, 0, 99, 0, 0,
"breathprange",	"Breath Pitch",		19, 55, 19, 74, visnum, 0, 99, 0, 0,
"breatharange",	"Breath Amp",		20, 55, 20, 74, visnum, 0, 99, 0, 0,
"breathpbias",	"Breath Pitch Bias",	21, 55, 21, 74, visnum, 0, 99, 0, 0,
"breathegbias",	"Breath EG Bias",	22, 55, 22, 74, visnum, 0, 99, 0, 0,
NULL,	NULL, -1, -1, -1, -1, visnum, 0, 0, 0, 0
};
SHAR_EOF
cat << \SHAR_EOF > glib.h
/*
 * GLIB - a Generic LIBrarian and editor for synths
 */

#include <stdio.h>
#include "machdep.h"

#define EOX 0xf7
#define MOUSE -2

#ifndef BUFSIZ
#define BUFSIZ 512
#endif

/* If a machine needs to do something special to read/write a binary file, */
/* this is a hook that a machdep.h can override to do what it  needs to. */
/* For example, see the Atari ST version  of machdep.h */
#ifndef OPENBINFILE
#define OPENBINFILE(f,file,mode) f=fopen(file,mode)
#endif

/* Seconds before we give up trying to read something */
#define TIMEOUT 5

#define NUMONSCREEN 12
/* position of first voice row */
#define FIRSTROW 10
#define LEFTSIDE 2
#define RIGHTSIDE 54
#define YANKROW 12
#define YANKCOL 31
#define LIBBANKS 3
#define NOREDRAW 0
#define REDRAW 1

#define CH_REDRAW '\014'

#define CH_INC 'K'
#define CH_INC2 'I'
#define CH_INC3 '>'
#define CH_DEC 'J'
#define CH_DEC2 'M'
#define CH_DEC3 '<'

#define CH_LEFT 'h'
#define CH_DOWN 'j'
#define CH_UP 'k'
#define CH_RIGHT 'l'
#define SCR_DOWN '\04'
#define SCR_UP '\025'

#define STR_LEFT "h"
#define STR_DOWN "j"
#define STR_UP "k"
#define STR_RIGHT "l"

#define VOICEBYTE(d,v,n) (*((d)+(v)*Voicesize+(n)))

struct paraminfo {
	char *p_name;
	char *p_label;
	INT16 p_lrow;	/* position for printing name */
	INT16 p_lcol;
	INT16 p_vrow;		/* position for printing value */
	INT16 p_vcol;
	char *((*p_tovis)());
	INT16 p_min;
	INT16 p_max;
	INT16 p_val;
	INT16 p_flags;
};

struct labelinfo {
	INT16 l_row;
	INT16 l_col;
	char *l_text;
};

struct editinfo {
	char *ed_name;		/* Synth name */
	struct paraminfo *ed_params;	/* list of parameters */
	struct labelinfo *ed_labels;	/* screen labels in edit mode */
	INT16 ed_nvoices;		/* number of voices */
	INT16 ed_vsize;		/* size of each voice data, in bytes */
	INT16 ed_nsize;		/* name size */
	int (*ed_din)();	/* copy voice data into paraminfo array */
	int (*ed_dout)();	/* copy voice data out of paraminfo array */
	int (*ed_sedit)();	/* send 1 voice to synth edit buffer */
	int (*ed_sone)();	/* send 1 voice to a synth (permanent) patch*/
	int (*ed_sbulk)();	/* send bulk voice data */
	int (*ed_gbulk)();	/* get bulk voice data */
	char *(*ed_nof)();	/* get name of a voice out of data */
	int (*ed_snof)();	/* set name of a voice in data */
	char *(*ed_numof)();	/* convert voice number to on-screen text */
	int (*ed_cvtnum)();	/* convert visable voice number to std. format */
	int (*ed_cvtanum)();	/* convert alphanumeric voice number to std. format */
};

struct peredinfo {
	char *ed_libdata;	/* memory for library banks */
	char *ed_syndata;	/* memory for synth bank */
	char *ed_yankdata;	/* memory for yank buffer */
	INT16 ed_libindex;	/* voice number of topmost displayed lib voice*/
	INT16 ed_synindex;	/* ditto for synth side */
	INT16 ed_channel;		/* MIDI channel # */
	INT16 ed_erow;
	INT16 ed_ecol;
};

extern struct paraminfo *P;
extern struct labelinfo *L;
extern struct editinfo E[];
extern int Rows, Cols, Channel, Nvoices, Voicesize, Redraw;
extern char *Reason, *Synthname;

char *bankvoice();
char *malloc(), *alloc(), *nextls();
long milliclock();
SHAR_EOF
cat << \SHAR_EOF > list.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * The E array is the list of synths that can be handled.
 * GLIB is completely driven from the stuff in the editinfo structure.
 * To add/delete a synth, just add/delete an entry to the E array,
 * and provide the functions.  The #defines at the top provide a
 * convenient way of including/excluding synths that are already
 * supported.
 */

#define TX81Z
#define TX81ZPERF
#define DX100
#define DW8000
/* #define DEP5 */
#define K5

#include "glib.h"

#ifdef DX100
extern dxtxdin(), dxtxdout(), dx1snof(), dx1sbulk(), dx1gbulk(), dx1sedit();
extern char *dx1nof();
extern struct paraminfo Pdx100[];
extern struct labelinfo Ldx100[];
#endif

#ifdef TX81Z
extern dxtxdin(), dxtxdout(), dx1snof(), dx1sbulk(), dx1gbulk(), dx1sedit();
extern char *dx1nof();
extern struct paraminfo Ptx81z[];
extern struct labelinfo Ltx81z[];
#endif

#ifdef TX81ZPERF
extern tx8pdin(), tx8pdout(), tx8psedit(), tx8psbulk(), tx8pgbulk(), tx8psnof();
extern char *tx8pnof();
extern struct paraminfo Ptx81p[];
extern struct labelinfo Ltx81p[];
#endif

#ifdef DEP5
extern struct paraminfo Pdep5[];
extern struct labelinfo Ldep5[];
extern dep5din(), dep5dout(), dep5snof(), dep5sone(), dep5sedit();
extern char *dep5nof();
#endif

#ifdef DW8000
extern struct paraminfo Pdw800[];
extern struct labelinfo Ldw800[];
extern dw8din(), dw8dout(), dw8snof(), dw8sone(), dw8gbulk();
extern dw8numv(), dw8sedit();
extern char *dw8nof(), *dw8vnum();
#endif

#ifdef K5
extern struct paraminfo Pk5sin[], Pk5mul[];
extern struct labelinfo Lk5sin[], Lk5mul[];
extern k5sindin(), k5sindout(), k5sinsnof(), k5sinsone();
extern k5muldin(), k5muldout(), k5mulsnof(), k5mulsone();
extern k5sinsbulk(), k5mulsbulk();
extern k5numv(), k5sinsedit(), k5mulsedit(), k5singbulk(), k5mulgbulk();
extern char *k5sinnof(), *k5mulnof(), *k5vnum();
#endif

struct editinfo E[] = {
#ifdef DX100
   {"DX-100", Pdx100, Ldx100, 24, 128, 17,
	dxtxdin, dxtxdout, dx1sedit, NULL, dx1sbulk, dx1gbulk, dx1nof, dx1snof,
	NULL, NULL, NULL},
#endif
#ifdef DEP5
   {"DEP-5", Pdep5, Ldep5, 99, 42, 16,
	dep5din, dep5dout, dep5sedit, dep5sone, NULL, NULL, dep5nof, dep5snof,
	NULL, NULL, NULL},
#endif
#ifdef TX81Z
   {"TX81Z", Ptx81z, Ltx81z, 32, 128, 17,
	dxtxdin, dxtxdout, dx1sedit, NULL, dx1sbulk, dx1gbulk, dx1nof, dx1snof,
	NULL, NULL, NULL},
#endif
#ifdef TX81ZPERF
   {"TX81Z Performance", Ptx81p, Ltx81p, 24, 76, 17,
	tx8pdin, tx8pdout, tx8psedit, NULL, tx8psbulk, tx8pgbulk, tx8pnof,
	tx8psnof, NULL, NULL, NULL},
#endif
#ifdef DW8000
   {"DW8000", Pdw800, Ldw800, 64, 72, 17,
	dw8din, dw8dout, dw8sedit, dw8sone, NULL, dw8gbulk, dw8nof, dw8snof,
	dw8vnum, dw8numv, NULL},
#endif
#ifdef K5
   {"K-5 Single", Pk5sin, Lk5sin, 48, 984, 8,
	k5sindin, k5sindout, k5sinsedit, k5sinsone, k5sinsbulk, k5singbulk,
	k5sinnof, k5sinsnof, k5vnum, NULL, k5numv},
   {"K-5 Multi", Pk5mul, Lk5mul, 48, 352, 8,
	k5muldin, k5muldout, k5mulsedit, k5mulsone, k5mulsbulk, k5mulgbulk,
	k5mulnof, k5mulsnof, k5vnum, NULL, k5numv},
#endif
   {NULL,NULL,NULL,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
};
SHAR_EOF
cat << \SHAR_EOF > pc-mach.c
/*
 * Glib - Generic LIBrarian and editor
 *
 * Machine dependent stuff for MIDI programs.
 *
 * This is for MS-DOS machines.  The screen operations should
 * work okay, but the MIDI I/O needs to be worked on.  It may
 * or may not be fast enough on some machines. 
 */

#include "dos.h"
#include "glib.h"

#define C86
#ifdef C86
#define inp inportb
#define outp outportb
#endif

int Rows = 24;
int Cols = 80;

flushmidi()
{
	while ( statmidi() )
		getmidi();
}

/* getmouse - get currect row and column of mouse */
getmouse(amr,amc)
int *amr;
int *amc;
{
	*amr = -1;
	*amc = -1;
}

/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */
statmouse()
{
	return(-1);
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
	return(getconsole());
}

flushconsole()
{
}

statconsole()
{
	struct regval sreg, rreg;
	sreg.ax = 0x0100;
	sysint(0x16, &sreg, &rreg);
	if ( rreg.ax != 0 )
		return(1);
	else
		return(0);
}

getconsole()
{
	struct regval sreg, rreg;
	sreg.ax = 0x0000;
	sysint(0x16, &sreg, &rreg);
	return(rreg.ax & 0x7f);
}

long milliclock()
{
	static int hour1 = -1, min1, sec1, hund1;
	struct regval sreg, rreg;
	int hours, mins, secs, hunds;
	long mills;

	sreg.ax = 0x2c00;
	sysint(0x21, &sreg, &rreg);
	hours = (rreg.cx >> 8) & 0x7f;
	mins = rreg.cx & 0x7f;
	secs = (rreg.dx >> 8) & 0x7f;
	hunds = rreg.dx & 0x7f ;
	if ( hour1 < 0 ) {
		mills = 0L;
		hour1 = hours;
		min1 = mins;
		sec1 = secs;
		hund1 = hunds;
	}
	else {
		mills = 10L*(hunds-hund1)+1000L*(secs-sec1)
			+60000L*(mins-min1)+360000L*(hours-hour1);
	}
	return( mills );
}

char *
alloc(n)
{
	char *p;

	if ( (p=malloc((unsigned)n)) == (char *)NULL ) {
		printf("*** Whoops *** alloc has failed?!?  No more memory!\n");
		fflush(stdout);
		bye();
	}
	return(p);
}

windinit()
{
}

windgoto(r,c)
int r,c;
{
	struct regval sreg, rreg;
	sreg.ax = 0x200;
	sreg.bx = 0;
	sreg.dx = (r<<8) | c ;
	sysint(0x10, &sreg, &rreg);
}

winderaserow(r)
{
	struct regval sreg, rreg;
	sreg.ax = 0x0600;
	sreg.bx = 0;
	sreg.cx = (r<<8);	/* urow, lcol */
	sreg.dx = (r<<8) | 79;
	sysint(0x10, &sreg, &rreg);
}

windexit(r)
int r;
{
	/* windgoto(23,0);
	windrefresh();
	nocbreak();
	nl();
	echo();
	endwin(); */
}

windclear()
{
	struct regval sreg, rreg;
	sreg.ax = 0x0600;
	sreg.bx = 0;
	sreg.cx = 0;	/* urow, lcol */
	sreg.dx = (24<<8) | 79;
	sysint(0x10, &sreg, &rreg);
}

/* windgets - get a line of input from the console, handling backspaces */
windgets(s)
char *s;
{
	char *origs = s;
	int c;

	while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				windstr("\b \b");
				s--;
			}
		}
		else {
			windputc(c);
			*s++ = c;
		}
		windrefresh();
	}
	*s = '\0';
}

windstr(s)
char *s;
{
	int c;

	while ( (c=(*s++)) != '\0' )
		windputc(c);
}

windputc(c)
int c;
{
	putchar(c);
}

windrefresh()
{
}

beep()
{
	putchar('\007');
}

windhigh()
{
}

windnorm()
{
}

/****************
 * openls(), nextls(), and closels() are used to scan the current directory.
 ***************/

openls()
{
}
char *
nextls()
{
	return(NULL);
}
closels()
{
}

/*
 * The following MPU code has been provided by Steve Frysinger (moss!spf).
 */

#define	STATUS_PORT	0x0331
#define	COMMAND_PORT	0x0331
#define	DATA_PORT	0x0330
#define	DATA_READY_MASK	0x40
#define	DATA_AVAIL_MASK	0x80

int send_command_4001(val)	/* Patterned after Voyetra's reset_4001() */
unsigned val;
{
	unsigned x = 0;
	int flag;
	int ack_count,time_count;
	int retval=1; /* Assume success */
	inp(DATA_PORT);
	for (time_count=5000,flag=1;time_count&&flag;time_count--)
	{
		if (!(inp(STATUS_PORT)&DATA_READY_MASK)) flag=0;
	}
	if (flag)
	{
		fprintf(stderr,"Command timeout waiting for port!\n");
		retval = -1;
	}
	else
	{
		outp(COMMAND_PORT,val);
		for (time_count=10000,ack_count=5,flag=0;!flag;)
		{
			if ((inp(STATUS_PORT)&DATA_AVAIL_MASK))
			{
				time_count--;
				if (!time_count)
				{
					flag++;
					fprintf(stderr,"Command timeout waiting for ACK.\n");
					retval = -1;
				}
			}
			else
			{
				x = (unsigned)inp(DATA_PORT);
				if (x == 0xfe)
				{
					flag++;
					fprintf(stderr,"Got command acknowledgement\n");
				}
				else
				{
					ack_count--;
					if (!ack_count)
					{
						printf("Too many data bytes without ACK\n");
						retval = -1;
					}
				}
			}
		}
	}
	return(retval);
} /* send_command_4001 */

getmidi()
{
	while (inp(STATUS_PORT) & DATA_AVAIL_MASK)
		; /* Wait for data available */
	return(inp(DATA_PORT));
}

statmidi()
{
	if ( inp(STATUS_PORT) & DATA_AVAIL_MASK) /* data available ? */
		return(0);
	else
		return(1);
}

sendmidi(val)
int val;
{
	int timeout = 10000;

	unsigned status;
	status=inp(STATUS_PORT);
	while (status & DATA_READY_MASK)
		printf("Busy; read %d ",getmidi());
	/*
	This printf lets me know what's holding up the transfer; I usually get
	254 back, unless I press a synth key, when I get the key press parameters.
	*/
	outp(DATA_PORT,val);
}

hello()
{
	send_command_4001(0xff);	/* reset */
	send_command_4001(0x96);	/* kill RT? */
	send_command_4001(0x94);	/* ?? */
	send_command_4001(0x90);	/* ?? */
	send_command_4001(0x3f);	/* go into uart mode */
}

bye()
{
	send_command_4001(0xff);	/* reset */
	windexit(0);
}

SHAR_EOF
cat << \SHAR_EOF > pc-mach.h
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * MS-DOS version
 */

#define INT16 int

#define STATMIDI (statmidi())
SHAR_EOF
cat << \SHAR_EOF > st-mach.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 */

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

int Rows, Cols;

#define EscSeq(x) Cconout('\033');Cconout(x);
struct iorecinfo {
	char *ibuf;
	int ibufsiz;
	int ibufhd;
	int ibuftl;
	int ibuflow;
	int ibufhigh;
};
#define MIDIBUFSIZE 5000
char *Origbuf;
int Origsize;
struct iorecinfo *Ioptr;
int work_in[12], work_out[60];  /* GEM & VDI stuff */
int intin[128], ptsin[128];
int intout[128], ptsout[128];
int contrl[12];
int Handle, Vhandle;

/* These contain the raw voice data */
hello()
{
	int dummy, n;

	appl_init();

	/* Get the Midi Iorec and put in a bigger buffer */
	flushmidi();
	Ioptr = (struct iorecinfo *)(Iorec(2));
	Origbuf = Ioptr->ibuf;
	Origsize = Ioptr->ibufsiz;
	Ioptr->ibuf = alloc(MIDIBUFSIZ);
	Ioptr->ibufsiz = MIDIBUFSIZ;
	Ioptr->ibuftl = Ioptr->ibufhd = 0;
	Cursconf(2,0);		/* set non-blinking block cursor */
	mouseon();
}

bye()
{
	/* Restore the original Midi Iorec buffer */
	flushmidi();
	Ioptr->ibuf = Origbuf;
	Ioptr->ibufsiz = Origsize;
	Ioptr->ibuftl = Ioptr->ibufhd = 0;
	mouseoff();
	appl_exit();

	/* are these ever called? SAF */
	windgoto(23,0);
	windrefresh();
	windexit(0);
}

/* getmouse - get currect row and column of mouse */
getmouse(amr,amc)
int *amr;
int *amc;
{
#ifdef USEMOUSE
	int button, ret, keycode, tmp1, tmp2;
	char msgbuf[8];

	graf_mkstate(amc,amr,&tmp1,&tmp2);
	/* evnt_multi(MU_TIMER,
		0,0,0,
		0,0,0,0,0,
		0,0,0,0,0,
		msgbuf, 0, 0,
		amc, amr, &button, &ret, &keycode, &ret); */
	/* convert bitmap x,y coordinates to row,colum */
	*amr = (*amr)/16;
	*amc = (*amc)/8;
#else
	*amr = -1;
	*amc = -1;
#endif
}

/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */
statmouse()
{
#ifdef USEMOUSE
	int tmp1, tmp2, tmp3, buttons;
	char msgbuf[8];

	graf_mkstate(&tmp1,&tmp2,&buttons,&tmp3);
	/* evnt_multi(MU_TIMER,
		0,0,0,
		0,0,0,0,0,
		0,0,0,0,0,
		msgbuf, 0, 0,
		&tmp1, &tmp1, &buttons, &tmp1, &tmp1, &tmp1); */
	return(buttons);
#else
	return(-1);
#endif
}

int Mouseshown = 0;
mouseon()
{
#ifdef USEMOUSE
	if ( Mouseshown == 0 ) {
		Vsync();	/* wait until next VBI to ensure updating */
		Cursconf(1,0);		/* show block cursor */
		Vsync();	/* wait until next VBI to ensure updating */
		graf_mouse(257,NULL);	/* display mouse cursor */
		Mouseshown = 1;
		Vsync();
	}
#endif
}
mouseoff()
{
#ifdef USEMOUSE
	if ( Mouseshown == 1 ) {
		Vsync();	/* wait until next VBI to ensure updating */
		graf_mouse(256,NULL);	/* hide mouse cursor */
		Vsync();	/* wait until next VBI to ensure updating */
		Cursconf(0,0);		/* hide block cursor */
		Mouseshown = 0;
		Vsync();
	}
#endif
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
#ifdef USEMOUSE
	int evnt, ret, keycode, button, mx, my, tmp1, tmp2, tmp3;
	char msgbuf[8];

	mouseon();
	for ( ;; ) {
		graf_mkstate(&tmp1,&tmp2,&button,&tmp3);
		/* evnt = evnt_multi(MU_TIMER,
			0,0,0,
			0,0,0,0,0,
			0,0,0,0,0,
			msgbuf, 0, 0,
			&mx, &my, &button, &ret, &keycode, &ret); */
		if ( button != 0 ) {
			return(MOUSE);
		}
		if ( statmouse() > 0 )
			return(MOUSE);
		if ( statconsole() )
			return(getconsole());
	}
#else
	return(getconsole());
#endif
}

flushconsole()
{
	while ( statconsole() )
		getconsole();
}

statconsole()
{
	/* return(Bconstat(CONSOLE)); */
	return(Cconis());
}

getconsole()
{
	/* return(Bconin(CONSOLE)); */
	return(Crawcin());
}

getmidi()
{
	return(Bconin(MIDI));
}

/*ARGSUSED*/
sendmidi(c)
{
	Bconout(MIDI,c);
}

flushmidi()
{
	while ( STATMIDI )
		getmidi();
}

long milliclock()
{
	register long save_ssp=Super(0L);
	register long uhz200= *(long *)0x4ba;
	Super(save_ssp);
	return(uhz200 * 5);
}

millisleep(n)
{
	long first = milliclock();
	while ( milliclock() < (first+n) )
		;
}

char *
alloc(n)
{
	char *p;

	if ( (p=malloc((unsigned)n)) == (char *)NULL ) {
		printf("*** Whoops *** alloc has failed?!?  No more memory!\n");
		fflush(stdout);
		bye();
	}
	return(p);
}

windinit()
{
	Cols=80;
	Rows=25;
	Cursconf(1,NULL);
}

windgoto(r,c)
int r,c;
{
	mouseoff();
	EscSeq('Y');
	Cconout(r+040);
	Cconout(c+040);
}

windeeol()
{
	mouseoff();
	EscSeq('K');
}

winderaserow(r)
{
	windgoto(r,0);
	windeeol();
}

windexit(r)
int r;
{
	exit(r);
}

windclear()
{
	mouseoff();
	EscSeq('H');
	EscSeq('J');
}

/* windgets - get a line of input from the console, handling backspaces */
windgets(s)
char *s;
{
	char *origs = s;
	int c;

	while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				windstr("\b \b");
				s--;
			}
		}
		else {
			windputc(c);
			*s++ = c;
		}
		windrefresh();
	}
	*s = '\0';
}

windstr(s)
char *s;
{
	int c;

	while ( (c=(*s++)) != '\0' )
		windputc(c);
}

windputc(c)
int c;
{
	mouseoff();
	Cconout(c);
}

windrefresh()
{
}

beep()
{
	Cconout('\007');
}

windhigh()
{
}

windnorm()
{
}

/****************
 * openls(), nextls(), and closels() are used to scan the current directory.
 ***************/

char Dtabuff[44];
long Origdta;
int Atarifirst = 0;

char *
openls()
{
	int n, c;

	Origdta = Fgetdta();
	Fsetdta(Dtabuff);
	Atarifirst = 1;
}
char *
nextls()
{
	static char fname[17];
	int n, c;

	if ( Atarifirst ) {
		if ( Fsfirst("*.*",0x10) < 0 )
			return(NULL);
	}
	else {
		if ( Fsnext() < 0 )
			return(NULL);
	}
	Atarifirst = 0;
	for ( n=0; n<14; n++ ) {
		c = fname[n] = Dtabuff[30+n];
		/* ALL phrase names are lower case */
		if ( c >= 'A' && c <= 'Z' )
			fname[n] = c - 'A' + 'a';
	}
	fname[14] = '\0';
	return(fname);
}
closels()
{
	Fsetdta((char *)Origdta);
}

SHAR_EOF
cat << \SHAR_EOF > st-mach.h
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Atari ST version
 */

#define INT16 int

#include <osbind.h>
#include <gemdefs.h>
#include <obdefs.h>

#define CONSOLE 2
#define MIDI 3

#ifdef OVERLAY1
overlay "over1"
#endif

#ifdef OVERLAY2
overlay "over2"
#endif

#define OPENBINFILE(f,name,mode) f=fopen(name,mode[0]=='r'?"br":"bw")

#define STATMIDI (Bconstat(MIDI))
SHAR_EOF
cat << \SHAR_EOF > tx81z.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * TX81Z routines for Patch parameters
 */

#define OVERLAY1

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

char *visnum(), *visonoff(), *vism3num(), *viswave(), *vismono();
char *visdx1a(), *vistxwave(), *vistxsft();
char *vistxf1(), *vistxf2(), *vistxf3(), *vistxf4();
char *visfx(), *visfix1(), *visfix2(), *visfix3(), *visfix4();
extern int Dopmap[];

/* This array contains arbitrary screen labels */
struct labelinfo Ltx81z[] = {
5,0," O       Dcy Lev Dcy               De  Out     Amp Eg  Key Key EG",
6,0," P   Atk  1   1   2  Rls Wav  Freq tun Lvl Vel Mod Bia Rat Scl Sft Fix/Ratio",
7,0," -   --- --- --- --- --- --- ----- --- --- --- --- --- --- --- --- ---------",
8,0," 1",
9,0," 2",
10,0," 3",
11,0," 4",
17,0,"-------------------------+",
18,0,"N = set name  q = quit   |",
19,0,"K = incr      J = decr   |",
20,0,"space = play auto-note   |",
21,0,"                         |",
22,0,"Auto-Note:               |",
23,0,"                         |",
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Ptx81z[] = {
"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,

"op1attack",	NULL, -1, -1, 8, 6, visnum, 0, 31, 0, 0,
"op1decay1",	NULL, -1, -1, 8, 10, visnum, 0, 31, 0, 0,
"op1level1",	NULL, -1, -1, 8, 14, visnum, 0, 15, 0, 0,
"op1decay2",	NULL, -1, -1, 8, 18, visnum, 0, 31, 0, 0,
"op1release",	NULL, -1, -1, 8, 22, visnum, 0, 31, 0, 0,
"op1wave",	NULL, -1, -1, 8, 26, vistxwave, 0, 7, 0, 0,
"op1freq",	NULL, -1, -1, 8, 30, vistxf1, 0, 878, 0, 0,
"op1detune",	NULL, -1, -1, 8, 36, vism3num, 0, 6, 0, 0,
"op1outlevel",	NULL, -1, -1, 8, 40, visnum, 0, 99, 0, 0,
"op1velocity",	NULL, -1, -1, 8, 44, visnum, 0, 7, 0, 0,
"op1ampmod",	NULL, -1, -1, 8, 47, visonoff, 0, 1, 0, 0,
"op1egbias",	NULL, -1, -1, 8, 52, visnum, 0, 7, 0, 0,
"op1keyrate",	NULL, -1, -1, 8, 56, visnum, 0, 3, 0, 0,
"op1keyscale",	NULL, -1, -1, 8, 60, visnum, 0, 99, 0, 0,
"op1egsft",	NULL, -1, -1, 8, 63, vistxsft, 0, 3, 0, 0,
"op1fix",	NULL, -1, -1, 8, 69, visfix1, 0, 1, 0, 0,
"op2attack",	NULL, -1, -1, 9, 6, visnum, 0, 31, 0, 0,
"op2decay1",	NULL, -1, -1, 9, 10, visnum, 0, 31, 0, 0,
"op2level1",	NULL, -1, -1, 9, 14, visnum, 0, 15, 0, 0,
"op2decay2",	NULL, -1, -1, 9, 18, visnum, 0, 31, 0, 0,
"op2release",	NULL, -1, -1, 9, 22, visnum, 0, 31, 0, 0,
"op2wave",	NULL, -1, -1, 9, 26, vistxwave, 0, 7, 0, 0,
"op2freq",	NULL, -1, -1, 9, 30, vistxf2, 0, 878, 0, 0,
"op2detune",	NULL, -1, -1, 9, 36, vism3num, 0, 6, 0, 0,
"op2outlevel",	NULL, -1, -1, 9, 40, visnum, 0, 99, 0, 0,
"op2velocity",	NULL, -1, -1, 9, 44, visnum, 0, 7, 0, 0,
"op2ampmod",	NULL, -1, -1, 9, 47, visonoff, 0, 1, 0, 0,
"op2egbias",	NULL, -1, -1, 9, 52, visnum, 0, 7, 0, 0,
"op2keyrate",	NULL, -1, -1, 9, 56, visnum, 0, 3, 0, 0,
"op2keyscale",	NULL, -1, -1, 9, 60, visnum, 0, 99, 0, 0,
"op2egsft",	NULL, -1, -1, 9, 63, vistxsft, 0, 3, 0, 0,
"op2fix",	NULL, -1, -1, 9, 69, visfix2, 0, 1, 0, 0,
"op3attack",	NULL, -1, -1, 10, 6, visnum, 0, 31, 0, 0,
"op3decay1",	NULL, -1, -1, 10, 10, visnum, 0, 31, 0, 0,
"op3level1",	NULL, -1, -1, 10, 14, visnum, 0, 15, 0, 0,
"op3decay2",	NULL, -1, -1, 10, 18, visnum, 0, 31, 0, 0,
"op3release",	NULL, -1, -1, 10, 22, visnum, 0, 31, 0, 0,
"op3wave",	NULL, -1, -1, 10, 26, vistxwave, 0, 7, 0, 0,
"op3freq",	NULL, -1, -1, 10, 30, vistxf3, 0, 878, 0, 0,
"op3detune",	NULL, -1, -1, 10, 36, vism3num, 0, 6, 0, 0,
"op3outlevel",	NULL, -1, -1, 10, 40, visnum, 0, 99, 0, 0,
"op3velocity",	NULL, -1, -1, 10, 44, visnum, 0, 7, 0, 0,
"op3ampmod",	NULL, -1, -1, 10, 47, visonoff, 0, 1, 0, 0,
"op3egbias",	NULL, -1, -1, 10, 52, visnum, 0, 7, 0, 0,
"op3keyrate",	NULL, -1, -1, 10, 56, visnum, 0, 3, 0, 0,
"op3keyscale",	NULL, -1, -1, 10, 60, visnum, 0, 99, 0, 0,
"op3egsft",	NULL, -1, -1, 10, 63, vistxsft, 0, 3, 0, 0,
"op3fix",	NULL, -1, -1, 10, 69, visfix3, 0, 1, 0, 0,
"op4attack",	NULL, -1, -1, 11, 6, visnum, 0, 31, 0, 0,
"op4decay1",	NULL, -1, -1, 11, 10, visnum, 0, 31, 0, 0,
"op4level1",	NULL, -1, -1, 11, 14, visnum, 0, 15, 0, 0,
"op4decay2",	NULL, -1, -1, 11, 18, visnum, 0, 31, 0, 0,
"op4release",	NULL, -1, -1, 11, 22, visnum, 0, 31, 0, 0,
"op4wave",	NULL, -1, -1, 11, 26, vistxwave, 0, 7, 0, 0,
"op4freq",	NULL, -1, -1, 11, 30, vistxf4, 0, 878, 0, 0,
"op4detune",	NULL, -1, -1, 11, 36, vism3num, 0, 6, 0, 0,
"op4outlevel",	NULL, -1, -1, 11, 40, visnum, 0, 99, 0, 0,
"op4velocity",	NULL, -1, -1, 11, 44, visnum, 0, 7, 0, 0,
"op4ampmod",	NULL, -1, -1, 11, 47, visonoff, 0, 1, 0, 0,
"op4egbias",	NULL, -1, -1, 11, 52, visnum, 0, 7, 0, 0,
"op4keyrate",	NULL, -1, -1, 11, 56, visnum, 0, 3, 0, 0,
"op4keyscale",	NULL, -1, -1, 11, 60, visnum, 0, 99, 0, 0,
"op4egsft",	NULL, -1, -1, 11, 63, vistxsft, 0, 3, 0, 0,
"op4fix",	NULL, -1, -1, 11, 69, visfix4, 0, 1, 0, 0,

"algorithm",	"Algorithm~l~l~l~l~l~l~l~l~l~d=============",	1, 49, 1, 61, visdx1a, 0, 7, 0, 0,

"feedback",	"Feedback",	13, 33, 13, 45, visnum, 0, 7, 0, 0,
"transpose",	"Transpose",	14, 33, 14, 45, visnum, 0, 45, 0, 0,
"lfospeed",	"LFO Speed",	15, 33, 15, 45, visnum, 0, 99, 0, 0,
"lfodelay",	"LFO Delay",	16, 33, 16, 45, visnum, 0, 99, 0, 0,
"lfowave",	"LFO Wave",	17, 33, 17, 45, viswave, 0, 3, 0, 0,
"lfosync",	"LFO Sync",	18, 33, 18, 45, visonoff, 0, 1, 0, 0,
"pitchbend",	"Pitch Bend",	19, 33, 19, 45, visnum, 0, 12, 0, 0,
"portatime",	"Port. Time",	20, 33, 20, 45, visnum, 0, 99, 0, 0,
"portmode",	"Port. Mode",	21, 33, 21, 45, visnum, 0, 1, 0, 0,
"portfoot",	"Port. Foot",	22, 33, 22, 45, visonoff, 0, 1, 0, 0,
"susfoot",	"Sus. Foot",	23, 33, 23, 45, visonoff, 0, 1, 0, 0,
"playmode",	"Mono/Poly",		13, 55, 13, 74, vismono, 0, 1, 0, 0,
"amoddepth",	"Amp Mod Depth",	14, 55, 14, 74, visnum, 0, 99, 0, 0,
"amodsens",	"Amp Mod Sense",	15, 55, 15, 74, visnum, 0, 3, 0, 0,
"pmoddepth",	"Pitch Mod Depth",	16, 55, 16, 74, visnum, 0, 99, 0, 0,
"pmodsens",	"Pitch Mod Sense",	17, 55, 17, 74, visnum, 0, 7, 0, 0,
"modprange",	"Mod Pitch Range",	18, 55, 18, 74, visnum, 0, 99, 0, 0,
"modarange",	"Mod Amp Range",	19, 55, 19, 74, visnum, 0, 99, 0, 0,
"breathprange",	"Breath Pitch",		20, 55, 20, 74, visnum, 0, 99, 0, 0,
"breatharange",	"Breath Amp",		21, 55, 21, 74, visnum, 0, 99, 0, 0,
"breathpbias",	"Breath Pitch Bias",	22, 55, 22, 74, visnum, 0, 99, 0, 0,
"breathegbias",	"Breath EG Bias",	23, 55, 23, 74, visnum, 0, 99, 0, 0,

"reverbrate",	"Reverb Rate",		13, 11, 13, 24, visnum, 0, 7, 0, 0,
"fcpitch",	"FC Pitch",		14, 11, 14, 24, visnum, 0, 99, 0, 0,
"fcamp",	"FC Amp",		15, 11, 15, 24, visnum, 0, 99, 0, 0,
NULL,	NULL, -1, -1, -1, -1, visnum, 0, 0, 0, 0
};

extern int *txindex;
extern int txleng;

char *
vistxwave(v)
{
	static char txbuff[3] = "W ";
	txbuff[1] = v + '1';
	return(txbuff);
}

char *visfix1(v) { return(visfx(1,v)); }
char *visfix2(v) { return(visfx(2,v)); }
char *visfix3(v) { return(visfx(3,v)); }
char *visfix4(v) { return(visfx(4,v)); }

char *visfx(n,v)
{
	static int lastfx[] = { 0, -1, -1, -1, -1 };
	char buff2[8];
	int fqindex;

	if ( lastfx[n] != -1 && lastfx[n] == v )
		goto nochange;

	lastfx[n] = v;
	sprintf(buff2,"op%dfreq",n);
	fqindex = parmindex(buff2);
	if ( v == 0 )
		P[fqindex].p_max = txleng-1;
	else
		P[fqindex].p_max = 247;
	if ( P[fqindex].p_val > P[fqindex].p_max )
		P[fqindex].p_val = P[fqindex].p_max;
	showparam(fqindex,0);
nochange:
	if ( v == 0 )
		return("ratio");
	else
		return("fixed");
}

char *
vistxsft(v)
{
	switch(v){
	case 0: return("off");
	case 1: return("48");
	case 2: return("24");
	case 3: return("12");
	}
	return("??");
}

extern int txfreq[];

char *
vistxq(v)
{
	static char fbuff[8];
	int f, n1, n2;

	txinit();
	f = txfreq[txindex[v]];
	n1 = f/100;
	n2 = f%100;
	sprintf(fbuff,n2<10?"%d.0%d":"%d.%d",n1,n2);
	return(fbuff);
}

char *
visfq(v)
{
	static char fixbuff[8];

	sprintf(fixbuff,"%-5d",v+8);
	return(fixbuff);
}

char *
visnfix(n,v)
{
	char buff[8];
	int fx;

	sprintf(buff,"op%dfix",n);
	fx = getval(buff);
	if ( fx == 0 )
		return(vistxq(v));
	else
		return(visfq(v));
}

char *vistxf1(v) { return(visnfix(1,v)); }
char *vistxf2(v) { return(visnfix(2,v)); }
char *vistxf3(v) { return(visnfix(3,v)); }
char *vistxf4(v) { return(visnfix(4,v)); }
SHAR_EOF
cat << \SHAR_EOF > unix-mach.c
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Unix version
 */

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

int Rows, Cols;

#include <curses.h>

hello()
{
}

bye()
{
	windgoto(22,0);
	windrefresh();
	windexit(0);
}

/* getmouse - get currect row and column of mouse */
getmouse(amr,amc)
int *amr;
int *amc;
{
#ifdef USEMOUSE
	/* no such */
#else
	*amr = -1;
	*amc = -1;
#endif
}

/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */
statmouse()
{
#ifdef USEMOUSE
	/* no such */
#else
	return(-1);
#endif
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
#ifdef USEMOUSE
	/* no such */
#else
	return(getconsole());
#endif
}

flushconsole()
{
}

statconsole()
{
	return(1);
}

getconsole()
{
	return(getchar());
}

getmidi()
{
	return(-1);
}

statmidi()
{
	return(0);
}

/*ARGSUSED*/
sendmidi(c)
{
}

flushmidi()
{
	while ( STATMIDI )
		getmidi();
}

long milliclock()
{
	static long hzcount = 0;

	return(hzcount++);
}

millisleep(n)
{
	sleep((n+500)/1000);
}

char *
alloc(n)
{
	char *p;

	if ( (p=malloc((unsigned)n)) == (char *)NULL ) {
		printf("*** Whoops *** alloc has failed?!?  No more memory!\n");
		fflush(stdout);
		bye();
	}
	return(p);
}

windinit()
{
	char *getenv();

	initscr();
	Cols = 80;
	Rows = 24;
	noecho();
	nonl();
	cbreak();
}

windgoto(r,c)
int r,c;
{
	move(r,c);
}

windeeol()
{
	clrtoeol();
}

winderaserow(r)
{
	windgoto(r,0);
	windeeol();
}

windexit(r)
int r;
{
	nocbreak();
	nl();
	echo();
	endwin();
	exit(r);
}

windclear()
{
	clear();
}

/* windgets - get a line of input from the console, handling backspaces */
windgets(s)
char *s;
{
	char *origs = s;
	int c;

	while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				windstr("\b \b");
				s--;
			}
		}
		else {
			windputc(c);
			*s++ = c;
		}
		windrefresh();
	}
	*s = '\0';
}

windstr(s)
char *s;
{
	int c;

	while ( (c=(*s++)) != '\0' )
		windputc(c);
}

windputc(c)
int c;
{
	addch(c);
}

windrefresh()
{
	refresh();
}

beep()
{
	putchar('\007');
}

windhigh()
{
	standout();
}

windnorm()
{
	standend();
}

/****************
 * openls(), nextls(), and closels() are used to scan the current directory.
 ***************/

FILE *Phrlist = NULL;

openls()
{
	FILE *popen();
	
	Phrlist = popen("ls","r");
}
char *
nextls()
{
	static char fname[65];

	if ( fscanf(Phrlist,"%s",fname) != 1 )
		return(NULL);
	return(fname);
}
closels()
{
	pclose(Phrlist);
}

#ifdef FAKECBREAK
#include <sys/termio.h>
struct termio Initterm;
static int First = 1;
cbreak()
{
	struct termio termbuff;

	if ( First  ) {
		First = 0;
		ioctl(0,TCGETA,&Initterm);
	}
	termbuff = Initterm;
	termbuff.c_lflag &= (~ICANON);
	termbuff.c_cc[4] = 1;
	termbuff.c_cc[5] = 1;
	ioctl(0,TCSETA,&termbuff);
}
nocbreak()
{
	ioctl(0,TCSETA,&Initterm);
}
#endif
SHAR_EOF
cat << \SHAR_EOF > unix-mach.h
/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Unix version
 */

#define INT16 int

#define STATMIDI (statmidi())
SHAR_EOF
cat << \SHAR_EOF > unix-make
CFLAGS = -O

OBJ = machdep.o glib.o list.o dx100.o tx81z.o tx81p.o dw8000.o yama_com.o

#LIBS = -lcurses -ltermcap
LIBS = -lcurses

glib : $(OBJ)
	cc $(OBJ) $(LIBS) -o glib

# On the UNIX PC (at least mine), cbreak() and nocbreak() aren't in
# libcurses.a so this hack (-DFAKECBREAK) is one way out.
machdep.o : machdep.c
	# On the UNIX PC, add a -DFAKECBREAK to the following line
	cc $(CFLAGS) -c machdep.c

lint :
	lint glib.c list.c machdep.c dx100.c dw8000.c tx81z.c tx81p.c \
	yama_com.c

st-arc :
	arc a glib.arc glib.c list.c dx100.c tx81z.c tx81p.c glib.h \
	yama_com.c dw8000.c  st-mach.c st-mach.h
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.