#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	midimon
# This archive created: Thu Aug 20 23:43:34 1987
export PATH; PATH=/bin:$PATH
if test ! -d 'midimon'
then
	echo shar: creating directory "'midimon'"
	mkdir 'midimon'
fi
echo shar: entering directory "'midimon'"
cd 'midimon'
echo shar: extracting "'machdep.c'" '(2663 characters)'
if test -f 'machdep.c'
then
	echo shar: will not over-write existing file "'machdep.c'"
else
cat << \SHAR_EOF > 'machdep.c'
/*
 * Midi Data Monitor
 *
 * Copyright (c) 1987 by Tim Thompson, All Rights Reserved.
 * Permission granted for copying and distribution for non-commercial use.
 *
 * Machine dependent stuff for MIDI programs.
 */

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

#ifdef DATALIGHT
#include <dos.h>
#define MIDI_CSR 0x331	/* MPU-401 control register address */
#define MIDI_DBR 0x330	/* MPU-401 data register address */
#define MPU_RESET 0xFF	/* MPU-401 reset command */
#define MPU_UART  0x3F	/* MPU-401 UART mode command */
#define XMT_BUSY  0x40
#define RCV_EMTY  0x80
#define GET_KBD_STAT  0xB00  /* DOS command for keyboard status */
#endif

#ifdef ATARI
struct iorecinfo {
	char *ibuf;
	int ibufsiz;
	int ibufhd;
	int ibuftl;
	int ibuflow;
	int ibufhigh;
};
#define MIDIBUFSIZE 32767
char *Origbuf;
int Origsize;
struct iorecinfo *Ioptr;
#endif

hello()
{
#ifdef ATARI
	/* 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((unsigned)MIDIBUFSIZ);
	Ioptr->ibufsiz = MIDIBUFSIZ;
	Ioptr->ibuftl = Ioptr->ibufhd = 0;
#endif
#ifdef DATALIGHT
	outp(MIDI_CSR, MPU_RESET);
	while (inp(MIDI_CSR) & XMT_BUSY) ;  /* Wait for MPU to swallow reset */
	outp(MIDI_CSR, MPU_UART);
#endif
}

bye()
{
#ifdef ATARI
	/* Restore the original Midi Iorec buffer */
	flushmidi();
	Ioptr->ibuf = Origbuf;
	Ioptr->ibufsiz = Origsize;
	Ioptr->ibuftl = Ioptr->ibufhd = 0;
#endif
#ifdef DATALIGHT
	outp(MIDI_CSR, MPU_RESET);
#endif
	exit(0);
}

flushconsole()
{
#ifdef ATARI
	while ( statconsole() )
		getconsole();
#endif
}

statconsole()
{
#ifdef ATARI
	return(Bconstat(CONSOLE));
#endif
#ifdef DATALIGHT
	REGS inreg, outreg;
	inreg.ax = GET_KBD_STAT;
	intdos(&inreg, &outreg);
	return(outreg.ax & 01);
#endif
#ifdef UNIX
	/* lazy and wrong */
	return(1);
#endif
}

getconsole()
{
#ifdef ATARI
	return(Bconin(CONSOLE));
#endif
#ifdef DATALIGHT
	return(getche());
#endif
#ifdef UNIX
	return(getchar());
#endif
}

statmidi()
{
#ifdef ATARI
	return(Bconstat(MIDI));
#endif
#ifdef DATALIGHT
	return(!(inp(MIDI_CSR) & RCV_EMTY));
#endif
#ifdef UNIX
	return(0);
#endif
}

getmidi()
{
#ifdef ATARI
	return(Bconin(MIDI));
#endif
#ifdef DATALIGHT
	return(inp(MIDI_DBR));
#endif
#ifdef UNIX
	return(-1);
#endif
}

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

/*ARGSUSED*/
sendmidi(c)
{
#ifdef ATARI
	Bconout(MIDI,c);
#endif
#ifdef DATALIGHT
	outp(MIDI_DBR, c);
#endif
}

long hz200()
{
#ifdef ATARI
	register long save_ssp=Super(0L);
	register long uhz200= *(long *)0x4ba;
	Super(save_ssp);
	return uhz200;
#else
	{static long hzcount = 0;
	return(hzcount++);
	}
#endif
}
SHAR_EOF
if test 2663 -ne "`wc -c < 'machdep.c'`"
then
	echo shar: error transmitting "'machdep.c'" '(should have been 2663 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(528 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
This directory contains the source for a program called 'midimon'.
It is a simple MIDI data monitor, originaly developed on and for
the Atari ST.  Most interesting, and generally useful, is the contents
of midi.c, which is a MIDI parser.  I have made use of it in all my
MIDI programs, and it has performed well.  By changing the contents
of a single structure, you can completely alter the processing that is
done on MIDI messages.  See the comments in midi.c for more information.

    ...Tim Thompson...twitch!glimmer!tjt...
SHAR_EOF
if test 528 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 528 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'II+machdep.c'" '(1301 characters)'
if test -f 'II+machdep.c'
then
	echo shar: will not over-write existing file "'II+machdep.c'"
else
cat << \SHAR_EOF > 'II+machdep.c'
/*
 * machdep.c		Peter Giacomini		last modified:	3/2/87
 *
 * Machine dependent stuff for MIDI programs for apple II+
 * with RAMCARD in slot 0, Passport MIDI interface in slot
 * 2, and VIDEX card in slot 3.
 */

#include "stdio.h"

#define KDATA   0xC000		/* keyboard data register */

/*
* void hello();
*/

hello()
{
	_noshift();		/* initialize keyboard device driver */
	_videx();		/* initialize video device driver    */
	midion();		/* initialize MIDI device driver     */
	startclk(60);
}

/*
 * void bye();
 */

bye()
{
	stopclk();
	midioff();		/* remove MIDI device driver	 */
}

/*
 * void flushconsole();
 */

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

/*
 * int statconsole();
 *
 *		return = 1 if data available
 *		       = 0 if no data available
 */

statconsole()
{
	
	return(((*KDATA & 0xff) < 128) ? 0 : 1);
}

/*
 * int getconsole();
 *
 *		return = character from keyboard
 */

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

