[comp.music] Unix MIDI software

mike@orca.WV.TEK.COM (Mike Witt) (09/13/89)

Does anyone out there have any experience with a MIDI setup for a regular UNIX
workstation?  That is, a MIDI interface that connects to a standard RS232 port
and sequencing or other software that runs on UNIX.

Mike Witt
mike@orca.wv.tek.com

dag@hp-lsd.COS.HP.COM (David Geiser) (09/26/89)

Silence?

I, too, am UNIX based and would be interested in 
obtaining/porting/hacking MIDI SW.


			      dag
			     a.k.a.
			  David Geiser
			 (719) 590-5038
		    same last 7 for Yelnet*

			  *Trademark*

paul@hpldola.HP.COM (Paul Bame) (09/28/89)

MIDI on UN*X isn't a new idea of course.  This is a fun reference.  Hardware
presented in the article is for a Multibus SUN and an MPU-401 but the
software seems pretty generic.  Some of the MIDI books might be useful since
much of the software is in C anyway.

Anybody know of a MIDI controller (aka MPU-401) with an RS-232 port?  Yeah,
I know it's probably too slow but if the buffer was big enough...

	MIDI Music Software for UN*X
	Michael Hawley - The Droid Works
	Proceedings of the 1986 Summer USENIX Conference - Page 1

sahayman@iuvax.cs.indiana.edu (Steve Hayman) (09/29/89)

>Anybody know of a MIDI controller (aka MPU-401) with an RS-232 port?  Yeah,
>I know it's probably too slow but if the buffer was big enough...

An Atari ST (with some simple software) would make a nice
MIDI-to-RS232 converter.  It's got the ports already, lots of
memory, and it's cheap.  You wouldn't even need the monitor, and if
you could arrange to put the software on cartridge, you wouldn't
even need a floppy drive.  