/*
 * int getmidi();
 *
 *		returns next MIDI byte from receive buffer
 */

getmidi()
{
	return(getbyte());
}

/*
 * int sendbyte(c)
 * int	c;
 *
 *		return 0 always (for now)
 *
 *		place byte in transmit buffer and enable transmit interrupts.
 */

sendmidi(c)
int c;
{
	sendbyte(c);
	return(0);
}

long hz200()
{
	return((long) grabclock());
}

SHAR_EOF
if test 1301 -ne "`wc -c < 'II+machdep.c'`"
then
	echo shar: error transmitting "'II+machdep.c'" '(should have been 1301 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'midi.h'" '(2208 characters)'
if test -f 'midi.h'
then
	echo shar: will not over-write existing file "'midi.h'"
else
cat << \SHAR_EOF > 'midi.h'
/*
 * Midi Data Monitor
 *
 * Copyright (c) 1987 by Tim Thompson, All Rights Reserved.
 * Permission granted for copying and distribution for non-commercial use.
 */

/*
 * One of the following should be uncommented
 */

/* #define ATARI */
/* #define DATALIGHT */
/* #define APPLEII */
#define UNIX

#include "stdio.h"

#define NOTEON 0x90

/*
   The 'midiaction' structure contains pointers to functions that
   will be called for each type of midi event received.  See midi.c
   for the finite state machine that makes use of this.
 */

struct midiaction {
	int (*mi_off)();	/* 0x8- note off */
	int (*mi_on)();		/* 0x9- note on */
	int (*mi_pressure)();	/* 0xa- key pressure */
	int (*mi_parameter)();	/* 0xb- controller change */
	int (*mi_program)();	/* 0xc- program change */
	int (*mi_chanpress)();	/* 0xd- channel pressure */
	int (*mi_pitchbend)();	/* 0xe- pitch wheel */
	int (*mi_sysex)();	/* 0xf0 system exclusive */
				/* 0xf1 is undefined */
	int (*mi_position)();	/* 0xf2 song position */
	int (*mi_song)();	/* 0xf3 song number */
				/* 0xf4 is undefined */
				/* 0xf5 is undefined */
	int (*mi_tune)();	/* 0xf6 */
	int (*mi_eox)();	/* 0xf7 end of system exclusive */
	int (*mi_timing)();	/* 0xf8 timing clock */
				/* 0xf9 is undefined */
	int (*mi_start)();	/* 0xfa sequencer start */
	int (*mi_continue)();	/* 0xfb sequencer continue */
	int (*mi_stop)();	/* 0xfc sequencer stop */
				/* 0xfd is undefined */
	int (*mi_active)();	/* 0xfe active sensing */
	int (*mi_reset)();	/* 0xff system reset */
};

extern struct midiaction Midi;
extern int Currchan;
extern int Debug;
extern struct midiaction Textmidi;
extern int Debug;
extern int Pr_bytes;
extern int Pr_on;
extern int Pr_off;
extern int Pr_pressure;
extern int Pr_parameter;
extern int Pr_program;
extern int Pr_chanpress;
extern int Pr_pitchbend;
extern int Pr_sysex;
extern int Pr_position;
extern int Pr_song;
extern int Pr_tune;
extern int Pr_eox;
extern int Pr_timing;
extern int Pr_start;
extern int Pr_continue;
extern int Pr_stop;
extern int Pr_reset;
extern char *Trapbuff;
extern char *Trapptr;

long hz200();
char *alloc();

#ifdef ATARI
#include <osbind.h>
#define RS232 1
#define CONSOLE 2
#define MIDI 3
#endif
SHAR_EOF
if test 2208 -ne "`wc -c < 'midi.h'`"
then
	echo shar: error transmitting "'midi.h'" '(should have been 2208 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'midi.c'" '(10404 characters)'
if test -f 'midi.c'
then
	echo shar: will not over-write existing file "'midi.c'"
else
cat << \SHAR_EOF > 'midi.c'
/*
 * Midi Data Monitor
 *
 * Copyright (c) 1987 by Tim Thompson, All Rights Reserved.
 * Permission granted for copying and distribution for non-commercial use.
 *
 * A MIDI parser
 */

#include "midi.h"

/*
 * midiparse(inbyte,intime)
 *
 * This is a finite state machine that recognizes MIDI.  As each MIDI
 * statement is recognized, the 'midiaction' functions (in the external
 * structure 'Midi') are called.  If a single-byte MIDI message is
 * received, the function is called right away.  For multi-byte messages
 * the 'Currfunc' is set to the proper MIDI function, and State determines
 * what the state machine is currently looking for.  When the end of the
 * message is received, the 'Currfunc' is called, and the State goes back
 * to NORMAL.
 *
 * The midiparse() function should be called repeatedly, passing it each midi
 * byte that is to be processed.  A value of -1 will reset the finite
 * state machine.
 */

/* possible values for State */
#define NORMAL 0
#define NEEDONEBYTE 1
#define NEEDTWOBYTES 2
#define VARIABLELENGTH 3

#define MESSAGESIZE 256

int State = NORMAL;	/* The current state of the finite state machine. */
			/* It indicates what we're currently looking for. */

int (*Currfunc)() = NULL;	/* This is the 'midiaction' function for the */
				/* current MIDI message being processed. */

int Currchan = 0;	/* This is the current channel, ie. the channel # */
			/* on the latest 'channel message' status byte. */

long Currtime = 0L;	/* Time of the latest byte.  Ie. the time associated */
			/* with each message is going to be the time of the */
			/* LAST byte in the message. */

char *Currmessage = NULL;	/* Current message buffer */

int Messleng = 0;	/* Size of currently allocated message */

int Messindex = 0;	/* Index of next byte to go into */
			/* 'Currmessage'.  When Messindex */
			/* gets >= Messleng, the 'Currmessage' */
			/* is reallocated to a larger size. */

int highbit;
int Runnable = 0;	/* If non-zero, the current MIDI message */
			/* can use the "running status byte" feature. */

struct midiaction Midi = {
	NULL,NULL,NULL,NULL,NULL,
	NULL,NULL,NULL,NULL,NULL,
	NULL,NULL,NULL,NULL,NULL,
	NULL,NULL,NULL
};

char *malloc();
char *alloc();

midiparse(inbyte,intime)
int inbyte;
long intime;
{
	if ( inbyte == -1 ) {
		State = NORMAL;
		Currfunc = NULL;
		Currchan = 0;
		Messindex = 0;
		return;
	}

	/* If necessary, allocate larger message buffer. */
	if ( Messindex >= Messleng )
		biggermess(&Currmessage,&Messleng);

	if ( (inbyte & 0x80) != 0 )
		highbit = 1;
	else
		highbit = 0;

	Currtime = intime;

	/*
	 * Variable length messages (ie. the 'system exclusive')
	 * can be terminated by the next status byte, not necessarily
	 * an EOX.  Actually, since EOX is a status byte, this
	 * code ALWAYS handles the end of a VARIABLELENGTH message.
	 */
	if ( State==VARIABLELENGTH && highbit )  {
		/* The message has ended; call Currfunc and reset. */
		if ( Currfunc!=NULL && Messindex>0 )
			(*Currfunc)(Currmessage,Messindex,Currtime);
		Currfunc = NULL;
		State = NORMAL;
	}

	/*
	 * Status bytes always start a new message.
	 */

	if ( highbit ) {
		Messindex = 0;
		Currmessage[Messindex++] = inbyte;
	}

	/*
	   Real time messages can occur ANYPLACE.
	*/
	if ( (inbyte & 0xf8) == 0xf8 ) {
		realmess(inbyte);
		return;
	}

	/*
	   System Messages.
	*/
	if ( (inbyte & 0xf0) == 0xf0 ) {
		sysmess(inbyte);
		Runnable = 0;
		return;
	}

	/*
	   Channel (Voice and Mode) Messages.
	*/
	if ( (inbyte & 0x80) != 0 ) {
		chanmess(inbyte);
		/* Channel messages can make use of */
		/* the "running status byte" feature. */
		Runnable = 1;
		return;
	}

	/*
	 * We've got a Data byte.
	 */

	Currmessage[Messindex++] = inbyte;

	switch ( State ) {
	case NORMAL:
		/*
		 * We shouldn't get here, since in NORMAL mode
		 * we're expecting a new status byte, NOT any
		 * data bytes.
	 	 */
		midierr("Unexpected data byte in NORMAL mode!");
		break;
	case NEEDTWOBYTES:
		/* wait for the second byte */
		if ( Messindex < 3 )
			return;
		/* THERE IS PURPOSELY NO 'break' HERE, WE WANT */
		/* TO FALL INTO THE NEXT 'case'. */
	case NEEDONEBYTE:
		/* We've completed a 1 or 2 byte message. */
		if ( Currfunc != NULL )
			(*Currfunc)(Currmessage,Messindex,Currtime);
		if ( Runnable ) {
			/* In Runnable mode, we reset the message */
			/* index, but keep the Currfunc and State the */
			/* same.  This provides the "running status */
			/* byte" feature. */
			Messindex = 1;
		}
		else {
			/* If not Runnable, reset to NORMAL mode */
			State = NORMAL;
			Currfunc = NULL;
		}
		break;
	case VARIABLELENGTH:
		/* nothing to do */
		break;
	}
	return;
}

/*
 * realmess(inbyte)
 *
 * Call the real-time function for the specified byte, immediately.
 * These can occur anywhere, so they don't change the State.
 */

realmess(inbyte)
int inbyte;
{
	int (*f)() = NULL;

	switch ( inbyte ) {
	case 0xf8:
		f = Midi.mi_timing;
		break;
	case 0xfa:
		f = Midi.mi_start;
		break;
	case 0xfb:
		f = Midi.mi_continue;
		break;
	case 0xfc:
		f = Midi.mi_stop;
		break;
	case 0xfe:
		f = Midi.mi_active;
		break;
	case 0xff:
		f = Midi.mi_reset;
		break;
	}
	if ( f != NULL )
		(*f)(Currmessage,Messindex,Currtime);
	return;
}

/*
 * chanmess(inbyte)
 *
 * Interpret a Channel (voice or mode) Message status byte.
 */

chanmess(inbyte)
int inbyte;
{
	Currchan = inbyte & 0xf;	/* channel # is lower 4 bits */

	/* The high 4 bits, which determine the type of channel message. */

	switch ( inbyte & 0xf0 ) {
	case 0x80:
		Currfunc = Midi.mi_off;
		State = NEEDTWOBYTES;
		break;
	case 0x90:
		Currfunc = Midi.mi_on;
		State = NEEDTWOBYTES;
		break;
	case 0xa0:
		Currfunc = Midi.mi_pressure;
		State = NEEDTWOBYTES;
		break;
	case 0xb0:
		Currfunc = Midi.mi_parameter;
		State = NEEDTWOBYTES;
		break;
	case 0xc0:
		Currfunc = Midi.mi_program;
		State = NEEDONEBYTE;
		break;
	case 0xd0:
		Currfunc = Midi.mi_chanpress;
		State = NEEDONEBYTE;
		break;
	case 0xe0:
		Currfunc = Midi.mi_pitchbend;
		State = NEEDTWOBYTES;
		break;
	}
	return;
}

/*
 * sysmess(inbyte)
 *
 * Initialize (and possibly call) the MIDI function for the specified byte.
 * Set the State that the state-machine should go into.  If the function
 * is not called immediately, Currfunc is set, so that when the state machine
 * gets to the end of the MIDI message, it can then call the function.
 * If the function IS called immediately, the finite state machine is reset
 * (Currfunc=NULL,State=NORMAL).
 */

sysmess(inbyte)
int inbyte;
{
	int (*f)() = NULL;

	switch ( inbyte ) {
	case 0xf0:
		Currfunc = Midi.mi_sysex;
		State = VARIABLELENGTH;
		break;
	case 0xf2:
		Currfunc = Midi.mi_position;
		State = NEEDTWOBYTES;
		break;
	case 0xf3:
		Currfunc = Midi.mi_song;
		State = NEEDONEBYTE;
		break;
	case 0xf6:
		f = Midi.mi_tune;
		Currfunc = NULL;
		State = NORMAL;
		break;
	case 0xf7:
		f = Midi.mi_eox;
		Currfunc = NULL;
		State = NORMAL;
		break;
	}
	if ( f != NULL )
		(*f)(Currmessage,Messindex,Currtime);
	return;
}