(I'm not volunteering to write the software.)

tjt@cbnewsh.ATT.COM (timothy.j.thompson) (10/01/89)

From article <10430001@hp-lsd.COS.HP.COM>, by dag@hp-lsd.COS.HP.COM (David Geiser):
> Silence?

Perhaps this will stimulate things.

Enclosed is a minimal device driver that provides a /dev/midi that
talks to an MPU-compatible MIDI hardware interface.  It *only* allows
use of the UART mode of the MPU hardware, and the timing resolution of
the clock it provides is (I think) 10 milliseconds.  It was written
for AT&T System V Release 3.2 on a 6386, but may be portable to most
SVR3-based operating systems, perhaps even SVR2.  See the README
and midi.7 files for more info.  The right way to do something like
this is to use streams.  This is a quick and dirty (but also quite
usable) hack.
                   Tim Thompson = tjt@twitch.att.com | att!twitch!tjt

#! /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:
#	devmidi
# This archive created: Sun Oct  1 12:37:02 1989
export PATH; PATH=/bin:$PATH
if test ! -d 'devmidi'
then
	echo shar: creating directory "'devmidi'"
	mkdir 'devmidi'
fi
echo shar: entering directory "'devmidi'"
cd 'devmidi'
echo shar: extracting "'Driver.c'" '(5377 characters)'
if test -f 'Driver.c'
then
	echo shar: will not over-write existing file "'Driver.c'"
else
cat << \SHAR_EOF > 'Driver.c'
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
#include <sys/midi.h>

/* BUFSIZ is the size of the buffers obtained from geteblk().  Is there */
/* a #define elsewhere that gives this value?  (besides stdio.h) */
#define BUFSIZ 1024

#define CIRCLESIZE (BUFSIZ*MIDI_BUFS)

#define controller(dev) (minor(dev))

#define DATA_PORT 0x330
#define STATUS_PORT 0x331
#define DATA_READY 0x40
#define DATA_AVAILABLE 0x80
#define RESET 0xff
#define UART 0x3f
/* note that active sensing and ACK from controller are the same */
#define ACK 0xfe
#define ACTIVE 0xfe

#define midi_putdata(ctlr,c)	(outb(ctlr_to_data_port[ctlr],(c)))
#define midi_putcmd(ctlr,c)	(outb(ctlr_to_status_port[ctlr],(c)))
#define midi_getdata(ctlr)	(inb(ctlr_to_data_port[ctlr]))
#define midi_getstatus(ctlr)	(inb(ctlr_to_status_port[ctlr]))
#define data_is_available(ctlr)	(!(midi_getstatus(ctlr)&DATA_AVAILABLE))
#define ready_for_data(ctlr)	(!(midi_getstatus(ctlr)&DATA_READY))

void
midiinit()
{
	register int n;

	/* create an irq_to_ctlr array so that midiintr() can */
	/* get the ctlr number quickly. */
	for ( n=0; n<NUMIRQ; n++ )
		irq_to_ctlr[n] = 0;
	for ( n=0; n<midi_nctlr; n++ )
		irq_to_ctlr[ ctlr_to_irq[n] ] = n;
}

unsigned char *
midiqchr(q,off)
struct midi_queue *q;
off_t off;
{
	struct buf *b;
	unsigned char *a;

	b = q->buf[(int)((off/BUFSIZ)%MIDI_BUFS)];
	if ( ! b )
		return NULL;
	a = (unsigned char *)(b->b_un.b_addr);
	if ( ! a )
		return NULL;
	return (a + (int)(off%BUFSIZ));
}

void
midiqput(q,c)
register struct midi_queue *q;
int c;
{
	register unsigned char *p = midiqchr(q,q->high);

	if ( p ) {
		*p = c;
		q->high++;
		/* if we wrap around in the circular buffer, */
		/* make sure the low offset keeps up (ie. this */
		/* throws away the oldest unread data) */
		if ( (q->high - q->low) >= CIRCLESIZE )
			q->low = q->high - CIRCLESIZE + 1;
	}
}

midiqget(q)
struct midi_queue *q;
{
	register unsigned char *p;
	register int c;

	if ( q->low == q->high )
		return -1;

	p = midiqchr(q,q->low);
	if ( ! p )
		return -1;
	c = *p;
	q->low++;
	return c;
}

void
midireset(ctlr,uart)
{
	register struct midi_ctlr *m = &midi_ctlr[ ctlr ];
	register time_t etime;
	int n;

	while ( data_is_available(ctlr) )
		(void) midi_getdata(ctlr);

	/* try reset twice if ACK not received */
	for ( n=0; n<2; n++ ) {
		midi_putcmd(ctlr,RESET);
		/* probably shouldn't busy loop */
		etime = lbolt + HZ / 40;	/* for 25 milliseconds */
		while ( lbolt >= etime ) {
			if ( midiqget(&(m->in)) == ACK )
				break;
		}
		if ( lbolt < etime )
			break;
	}
	if ( n >= 2 )
		printf("midireset didn't get ACK?\n");
	if ( uart )
		midi_putcmd(ctlr,UART);	/* doesn't send an ACK back */
}

void
midiopen(dev)
{
	register struct midi_ctlr *m;
	register int ctlr = controller(dev);
	register int n;

	if ( ctlr >= midi_nctlr ) {
		u.u_error = ENXIO;
		return;
	}
	m = &midi_ctlr[ctlr];
	if ( ((m->flags)&ISOPEN) == 0 ) {
		/* opened for the first time */
		for ( n=0; n<MIDI_BUFS; n++ ) {
			m->in.buf[n] = geteblk();
			m->in.low = m->in.high = 0;
		}
		m->flags |= ISOPEN;
		m->flags &= (~ACTSENSE);/* default is to ignore active sensing */
		m->clockoffset = lbolt;	/* TIME starts out at 0 */
		midireset(ctlr,1);	/* default is UART mode */
	}
}

void
midiioctl(dev, cmd, arg, mode)
{
	register int ctlr = controller(dev);
	register struct midi_ctlr *m;
	time_t *t;
	off_t n;

	m = &midi_ctlr[ ctlr ];
	switch(cmd) {
	case MIDIACTIVE:
		if ( arg )
			m->flags |= ACTSENSE;
		else
			m->flags &= (~ACTSENSE);
		break;
	case MIDIRESET:
		midireset(ctlr,1);	/* default is UART mode */
		break;
	case MIDITHRU:
		midireset(ctlr,0);
		break;
	case MIDITIMERESET:
		m->clockoffset = lbolt;
		break;
	case MIDITIME:
		t = (time_t *)arg;
#define MILLIPERHZ (1000/HZ)
		if ( t )
			suword(t,(long)(MILLIPERHZ*(lbolt - m->clockoffset)));
		break;
	default:
		u.u_error = EINVAL;
		break;
	}
}

midi_wait_for_ready(ctlr)
{
	int tmout;

	for ( tmout=50000; tmout>0; tmout-- ) {
		if ( ready_for_data(ctlr) )
			break;
	}
	if ( tmout <= 0 ) {
		printf("/dev/midi timed out waiting for data ready\n");
		return 0;
	}
	return 1;
}

void
midiclose(dev)
{
	register struct midi_ctlr *m;
	register int n;
	register int ctlr = controller(dev);

	m = &midi_ctlr[ ctlr ];
	if ( ((m->flags)&ISOPEN) != 0 ) {	/* paranoia */
		m->flags &= (~ISOPEN);
		for ( n=0; n<MIDI_BUFS; n++ )
			brelse(m->in.buf[n]);
	}
	midireset(ctlr,0);
}

void
midiread(dev)
{
	register struct midi_ctlr *m;
	register int ctlr = controller(dev);
	register int c;

	m = &midi_ctlr[ ctlr ];
	while ( u.u_count ) {
		c = midiqget(&(m->in));
		if ( c < 0 )
			break; 
		/* active sensing may be ignored */
		if ( c == ACTIVE && ((m->flags&ACTSENSE)==0) )
			break;
		subyte(u.u_base,c);
		u.u_base++;
		u.u_count--;
	}
}

void
midiwrite(dev)
{
	register int ctlr = controller(dev);

	while ( u.u_count ) {
		if ( midi_wait_for_ready(ctlr) ) {
			midi_putdata(ctlr,fubyte(u.u_base));
			u.u_base++;
			u.u_count--;
		}
	}
}

void
midiintr(irq)
{
	register struct midi_ctlr *m;
	register int ctlr;
	register int c;

	ctlr = irq_to_ctlr[irq];
	if ( data_is_available(ctlr) ) {
		c = midi_getdata(ctlr);
		m = &midi_ctlr[ ctlr ];
		if ( (m->flags & ISOPEN) != 0 )
			midiqput(&(m->in),c);
	}
}
SHAR_EOF
if test 5377 -ne "`wc -c < 'Driver.c'`"
then
	echo shar: error transmitting "'Driver.c'" '(should have been 5377 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Files'" '(24 characters)'
if test -f 'Files'
then
	echo shar: will not over-write existing file "'Files'"
else
cat << \SHAR_EOF > 'Files'
/usr/include/sys/midi.h
SHAR_EOF
if test 24 -ne "`wc -c < 'Files'`"
then
	echo shar: error transmitting "'Files'" '(should have been 24 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Install'" '(3491 characters)'
if test -f 'Install'
then
	echo shar: will not over-write existing file "'Install'"
else
cat << \SHAR_EOF > 'Install'
#
# Install script for Midi device driver package
#

if [ "$1" = -f ]
then
	force=true
else
	force=false
fi

TMP=/tmp/midi.err
rm -f $TMP
ERROR1=" Errors have been written to the file $TMP."
ERROR2=" The Midi Driver software was not installed, and the System has not been modified."

if [ "`id | grep root`" = "" ]
then
	message "You have to be 'root' in order to install the driver! $ERROR2"
	exit 1
fi

echo "Installing Midi Device Driver Package..."

# BEGIN DYNAMIC CREATION OF Space.c, System, and Node
# based on controller info entered interactively

cat <<EOF > Space.c
/* THIS FILE WAS CREATED BY THE Install SCRIPT. */
#include "config.h"
#include "sys/types.h"
#include "sys/midi.h"

struct midi_ctlr midi_ctlr[MIDI_UNITS];
int midi_nctlr = MIDI_UNITS;
int irq_to_ctlr[NUMIRQ];	/* to be filled in by midi_init */

EOF

echo "\nHow many Midi controllers do you have? [1] --> \c"
read nctlr
if [ "$nctlr" = "" ]
then
	nctlr=1
fi
n=0
while [ "$n" -lt $nctlr ]
do
	cn=`expr $n + 1`
	echo "\nWhat is the IRQ # for controller number $cn ? [2] --> \c"
	read vect
	if [ "$vect" = "" ]
	then
		vect=2
	fi
	# On the 6386, vector 2 gets linked to 9
	if [ "$vect" = 2 ]
	then
		vect=9
	fi
	eval vect$n=$vect

	echo "Starting address (in hex) for controller number $cn ? [330] --> \c"
	read addr
	if [ "$addr" = "" ]
	then
		addr=330
	fi
	eval saddr$n=$addr

	echo "Ending address (in hex) for controller number $cn ? [331] --> \c"
	read addr
	if [ "$addr" = "" ]
	then
		addr=331
	fi
	eval eaddr$n=$addr
	n=`expr $n + 1`
done

n=0
> System
while [ "$n" -lt $nctlr ]
do
	eval echo "midi:Y:1:7:1:\$vect$n:\$saddr$n:\$eaddr$n:0:0" |
		sed "s/:/	/g" >> System
	n=`expr $n + 1`
done

echo "int ctlr_to_irq[] = {" >> Space.c
echo MIDI_0_VECT >> Space.c
n=1
while [ "$n" -lt $nctlr ]
do
	echo ",MIDI_${n}_VECT" >> Space.c
	n=`expr $n + 1`
done
echo "};" >> Space.c

echo "int ctlr_to_data_port[] = {" >> Space.c
echo MIDI_0_SIOA >> Space.c
n=1
while [ "$n" -lt $nctlr ]
do
	echo ",MIDI_${n}_SIOA" >> Space.c
	n=`expr $n + 1`
done
echo "};" >> Space.c

echo "int ctlr_to_status_port[] = {" >> Space.c
echo "MIDI_0_SIOA + 1" >> Space.c
n=1
while [ "$n" -lt $nctlr ]
do
	echo ", MIDI_${n}_SIOA + 1" >> Space.c
	n=`expr $n + 1`
done
echo "};" >> Space.c

echo "midi	midi	c	0" > Node
n=1
while [ "$n" -lt $nctlr ]
do
	echo "midi	midi`expr $n + 1`	c	$n" >> Node
	n=`expr $n + 1`
done

echo ""

# END OF DYNAMIC CREATION OF Space.c, System, and Node

/etc/conf/bin/idcheck -p midi 2>> $TMP
if [ $? != 0 ]
then
	if [ $force = true ]
	then
		/etc/conf/bin/idinstall -d midi
	else
		message -cu "The Midi Device Driver is already installed (or partially installed).
Do you wish to overwrite the existing device driver software?"
		if [ $? = 0 ]
		then
			/etc/conf/bin/idinstall -d midi
		else
			exit 1
		fi
	fi
fi

inc=/usr/include/sys/midi.h
cp midi.h $inc
chown bin $inc
chgrp bin $inc
chmod 444 $inc

if [ -f Driver.c ]
then
	echo "Compiling Driver.c ..."
	cc -c Driver.c 2>> $TMP
	if [ $? != 0 ]
	then
		message "There was an error while compiling Driver.c. $ERROR1 $ERROR2"
		exit 1
	fi
fi

/etc/conf/bin/idinstall -a -k midi 2>> $TMP
if [ $? != 0 ]
then
	message "There was an error during package installation. $ERROR1 $ERROR2"
	exit 1
fi

/etc/conf/bin/idbuild 2>> $TMP
if [ $? != 0 ]
then
	# if an error occurs here, remove the driver components
	/etc/conf/bin/idinstall -d midi
	rm -f $inc
	message "There was an error during Kernel reconfiguration. $ERROR1 $ERROR2"
	exit 1
fi

rm -f $TMP
exit 0
SHAR_EOF
if test 3491 -ne "`wc -c < 'Install'`"
then
	echo shar: error transmitting "'Install'" '(should have been 3491 characters)'
fi
chmod +x 'Install'
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(217 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
all : testread testwrite resetmidi

clean :
	rm -f testread testwrite resetmidi *.o

lint : lintlib.ln
	lint -nux lintlib.ln Driver.c | grep -v "struct/union.*never defined"

lintlib.ln : lintlib.c
	lint -c lintlib.c
SHAR_EOF
if test 217 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 217 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Master'" '(32 characters)'
if test -f 'Master'
then
	echo shar: will not over-write existing file "'Master'"
else
cat << \SHAR_EOF > 'Master'
midi	ocrwiI	icH	midi	0	0	1	1	-1
SHAR_EOF
if test 32 -ne "`wc -c < 'Master'`"
then
	echo shar: error transmitting "'Master'" '(should have been 32 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Name'" '(35 characters)'
if test -f 'Name'
then
	echo shar: will not over-write existing file "'Name'"
else
cat << \SHAR_EOF > 'Name'
386unix Midi Device Driver Package
SHAR_EOF
if test 35 -ne "`wc -c < 'Name'`"
then
	echo shar: error transmitting "'Name'" '(should have been 35 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Node'" '(29 characters)'
if test -f 'Node'
then
	echo shar: will not over-write existing file "'Node'"
else
cat << \SHAR_EOF > 'Node'
midi	midi	c	0
midi	midi2	c	1
SHAR_EOF
if test 29 -ne "`wc -c < 'Node'`"
then
	echo shar: error transmitting "'Node'" '(should have been 29 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(673 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
This is a minimal device driver that provides a /dev/midi that
talks to an MPU-compatible MIDI hardware interface.  It ONLY allows
use of the UART mode of the MPU hardware.  It was written for AT&T
System V Release 3.2 on a 6386, but may be portable to most System V
Release 3-based operating systems.   To install, invoke (as root):

     Install

This assumes the installable device driver structure of System V 3.2.
The hardware interrupt # and address will be requested interactively.
Included are testread.c and testwrite.c programs that can be used
to exercise the device.  See midi.7 for more info.

                                Tim Thompson = tjt@twitch.att.com
SHAR_EOF
if test 673 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 673 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Reboot'" '(23 characters)'
if test -f 'Reboot'
then
	echo shar: will not over-write existing file "'Reboot'"
else
cat << \SHAR_EOF > 'Reboot'
/etc/conf/bin/idreboot
SHAR_EOF
if test 23 -ne "`wc -c < 'Reboot'`"
then
	echo shar: error transmitting "'Reboot'" '(should have been 23 characters)'
fi
chmod +x 'Reboot'
fi # end of overwriting check
echo shar: extracting "'Remove'" '(419 characters)'
if test -f 'Remove'
then
	echo shar: will not over-write existing file "'Remove'"
else
cat << \SHAR_EOF > 'Remove'
#
# Remove script for Midi device driver
#

TMP=/tmp/midi.err
RERR="An error was encountered while removing the Midi Driver Package.
The file $TMP contains errors reported by the system."

echo "Removing Midi Device Driver Package..."

/etc/conf/bin/idinstall -d midi 2> $TMP
if [ $? != 0 ]
then
	message $RERR
	exit 1
fi

/etc/conf/bin/idbuild 2>> $TMP
if [ $? != 0 ]
then
	message $RERR
	exit 1
fi

rm -f $TMP
exit 0
SHAR_EOF
if test 419 -ne "`wc -c < 'Remove'`"
then
	echo shar: error transmitting "'Remove'" '(should have been 419 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Size'" '(18 characters)'
if test -f 'Size'
then
	echo shar: will not over-write existing file "'Size'"
else
cat << \SHAR_EOF > 'Size'
ROOT=1500
USR=500
SHAR_EOF
if test 18 -ne "`wc -c < 'Size'`"
then
	echo shar: error transmitting "'Size'" '(should have been 18 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Space.c'" '(420 characters)'
if test -f 'Space.c'
then
	echo shar: will not over-write existing file "'Space.c'"
else
cat << \SHAR_EOF > 'Space.c'
/* THIS FILE WAS CREATED BY THE Install SCRIPT. */
#include "config.h"
#include "sys/types.h"
#include "sys/midi.h"

struct midi_ctlr midi_ctlr[MIDI_UNITS];
int midi_nctlr = MIDI_UNITS;
int irq_to_ctlr[NUMIRQ];	/* to be filled in by midi_init */

int ctlr_to_irq[] = {
MIDI_0_VECT
,MIDI_1_VECT
};
int ctlr_to_data_port[] = {
MIDI_0_SIOA
,MIDI_1_SIOA
};
int ctlr_to_status_port[] = {
MIDI_0_SIOA + 1
, MIDI_1_SIOA + 1
};
SHAR_EOF
if test 420 -ne "`wc -c < 'Space.c'`"
then
	echo shar: error transmitting "'Space.c'" '(should have been 420 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'System'" '(54 characters)'
if test -f 'System'
then
	echo shar: will not over-write existing file "'System'"
else
cat << \SHAR_EOF > 'System'
midi	Y	1	7	1	9	330	331	0	0
midi	Y	1	7	1	7	300	301	0	0
SHAR_EOF
if test 54 -ne "`wc -c < 'System'`"
then
	echo shar: error transmitting "'System'" '(should have been 54 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'midi.7'" '(1025 characters)'
if test -f 'midi.7'
then
	echo shar: will not over-write existing file "'midi.7'"
else
cat << \SHAR_EOF > 'midi.7'
.TH MIDI 7
.SH SYNOPSIS
/dev/midi
.SH DESCRIPTION
/dev/midi controls a MIDI interface.
Data read from and written to /dev/midi is pure MIDI data.
Reading is always non-blocking, returning immediately if
no input is available.
A static number of system buffers is allocated for MIDI input when
/dev/midi is first opened, forming a large circular buffer in which new MIDI
input overwrites the oldest MIDI input (which may still be unread).
Ioctl commands are:
.P
ioctl(fd,MIDIRESET)
.IP
Reset the interface, flushing all pending MIDI input and output.
The MIDI clock time is reset to 0.
.P
ioctl(fd,MIDITHRU)
.IP
Turn ``thru'' mode
on.  This is a mode in which MIDI input is routed directly to
MIDI output, and no MIDI input can be read from /dev/midi until
a MIDIRESET is done.
.P
ioctl(fd,MIDITIMERESET)
.IP
Reset the MIDI clock time to 0.
.P
ioctl(fd,MIDITIME,arg)
.IP
Get the MIDI clock time (relative to the last time a MIDITIMERESET
was done) in milliseconds.
arg is a pointer to a long, into which the value is written.
SHAR_EOF
if test 1025 -ne "`wc -c < 'midi.7'`"
then
	echo shar: error transmitting "'midi.7'" '(should have been 1025 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'midi.h'" '(873 characters)'
if test -f 'midi.h'
then
	echo shar: will not over-write existing file "'midi.h'"
else
cat << \SHAR_EOF > 'midi.h'
/* MIDI_BUFS is the number of buffers to allocate for MIDI I/O queues. */
/* All of the buffers get allocated when /dev/midi is first */
/* opened, and get freed when /dev/midi is finally closed. */
#define MIDI_BUFS 5

#define NUMIRQ 16

#define MIDIC		('M'<<8)
#define MIDIRESET	(MIDIC|01)
#define MIDITIME	(MIDIC|02)
#define MIDITIMERESET	(MIDIC|03)
#define MIDIACTIVE	(MIDIC|04)
#define MIDITHRU	(MIDIC|05)

/* bits for midi_ctlr.flags */
#define ISOPEN		01
/* active sensing is passed on to the reader */
#define ACTSENSE	02

struct midi_queue {
	struct buf *	buf[MIDI_BUFS];
	off_t		low;
	off_t		high;
};

struct midi_ctlr {
	int			flags;
	time_t			clockoffset;
	struct midi_queue	in;
};

extern struct midi_ctlr midi_ctlr[];
extern int midi_nctlr;
extern int irq_to_ctlr[];
extern int ctlr_to_irq[];
extern int ctlr_to_data_port[];
extern int ctlr_to_status_port[];
SHAR_EOF
if test 873 -ne "`wc -c < 'midi.h'`"
then
	echo shar: error transmitting "'midi.h'" '(should have been 873 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'resetmidi.c'" '(273 characters)'
if test -f 'resetmidi.c'
then
	echo shar: will not over-write existing file "'resetmidi.c'"
else
cat << \SHAR_EOF > 'resetmidi.c'
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/midi.h>
#include <sys/signal.h>

main(argc,argv)
int argc;
char **argv;
{
	int fd;

	if ( argc > 1 )
		fd = open(argv[1],O_RDONLY );
	else
		fd = open("/dev/midi",O_RDONLY );
	ioctl(fd,MIDIRESET,0);
	close(fd);
}
SHAR_EOF
if test 273 -ne "`wc -c < 'resetmidi.c'`"
then
	echo shar: error transmitting "'resetmidi.c'" '(should have been 273 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'testread.c'" '(618 characters)'
if test -f 'testread.c'
then
	echo shar: will not over-write existing file "'testread.c'"
else
cat << \SHAR_EOF > 'testread.c'
/*
 * A test program for reading from /dev/midi.
 * Invoke it, and play something on the MIDI input keyboard.
 * Interrupt to terminate.
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/midi.h>

main(argc,argv)
int argc;
char **argv;
{
	int n, k;
	unsigned char buff[100];
	long t;
	int fd;

	if ( argc > 1 )
		fd = open(argv[1],O_RDONLY );
	else
		fd = open("/dev/midi",O_RDONLY );
	ioctl(fd,MIDIRESET,0);
	while ( 1 ) {
		if ( (n=read(fd,buff,sizeof(buff))) > 0 ) {
			ioctl(fd,MIDITIME,&t);
			printf("Time=%ld  ",t);
			for ( k=0; k<n; k++ )
				printf("  0x%x",buff[k]);
			printf("\n");
		}
	}
}
SHAR_EOF
if test 618 -ne "`wc -c < 'testread.c'`"
then
	echo shar: error transmitting "'testread.c'" '(should have been 618 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'testwrite.c'" '(873 characters)'
if test -f 'testwrite.c'
then
	echo shar: will not over-write existing file "'testwrite.c'"
else
cat << \SHAR_EOF > 'testwrite.c'
/*
 * A test program for writing to /dev/midi.
 *
 * Usage: testwrite {file}
 * 
 * The contents of the file will be used to control the pitches of
 * notes written to /dev/midi.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/midi.h>

main(argc,argv)
int argc;
char **argv;
{
	int n, k, c;
	unsigned char buff[100];
	long t;
	int fd;
	FILE *fin;
	long tm, nexttm;

	if ( argc > 2 ) {
		fd = open(argv[1],O_WRONLY );
		argc--;
		argv++;
	}
	else
		fd = open("/dev/midi",O_WRONLY );

	if ( argc > 1 )
		fin = fopen(argv[1],"r");
	else
		fin = stdin;
	ioctl(fd,MIDIRESET,0);
	ioctl(fd,MIDITIME,&tm);
	while ( (c=getc(fin)) != EOF ) {
		buff[0] = 0x90;
		buff[1] =  c % 128;
		buff[2] = 0x40;
		write(fd,buff,3);
		nexttm = tm + 100;
		while ( tm < nexttm )
			ioctl(fd,MIDITIME,&tm);
		buff[2] = 0x00;
		write(fd,buff,3);
	}
	close(fd);
}
SHAR_EOF
if test 873 -ne "`wc -c < 'testwrite.c'`"
then
	echo shar: error transmitting "'testwrite.c'" '(should have been 873 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'devmidi'"
cd ..
#	End of shell archive
exit 0

bender@oobleck.Central.Sun.COM (Michael Bender) (10/04/89)

Does anyone know of any UNIX-based MIDI software (specifically
for a Sun)?  Preferably PD?  I'm looking for a sequencer/patch
editor-librarian/sample editor, whatever's out there.

thanks,
mike bender
------------------------------------------------------------------------
michael bender - bender@sun                (can't think of a witty thing
 415 336-6353 (w)  415 941-3864 (h)         to put here yet)
------------------------------------------------------------------------

rlw@ttardis.UUCP (Ron Wilson) (10/04/89)

In article <4401@cbnewsh.ATT.COM>, tjt@cbnewsh.ATT.COM (timothy.j.thompson) writes:
>Enclosed is a minimal device driver that provides a /dev/midi that
>talks to an MPU-compatible MIDI hardware interface.  It *only* allows
>use of the UART mode of the MPU hardware, and the timing resolution of
>the clock it provides is (I think) 10 milliseconds.  It was written
>for AT&T System V Release 3.2 on a 6386, but may be portable to most
>SVR3-based operating systems, perhaps even SVR2.  See the README
>and midi.7 files for more info.  The right way to do something like
>this is to use streams.  This is a quick and dirty (but also quite
>usable) hack.
>                   Tim Thompson = tjt@twitch.att.com | att!twitch!tjt
[shell archive deleted]

Any chance of a psuedo driver that would use the standard tty driver
in external baud rate mode?

(Please cross post to rec.music - thanks)