/*
 * biggermess(amessage,aMessleng);
 *
 * Allocate a bigger message buffer.  The current message and its length
 * are passed by pointer, so that they can both be modified.
 */

biggermess(amessage,aMessleng)
char **amessage;
int *aMessleng;
{
	char *oldmess = *amessage;
	char *newmess;
	int oldleng = *aMessleng;

	*aMessleng += MESSAGESIZE;
	newmess = alloc( (unsigned)(sizeof(char)*(*aMessleng)) );

	/* copy old message into larger new message */
	if ( oldmess != NULL ) {
		char *p = newmess;
		char *q = oldmess;
		char *endq = &oldmess[oldleng];

		for ( ; q!=endq ; p++,q++ )
			*p = *q;
		myfree(oldmess);
	}
	*amessage = newmess;
}

char *
alloc(n)
unsigned n;
{
	char *p;
	if ( (p=malloc(n)) == NULL ) {
		printf("*** ERROR *** alloc has failed ?!?\n");
		/* To attempt to continue, I don't exit.  Fat chance the */
		/* program can continue much longer, but maybe you can save */
		/* something. */
	}
	return(p);
}

myfree(p)
char *p;
{
	if ( p == NULL ) {
		fprintf(stderr,"*** ERROR *** myfree called with p==NULL!\n");
		return;
	}
#ifndef ATARI
	/* SOMETHING'S WRONG WITH THE ST'S STORAGE ALLOCATOR (he hoped) */
	free(p);
#endif
}

/*
 * MIDI utility functions.
 */

midinote(onoff,chan,pitch,vol)
{
	if ( Debug )
		printf("Midinote(chan=%d,pitch=%d,vol=%d)\n",chan,pitch,vol);
	sendmidi( ((onoff==1)?(0x90):(0x80)) | ((chan)&0xf) );
	sendmidi( pitch & 0x7f );
	sendmidi( vol & 0x7f );
}

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

midierr(s)
char *s;
{
	printf("%s\n",s);
}

allnotesoff()
{
	int n;
	/* Go through all channels. */
	for ( n=0; n<15; n++ ) {
		sendmidi( n | 0xb0 );
		sendmidi( 0x7b );
		sendmidi( 0x00 );
	}
}

/*
 * pause for n milliseconds.
 */

millipause(n)
{
	long goal = hz200() + (long)(n/5);

	while ( hz200() <= goal )
		;
}

pollpause(n)
{
	long goal = hz200() + (long)(n/5);

	while ( hz200() <= goal )
		pollmidi();
}

pollmidi()
{
	int c;
	long time;

	grabmidi();	/* grab any pending input */
	getnextbyte(&c,&time);
	if ( c >= 0 )
		midiparse(c,time);
}

struct byteinfo {
	int bi_byte;
	long bi_time;
};

/* Circular buffer for MIDI bytes that have been received but not processed */
#define BYTEBUFF 16
struct byteinfo Bytes[BYTEBUFF];
int Topbyte = 0;	/* Index for top byte in the circular buffer. */
int Botbyte = 0;	/* Index for next available slot in the circ. buffer */

/*
 * Grab and add all currently available MIDI bytes to the Bytes
 * array, a circular buffer.
 */

grabmidi()
{
	register struct byteinfo *b;
	register int c;
	register int avail;

	if ( ! statmidi() )
		return;		/* quick exit when nothing's there */

	/* compute number of available bytes in circular buffer */
	avail = Topbyte - Botbyte;
	if ( avail <= 0 )
		avail += BYTEBUFF;
	/* Don't press your luck trying to pack the buffer */
	avail -= 2;

	while ( statmidi() && avail-- > 0 ) {
		/* ignore active sensing */
		if ( (c=(getmidi() & 0xff)) == 0xfe )
			continue;

		if ( Trapptr != NULL )
			*Trapptr++ = c;

		b = &(Bytes[Botbyte++]);
		b->bi_byte = c;
		b->bi_time = hz200();
		if ( Botbyte >= BYTEBUFF )
			Botbyte = 0;
	}
}

getnextbyte(ac,atime)
int *ac;
long *atime;
{
	register struct byteinfo *b;

	if ( Topbyte == Botbyte ) {
		*ac = -1;	/* There are no bytes in the buffer. */
		return;
	}

	b = &(Bytes[Topbyte++]);
	*atime = b->bi_time;
	*ac = b->bi_byte;

	/* Wrap around at the end of the circular buffer. */
	if ( Topbyte >= BYTEBUFF )
		Topbyte = 0;
}
SHAR_EOF
if test 10404 -ne "`wc -c < 'midi.c'`"
then
	echo shar: error transmitting "'midi.c'" '(should have been 10404 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(196 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
midimon : mon1.o mon2.o midi.o machdep.o
	cc mon1.o mon2.o midi.o machdep.o -o midimon

lint :
	lint mon1.c mon2.c midi.c machdep.c

arc :
	arc a midimon.arc machdep.c midi.c midi.h mon1.c mon2.c
SHAR_EOF
if test 196 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 196 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mon1.c'" '(5928 characters)'
if test -f 'mon1.c'
then
	echo shar: will not over-write existing file "'mon1.c'"
else
cat << \SHAR_EOF > 'mon1.c'
/*
 * Midi Data Monitor
 *
 * Copyright (c) 1987 by Tim Thompson, All Rights Reserved.
 * Permission granted for copying and distribution for non-commercial use.
 */

#include "midi.h"

int Debug = 1;
int Pr_bytes = 0;
int Pr_on = 1;
int Pr_off = 1;
int Pr_pressure = 0;
int Pr_parameter = 1;
int Pr_program = 1;
int Pr_chanpress = 0;
int Pr_pitchbend = 0;
int Pr_sysex = 1;
int Pr_position = 1;
int Pr_song = 1;
int Pr_tune = 1;
int Pr_eox = 1;
int Pr_timing = 1;
int Pr_start = 1;
int Pr_continue = 1;
int Pr_stop = 1;
int Pr_reset = 1;
char *Trapbuff;
char *Trapptr = NULL;

main()
{
	hello();
	printf("Midi Data Analyzer\n");
	printf("Press '?' for some help.\n\n");
	Trapbuff = alloc((unsigned)32767);
	Trapptr = Trapbuff;
	prompt();
	Midi = Textmidi;
	midiparse(-1,0L);		/* Initialize the MIDI parser. */
	for ( ;; )
		npollmidi();
}

prompt()
{
	printf("--> ");
	fflush(stdout);
}

npollmidi()
{
	int ch;
	long time;

	grabmidi();	/* grab any pending input */
	getnextbyte(&ch,&time);
	if ( ch >= 0 ) {
		if ( Pr_bytes )
			printf("Raw MIDI byte: hex=%2x decimal=%d\n",ch,ch);
		midiparse(ch,time);
	}

	/* Check keyboard for ESC, to send allnotesoff */
	if ( statconsole() ) {
		ch = getconsole() & 0xff;
		switch (ch) {
		case 'o':
#ifndef APPLEII
		case '\033':
#endif
			allnotesoff();
			printf("\nAll notes off has been sent!\n");
			break;
		case 'q':
			bye();
			exit(0);
			break;
		case '?':
	printf("\n\nThe MIDI Data Analyzer has the following commands:\n\n");
	printf("   =   : to print the current settings\n");
	printf("   +   : enable printing of MIDI messages (by type)\n");
	printf("   -   : disable printing of MIDI messages (by type)\n");
	printf("   s   : to send arbitrary MIDI bytes\n");
	printf("   t   : trap all incoming bytes in a buffer\n");
	printf("   d   : dump the buffer into a file\n");
	printf("  ESC  : to send an all-notes-off message\n");
	printf("   q   : to quit\n\n");
			break;
		case 't':
			printf("Trapping of data has been turned on.\n");
			Trapptr = Trapbuff;
			break;
		case 'd':
			dumpdata();
			/* purposely fall through */
		case 'T':
			printf("Trapping of data has been turned off.\n");
			Trapptr = NULL;
			break;
		case 's':
		case 'x':
			{ int hex=0,nchars=0, c;
printf("\nEnter hex characters\n(2 per MIDI byte to be sent): ");
			fflush(stdout);
			while ( (c=getchar()) != '\n' ) {
				/* convert to upper case */
				if ( c >= 'A' && c <= 'F' )
					c = c - 'A' + 'a';
				/* grab hex chars */
				if ( c>='0'&&c<='9' ||
						 c>='a'&&c<='f' ) {
					int val = 0;
					if ( c>='0' && c<= '9' )
						val = c - '0';
					if ( c>='a' && c<= 'f' )
						val = c - 'a' + 10;
					hex = hex * 16 + val;
					if ( ++nchars >= 2 ) {
						sendmidi(hex);
						nchars = hex = 0;
					}
				}
				else if ( nchars > 0 ) {
					sendmidi(hex);
					nchars = hex = 0;
				}
			}
			if ( nchars > 0 )
				sendmidi(hex);
			}
			break;
		case '=':
printf("\nThe following MIDI message types are enabled:\n");
			penable("Raw bytes",Pr_bytes);
			penable("Note ON",Pr_on);
			penable("Note OFF",Pr_off);
			penable("Key pressure",Pr_pressure);
			penable("Parameter",Pr_parameter);
			penable("Program",Pr_program);
			penable("Channel Pressure",Pr_chanpress);
			penable("Pitchbend",Pr_pitchbend);
			penable("System Exclusive",Pr_sysex);
			penable("Song position",Pr_position);
			penable("Song Number",Pr_song);
			penable("Tune Request",Pr_tune);
			penable("Eox",Pr_eox);
			penable("Timing clock",Pr_timing);
			penable("Start",Pr_start);
			penable("Continue",Pr_continue);
			penable("Stop",Pr_stop);
			penable("Reset",Pr_reset);
			break;
		case '+':
		case '-':
			{
			int onoff = (ch=='+')?1:0;
			char rawbuff[100], inbuff[100], *p;
			p = (onoff?"on":"off");
			printf("\n");
reask:
printf("\nEnter message type you want to turn %s,\n",p);
printf("      or enter '*' to turn everything %s,\n",p);
printf("      or enter '?' for a list of the keywords --> ");
			fflush(stdout);
			gets(rawbuff);
			if ( *rawbuff=='\0'
				|| sscanf(rawbuff,"%s",inbuff)!=1
				|| *inbuff=='\0' || *inbuff=='\n' ) {
				printf("\n");
				break;
			}
			if ( *inbuff=='h' || *inbuff=='?' ) {
printf("\n\nThese are the MIDI message types you can turn on and off:\n\n");
printf("   bytes, on, off, pressure, parameter, program\n");
printf("   chanpress, pitchbend, sysex, position\n");
printf("   song, tune, eox, timing, start, continue, stop, reset\n");
				goto reask;
			}
			if ( *inbuff == '*' ) {
				if ( onoff == 1 )
					printall();
				else
					noprintall();
				break;
			}
			else if ( strcmp(inbuff,"bytes") == 0 )
				Pr_bytes = onoff;
			else if ( strcmp(inbuff,"on")==0 )
				Pr_on = onoff;
			else if ( strcmp(inbuff,"off")==0 )
				Pr_off = onoff;
			else if ( strcmp(inbuff,"pressure")==0 )
				Pr_pressure = onoff;
			else if ( strcmp(inbuff,"parameter")==0 )
				Pr_parameter = onoff;
			else if ( strcmp(inbuff,"program")==0 )
				Pr_program = onoff;
			else if ( strcmp(inbuff,"chanpress")==0 )
				Pr_chanpress = onoff;
			else if ( strcmp(inbuff,"pitchbend")==0 )
				Pr_pitchbend = onoff;
			else if ( strcmp(inbuff,"sysex")==0 )
				Pr_sysex = onoff;
			else if ( strcmp(inbuff,"position")==0 )
				Pr_position = onoff;
			else if ( strcmp(inbuff,"song")==0 )
				Pr_song = onoff;
			else if ( strcmp(inbuff,"tune")==0 )
				Pr_tune = onoff;
			else if ( strcmp(inbuff,"eox")==0 )
				Pr_eox = onoff;
			else if ( strcmp(inbuff,"timing")==0 )
				Pr_timing = onoff;
			else if ( strcmp(inbuff,"start")==0 )
				Pr_start = onoff;
			else if ( strcmp(inbuff,"continue")==0 )
				Pr_continue = onoff;
			else if ( strcmp(inbuff,"stop")==0 )
				Pr_stop = onoff;
			else if ( strcmp(inbuff,"reset")==0 )
				Pr_reset = onoff;
			else {
printf("\nUnrecognized message type!  Enter '?' for a list.\n");
				goto reask;
			}
			}
			break;
		default:
printf("\nUnrecognized command character!  Press '?' for list!\n");
			break;
		}
		prompt();
	}

}
SHAR_EOF
if test 5928 -ne "`wc -c < 'mon1.c'`"
then
	echo shar: error transmitting "'mon1.c'" '(should have been 5928 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mon2.c'" '(4523 characters)'
if test -f 'mon2.c'
then
	echo shar: will not over-write existing file "'mon2.c'"
else
cat << \SHAR_EOF > 'mon2.c'
/*
 * Midi Data Monitor
 *
 * Copyright (c) 1987 by Tim Thompson, All Rights Reserved.
 * Permission granted for copying and distribution for non-commercial use.
 */

#include "midi.h"

penable(s,v)
char *s;
int v;
{
	if ( v == 0 )
		return;
	printf("%s\n",s);
}

printall()
{
	Pr_bytes = Pr_on = Pr_off = Pr_pressure = Pr_parameter = 1;
	Pr_program = Pr_chanpress = Pr_pitchbend = Pr_sysex = 1;
	Pr_position = Pr_song = Pr_tune = Pr_eox = 1;
	Pr_timing = Pr_start = Pr_continue = Pr_stop = 1;
	Pr_reset = 1;
}

noprintall()
{
	Pr_bytes = Pr_on = Pr_off = Pr_pressure = Pr_parameter = 0;
	Pr_program = Pr_chanpress = Pr_pitchbend = Pr_sysex = 0;
	Pr_position = Pr_song = Pr_tune = Pr_eox = 0;
	Pr_timing = Pr_start = Pr_continue = Pr_stop = 0;
	Pr_reset = 0;
}

tx_on(mess,indx,time)
char *mess;
int indx;
long time;
{
	if ( Debug && Pr_on ) {
		printf("NOTE ON time:%ld chan:%d pitch:%d vol:%d\n",
			time,Currchan+1,(int)(mess[1]),(int)(mess[2]));
	}
}

tx_off(mess,indx,time)
char *mess;
int indx;
long time;
{
	if ( Debug && Pr_off ) {
		printf("NOTE OFF time:%ld chan:%d pitch:%d vol:%d\n",
			time,Currchan+1,(int)(mess[1]),(int)(mess[2]));
	}
}

tx_pressure(mess,indx,time)
char *mess;
int indx;
long time;
{
	if ( Debug && Pr_pressure ) {
		printf("POLYPHONIC KEY PRESSURE time:%ld chan:%d pitch:%d value:%d\n",
			time,Currchan+1,(int)(mess[1]),(int)(mess[2]));
	}
}

tx_parameter(mess,indx,time)
char *mess;
int indx;
long time;
{
	if ( Debug && Pr_parameter ) {
		printf("PARAMETER time:%ld chan:%d control:%d data:%d\n",
			time,Currchan+1,(int)(mess[1]),(int)(mess[2]));
	}
}

tx_program(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_program ) {
		printf("PROGRAM CHANGE time:%ld chan:%d program:%d\n",
			time,Currchan+1,(int)(mess[1]));
	}
}

tx_chanpress(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_chanpress ) {
		printf("CHANNEL (AFTER TOUCH) PRESSURE time:%ld chan:%d pressure:%d\n",
			time,Currchan+1,(int)(mess[1]));
	}
}


tx_pitchbend(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_pitchbend ) {
		printf("PITCHBEND time:%ld chan:%d lowbyte:%d highbyte:%d\n",
			time,Currchan+1,(int)(mess[1]),(int)(mess[2]));
	}
}

tx_sysex(mess,indx,time)
char *mess;int indx;long time;
{
	int n;

	if ( Debug && Pr_sysex ) {
		printf("SYSTEM EXCLUSIVE time:%ld length:%d\n",time,indx);
		for ( n=0; n<indx; n++ ) {
			if ( n > 0 && (n%25)==0 )
				printf("\n");
			printf("%2x ",(int)(mess[n] & 0xff));
		}
		printf("\n");
	}
}

tx_position(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_position )
		printf("SONG POSITION time:%ld lowbyte=%d highbyte=%d\n",
			time,(int)(mess[1]),(int)(mess[2]));
}

tx_song(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_song )
		printf("SONG SELECT time:%ld number=%d\n",time,(int)(mess[1]));
}

tx_tune(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_tune )
		printf("TUNE REQUEST time:%ld\n",time);
}

tx_eox(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_eox )
		printf("END OF SYSTEM EXCLUSIVE time:%ld\n",time);
}

tx_timing(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_timing )
		printf("TIMING CLOCK time:%ld\n",time);
}

tx_start(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_start )
		printf("START time:%ld\n",time);
}

tx_continue(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_continue )
		printf("CONTINUE time:%ld\n",time);
}

tx_stop(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_stop )
		printf("STOP time:%ld\n",time);
}

tx_active(mess,indx,time)
char *mess;int indx;long time;
{
#ifdef OLDSTUFF
	if ( Debug && Pr_active )
		printf("ACTIVE SENSING time:%ld\n",time);
#endif
}

tx_reset(mess,indx,time)
char *mess;int indx;long time;
{
	if ( Debug && Pr_reset )
		printf("SYSTEM RESET time:%ld\n",time);
}

struct midiaction Textmidi = {
	tx_off,
	tx_on,
	tx_pressure,
	tx_parameter,
	tx_program,
	tx_chanpress,
	tx_pitchbend,
	tx_sysex,
	tx_position,
	tx_song,
	tx_tune,
	tx_eox,
	tx_timing,
	tx_start,
	tx_continue,
	tx_stop,
	tx_active,
	tx_reset
};

dumpdata()
{
	char *p, fname[128];
	FILE *f;
	int n, c;

	printf("Enter name of file to dump buffered data into --> ");
	fflush(stdout);
	for ( n=0; (c=getchar()) != '\n'; n++ )
		fname[n] = c;
	fname[n] = '\0';
	f = fopen(fname,"w");
	for ( n=0,p=Trapbuff; p<Trapptr; n++,p++ )
		putc(*p,f);
	printf("%d bytes of data have been written to file '%s'\n",n,fname);
	fclose(f);
}
SHAR_EOF
if test 4523 -ne "`wc -c < 'mon2.c'`"
then
	echo shar: error transmitting "'mon2.c'" '(should have been 4523 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'II+README'" '(2321 characters)'
if test -f 'II+README'
then
	echo shar: will not over-write existing file "'II+README'"
else
cat << \SHAR_EOF > 'II+README'
This describes the changes made to support the Apple II+.  The files
described below (e.g. mon1.c) are all prefixed with II+ (e.g. II+mon1.c).

>From midi-request Thu Mar 12 16:31 EST 1987 remote from twitch
#### Forwarded from the MIDI mailing list (twitch!midi) ####
>From uucp Thu Mar 12 15:40 EST 1987
>From pjg  Thu Mar 12 15:34:53 1987 remote from desoto
Date: 12 Mar 87 15:34:53 EST (Thu)
From: desoto!pjg (Pete Giacomini)
Full-Name: Pete Giacomini
Message-Id: <8703122034.AA05975@lc/garage/desoto.DK>
Received: by lc/garage/desoto.DK; 8703122034
Apparently-To: twitch!midi

I have made some minor modifications to Tim's MIDI monitor program to
make it usable on an apple ][+. The changes and requirements for
being able to use it are listed below. The major addition is an
interrupt driven device handler that allows an interface to Aztec
'C'. The routines that C can call are:

	midion()	to install the device driver
	midioff()	stop timer and remove device driver
	startclk(tempo)	to set the timer for tempo bpm and start it running
	stopclk()	to stop the timer
	statmidi()	to check for receive data in buffer
	getbyte()	to get next input MIDI byte from receive buffer
	sendbyte(byte)	to put byte in the transmit buffer
	grabclock()	to get the value of the software clock
	chtmpo(tempo)	to change the timer to tempo bpm

The machdep.c file has been modified to work with an apple ][+ and
the 6502 assembly language driver has been added in mdriver.s. The
mon.c source has been split into two sections so that it could
be compiled on the apple. Some minor changes where made in mon1.c,
mon2.c, and midi.c to make them compatible with the apple. The only
change that the user would see is that the all notes off command has
been changed to o instead of <esc>.  The apple configuration assumed 
is RAMCARD in slot 0, Passport MIDI interface in slot 2, VIDEX video 
card in slot 3, Autostart ROM, and AZTEC 'C'. 

To make the MIDI monitor with AZTEC 'C' version 1.02:
 
	as65 -o mdriver.o mdriver.s
	c65 -o machdep.o machdep.c
	cci -o midi.o midi.c
	cci -o mon1.o -z2500 mon1.c
	cci -o mon2.o mon2.c
	ln -o midimon midi.o mon1.o mon2.o machdep.o mdriver.o shint.lib
						 
I am uuto'ing the source to Tim so that he can include whatever it makes
sense to include in the archives.

	Peter Giacomini    desoto!pjg



SHAR_EOF
if test 2321 -ne "`wc -c < 'II+README'`"
then
	echo shar: error transmitting "'II+README'" '(should have been 2321 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'II+driver.s'" '(5128 characters)'
if test -f 'II+driver.s'
then
	echo shar: will not over-write existing file "'II+driver.s'"
else
cat << \SHAR_EOF > 'II+driver.s'
*
*	mdriver.a65		Peter Giacomini		last modified: 3/4/87
*
*	MIDI driver routines for apple II+ with Passport midi interface
*	in slot 2, RAMCARD in slot 0, VIDEX card in slot 3, and AUTOSTART
*	ROM.
*
*	zero page usage
*
SP	=	$2	;	AZTEC psuedo-stack pointer
R0	=	$8	;	AZTEC psuedo register
ACC	=	$45	;	monitor accumulator storage
RBUFIN	=	$60	;	receive buffer pointers
RBUFOUT	=	$62
SBUFIN	=	$64	;	transmit buffer pointers
SBUFOUT	=	$66
ISAVE	=	$68	;	interrupt vector storage
DIVQ	=	$6A	;	quotion for tempo division algorithm
REMAIN	=	$6C	;	remainder for tempo division algorithm
CLOCK	=	$6E	;	software clock
COUNTER	=	$70	;	timer interrupts per MIDI clock
INTCNT	=	$72	;	current timer interrupt count
TBYTE	=	$74	;	tempo in bpm
*
*	other addresses
*
IRQ	=	$3FE	;	interrupt soft vector
RBUFFER	=	$6000	;	receive buffer
SBUFFER	=	$6100	;	transmit buffer
TREG1	=	$C0A0	;	timer control register 1
TREG2	=	$C0A1	;	timer control register 2
TMR2H	=	$C0A4	;	timer high byte
TMR2L	=	$C0A5	;	timer low byte
MSTAT	=	$C0A8	;	uart control/status register
MDATA	=	$C0A9	;	uart data register
*
*	constants
*
RMASK	=	$1	;	uart receive mask
MRST	=	$3	;	uart reset
MOFF	=	$11	;	uart interrupts off
COFF	=	$13	;	timer off
MRCV	=	$91	;	uart receive interrupts
SNDRCV	=	$B1	;	uart receive and transmit interrupts
DIVCONT	=	$9C0E	;	tempo division constant
*
*	interrupt handler
*
irqh	
	lda ACC			; required for monitor
	pha
	tya
	pha
	ldy	#0
	lda	MSTAT		; get uart status
	bpl	timer		; not uart interrupt
	and	#RMASK		; check for receive interrupt
	beq	xmit
	lda	MDATA		; get midi data
	cmp	#$fe		; discard active sensing
	beq	iout
	sta	(RBUFIN),Y	; save in receive buffer
	inc	RBUFIN
	jmp	iout
xmit	lda	SBUFOUT		; transmit interrupt
	cmp	SBUFIN		; test for data to send
	beq	sout
	lda	(SBUFOUT),Y
	sta	MDATA		; transmit data
	inc	SBUFOUT
	jmp	iout
sout	lda	#MRCV		; turn off xmit interrupts if buffer empty
	sta	MSTAT
iout	pla
	tay
	pla
	rti
timer	lda	TREG2		; check for timer interrupt
	bpl	done
	lda	TMR2H		; clear interrupt
	dec	INTCNT
	bne	iout
	lda	COUNTER
	sta	INTCNT
	lda	#$f8		; send a midi clock
	sta	(SBUFIN),Y
	inc	SBUFIN
	lda	#SNDRCV		; enable transmit interrupts
	sta	MSTAT
	inc	CLOCK		; increment software clock
	bne	iout
	inc	CLOCK+1
	jmp	iout
done	pla			; not a midi interrupt
	tay
	pla
	jmp	(ISAVE)
*
*	void stopclock();
*
*	stopclk disables timers
*
	public stopclk_
stopclk_
	pha
	tya
	pha
	lda	#COFF
	sta	TREG2
	sta	TREG1
	ldy	#0
	lda	#$fc		; MIDI stop meassage
	sta	(SBUFIN),Y	; put in transmit buffer
	inc	SBUFIN
	lda	#SNDRCV		; enable transmit interrupts
	sta	MSTAT
	pla
	tay
	pla
	rts
*
*	void midion()
*
	public	midion_
midion_	
	sei
	pha
	lda	IRQ		; save soft vector
	sta	ISAVE
	lda	IRQ+1
	sta	ISAVE+1
	lda	#<irqh		; install midi interrupt handler
	sta	IRQ
	lda	#>irqh
	sta	IRQ+1
	lda	#0		; initialize buffer pointers
	sta	RBUFIN
	sta	RBUFOUT
	sta	SBUFIN
	sta	SBUFOUT
	lda	#>RBUFFER
	sta	RBUFIN+1
	sta	RBUFOUT+1
	lda	#>SBUFFER
	sta	SBUFIN+1
	sta	SBUFOUT+1
	lda	#COFF		; put timers in known state
	sta	TREG2
	sta	TREG1
	lda	#MRST		; initialize uart
	sta	MSTAT
	lda	#MRCV
	sta	MSTAT
	pla
	cli
	rts
*
*	void startclk(tempo)
*	unsigned tempo
*
	public	startclk
startclk
	pha
	tya
	pha
	lda	#0
	sta	CLOCK
	sta	CLOCK+1
	lda	#2
	sta	COUNTER
	sta	INTCNT
	jsr	chtmpo_
	lda	#$d3		; start timer
	sta	TREG2
	lda	#$92
	sta	TREG1
	ldy	#0
	lda	#$fa		; MIDI start meassage
	sta	(SBUFIN),Y	; put in transmit buffer
	inc	SBUFIN
	lda	#SNDRCV		; enable transmit interrupts
	sta	MSTAT
	pla
	tay
	pla
	rts	
*
*	int statmidi()
*
	public statmidi
statmidi	
	pha
	lda	#0		; initialize return value
	sta	R0		; assume no data
	sta	R0+1
	lda	RBUFIN		; check for receive data in buffer
	cmp	RBUFOUT
	beq	empty
	inc	R0		; data
empty	pla
	rts
*
* int getbyte()
*
	public	getbyte_
getbyte_	
	pha
	tya
	pha
	ldy	#0
	sty	R0+1
	lda	(RBUFOUT),Y	; get data from buffer
	inc	RBUFOUT
	sta	R0		; store in R0
	pla
	tay
	pla
	rts
*
*	void sendbyte(c)
*	int c;
*
	public	sendbyte
sendbyte	
	pha
	tya
	pha
	ldy	#0
	lda	(SP),Y		; retreive character from pseudo-stack
	sta	(SBUFIN),Y	; put in transmit buffer
	inc	SBUFIN
	lda	#SNDRCV		; enable transmit interrupts
	sta	MSTAT
	pla
	tay
	pla
	rts
*
*	int	grabclock();
*
	public grabclock
grabclock
	php
	sei
	lda	CLOCK
	sta	R0
	lda	CLOCK+1
	sta	R0+1
	plp
	rts
*
*	void chtmpo(tempo)
*	unsigned tempo
*
*	chtmpo changes the tempo to TBYTE bpm
*
	public chtmpo_
chtmpo_
	pha
	tya
	pha
	txa
	pha
	ldy	#0		; get tempo from stack
	lda	(SP),Y
	sta	TBYTE
	lda	#<DIVCONT	; determine timer value
	sta	DIVQ
	lda	#>DIVCONT
	sta	DIVQ+1
	lda	#0
	sta	REMAIN
	sta	REMAIN+1
	ldx	#16
divloop	asl	DIVQ
	rol	DIVQ+1
	rol	REMAIN
	rol	REMAIN+1
	sec
	lda	REMAIN
	sbc	TBYTE
	tay
	lda	REMAIN+1
	sbc	#0
	bcc	chknext
	sty	REMAIN
	sta	REMAIN+1
	inc	DIVQ
chknext	dex
	bne	divloop
	ldx	#5
mloop	asl	DIVQ
	rol	DIVQ+1
	dex
	bne	mloop
	php
	sei
	lda	DIVQ+1		; load timer 2
	sta	TMR2H
	lda	DIVQ
	sta	TMR2L
	plp
	pla
	tax
	pla
	tay
	pla
	rts	
*
*	void midioff()
*
	public	midioff_
midioff_
	sei
	pha
	jsr	stopclk_	; disable timers
	lda	#MOFF		; turn off uart
	sta	MSTAT
	lda	ISAVE
	sta	IRQ		; restore soft vector
	lda	ISAVE+1
	sta	IRQ+1
	pla
	cli
	rts
 
SHAR_EOF
if test 5128 -ne "`wc -c < 'II+driver.s'`"
then
	echo shar: error transmitting "'II+driver.s'" '(should have been 5128 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'midimon'"
cd ..
#	End of shell archive
exit 0
