home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume43
/
tclmidi
/
part03
< prev
next >
Wrap
Internet Message Format
|
1994-07-21
|
62KB
From: durian@boogie.com (Mike Durian)
Newsgroups: comp.sources.misc
Subject: v43i111: tclmidi - A language for manipulating MIDI files, v2.0, Part03/14
Date: 21 Jul 1994 19:26:14 -0500
Organization: Sterling Software
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <30n3n6$723@sparky.sterling.com>
X-Md4-Signature: 5bd81fb02b7ba888918fdfd2db8e01b7
Submitted-by: durian@boogie.com (Mike Durian)
Posting-number: Volume 43, Issue 111
Archive-name: tclmidi/part03
Environment: POSIX, (BSDI, NetBSD, LINUX, SVR4 for optional driver), C++, TCL
Supersedes: tclm: Volume 37, Issue 43-47
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: tclmidi-2.0/drivers/LINUX/Makefile
# tclmidi-2.0/drivers/SVR4/midi.c tclmidi-2.0/rb/rb.c
# Wrapped by kent@sparky on Thu Jul 21 19:05:13 1994
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 3 (of 14)."'
if test -f 'tclmidi-2.0/drivers/LINUX/Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tclmidi-2.0/drivers/LINUX/Makefile'\"
else
echo shar: Extracting \"'tclmidi-2.0/drivers/LINUX/Makefile'\" \(301 characters\)
sed "s/^X//" >'tclmidi-2.0/drivers/LINUX/Makefile' <<'END_OF_FILE'
XEXTRAFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
XCFLAGS = -DLOADABLE -D__KERNEL__ -DLINUX $(EXTRAFLAGS)
X
Xmidimodule.o: release.h midi.o midiconf.o quad.o
X ld -r -o midimodule.o midi.o midiconf.o quad.o
X
Xrelease.h:
X @echo char kernel_version[] = \"`uname -r`\"\; > release.h
END_OF_FILE
if test 301 -ne `wc -c <'tclmidi-2.0/drivers/LINUX/Makefile'`; then
echo shar: \"'tclmidi-2.0/drivers/LINUX/Makefile'\" unpacked with wrong size!
fi
# end of 'tclmidi-2.0/drivers/LINUX/Makefile'
fi
if test -f 'tclmidi-2.0/drivers/SVR4/midi.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tclmidi-2.0/drivers/SVR4/midi.c'\"
else
echo shar: Extracting \"'tclmidi-2.0/drivers/SVR4/midi.c'\" \(42554 characters\)
sed "s/^X//" >'tclmidi-2.0/drivers/SVR4/midi.c' <<'END_OF_FILE'
X/*-
X * Copyright (c) 1993, 1994 Michael B. Durian. All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X * notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X * notice, this list of conditions and the following disclaimer in the
X * documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X * must display the following acknowledgement:
X * This product includes software developed by Michael B. Durian.
X * 4. The name of the the Author may be used to endorse or promote
X * products derived from this software without specific prior written
X * permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#define INKERNEL 1
X#define _KERNEL 1
X
X#include <sys/sysmacros.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/dir.h>
X#include <sys/signal.h>
X#include <sys/user.h>
X#include <sys/systm.h>
X#include <sys/errno.h>
X#include <sys/open.h>
X#include <sys/uio.h>
X#include <sys/cred.h>
X#include <sys/ddi.h>
X#include <sys/poll.h>
X#include <sys/kmem.h>
X#include <sys/filio.h>
X#include <sys/termios.h>
X
X#include "midi.h"
X
Xextern struct midi_softc midi_sc[];
Xextern int midi_addrs[];
Xextern int midi_intrs[];
Xextern int NumMidi;
X
X#if defined(__STDC__) || defined(__cplusplus)
X#define __P(protos) protos
X#else
X#define __P(protos) ()
X#endif
X
X/* I've been burned too many times by different byte ordering */
X#define OUTB(x, y) outb((x), (y))
X#define INB(x) inb((x))
X
Xvoid midiinit __P(());
Xint midiopen __P((dev_t *dev, int flag, int otyp, cred_t *cred_p));
Xint midiclose __P((dev_t dev, int flag, int otyp, cred_t *cred_p));
Xint midiread __P((dev_t dev, uio_t *uio_p, cred_t *cred_p));
Xint midiwrite __P((dev_t dev, uio_t *uio_p, cred_t *cred_p));
Xint midiioctl __P((dev_t dev, int cmd, int arg, int mode, cred_t *cred_p,
X int *rval_p));
Xint midipoll __P((dev_t dev, int /* short */ events, int anyyet,
X short *reventsp, struct pollhead **phpp));
Xint midiintr __P((int ivec));
X
Xstatic void midi_copy_event __P((struct event *, struct event *));
Xstatic void midi_initq __P((struct event_queue *));
Xstatic int midi_deq __P((struct event_queue *, struct event **));
Xstatic int midi_peekq __P((struct event_queue *, struct event **));
Xstatic int midi_enq __P((struct event_queue *, struct event *));
Xstatic int midi_reset __P((struct midi_softc *));
Xstatic int midi_wait_rdy_rcv __P((struct midi_softc *softc));
Xstatic int midi_send_command __P((struct midi_softc *softc,
X /* u_char */ int comm));
Xstatic int midi_uart __P((struct midi_softc *));
Xstatic int midi_event2smf __P((struct midi_softc *, struct event *,
X struct stynamic *));
Xstatic int midi_next_byte __P((struct midi_softc *, struct uio *));
Xstatic int midi_uio2event __P((struct midi_softc *, struct uio *,
X struct event *));
Xstatic int midi_fix2var __P((u_long, u_char *));
Xstatic int midi_var2fix __P((u_char *, u_long *));
Xstatic u_long midi_smf2kernel_tick __P((struct midi_softc *, long));
Xstatic u_long midi_kernel2smf_tick __P((struct midi_softc *, long, long));
Xstatic void midi_timeout __P((caddr_t arg));
Xstatic void midi_add_complete_event __P((struct midi_softc *));
Xstatic void midi_schedule_timeout __P((struct midi_softc *));
Xstatic void midi_write_event __P((struct midi_softc *, struct event *));
Xstatic void midi_reset_devices __P((struct midi_softc *));
Xstatic void stynamic_add_byte __P((struct stynamic *, int /* u_char */));
Xstatic void stynamic_add_bytes __P((struct stynamic *, u_char *, int));
Xstatic u_char stynamic_get_byte __P((struct stynamic *, int));
Xstatic void stynamic_copy __P((struct stynamic *, void *, int));
Xstatic void stynamic_copy_from __P((struct stynamic *, int, void *, int));
Xstatic void stynamic_append __P((struct stynamic *, struct stynamic *));
Xstatic void stynamic_release __P((struct stynamic *));
Xstatic void stynamic_shift __P((struct stynamic *, int));
Xstatic void stynamic_init __P((struct stynamic *));
Xstatic void stynamic_print __P((struct stynamic *));
Xstatic int midi_killable __P((proc_t *owner, int pid));
X
Xvoid
Xmidiinit()
X{
X struct midi_softc *softc;
X int i;
X
X for (i = 0; i < NumMidi; i++) {
X softc = &midi_sc[i];
X softc->addr = midi_addrs[i];
X softc->intr = midi_intrs[i];
X softc->status = MIDI_RD_BLOCK;
X if (!midi_reset(softc))
X if (!midi_reset(softc)) {
X printf("Couldn't reset MPU401\n");
X softc->status |= MIDI_UNAVAILABLE;
X continue;
X }
X if (!midi_uart(softc)) {
X printf("Couldn't put MPU401 into UART mode!\n");
X softc->status |= MIDI_UNAVAILABLE;
X continue;
X }
X
X /* allocate memory for event queues */
X if ((softc->rqueue = kmem_alloc(sizeof(struct event_queue),
X KM_NOSLEEP)) == NULL) {
X printf("No memory for rqueue\n");
X softc->status |= MIDI_UNAVAILABLE;
X continue;
X }
X if ((softc->wqueue = kmem_alloc(sizeof(struct event_queue),
X KM_NOSLEEP)) == NULL) {
X printf("No memory for wqueue\n");
X softc->status |= MIDI_UNAVAILABLE;
X kmem_free(softc->rqueue, sizeof(struct event_queue));
X }
X /* zero read/write queue to clear stynamic structures */
X bzero(softc->rqueue, sizeof(struct event_queue));
X bzero(softc->wqueue, sizeof(struct event_queue));
X stynamic_init(&softc->rpartial);
X stynamic_init(&softc->wpartial);
X softc->wpartialpos = 0;
X }
X}
X
Xint
Xmidiopen(dev, flag, otyp, cred_p)
X dev_t *dev;
X int flag, otyp;
X cred_t *cred_p;
X{
X register struct midi_softc *softc;
X register int unit;
X
X unit = minor(*dev);
X if (unit >= NumMidi)
X return (ENXIO);
X softc = &midi_sc[unit];
X if (softc->status & MIDI_UNAVAILABLE)
X return (EIO);
X
X if (softc->status & MIDI_OPEN)
X return (EBUSY);
X else
X softc->status = MIDI_OPEN;
X
X /*
X * reads will block until something appears
X */
X softc->status |= MIDI_RD_BLOCK;
X
X /* initialize the queues */
X midi_initq(softc->rqueue);
X midi_initq(softc->wqueue);
X
X softc->partial_event.event.len = 0;
X softc->partial_event.event.datad = NULL;
X
X /* make sure we are in UART mode */
X if (!midi_fullreset(softc)) {
X printf("Couldn't put MPU401 into UART mode!\n");
X softc->status |= MIDI_UNAVAILABLE;
X kmem_free(softc->rqueue, sizeof(struct event_queue));
X kmem_free(softc->wqueue, sizeof(struct event_queue));
X return (EIO);
X }
X
X softc->pgid = u.u_procp->p_pid;
X softc->owner = u.u_procp;
X
X /* are we going to read, write or both? */
X if (flag & FREAD)
X softc->status |= MIDI_READING;
X else
X softc->status &= ~MIDI_READING;
X if (flag & FWRITE)
X softc->status |= MIDI_WRITING;
X else
X softc->status &= ~MIDI_WRITING;
X if (flag & FNONBLOCK)
X softc->status |= MIDI_NONBLOCK;
X else
X softc->status &= ~MIDI_NONBLOCK;
X
X return (0);
X}
X
Xint
Xmidiclose(dev, flag, otyp, cred_p)
X dev_t dev;
X int flag, otyp;
X cred_t *cred_p;
X{
X register struct midi_softc *softc;
X register int error, unit;
X
X unit = minor(dev);
X softc = &midi_sc[unit];
X
X /*
X * we're not going to finish closing until everything has
X * been played.
X */
X error = 0;
X if (softc->status & MIDI_WRITING) {
X /* same as MFLUSHQ ioctl */
X if (softc->wqueue->count != 0) {
X softc->status |= MIDI_FLUSH_SLEEP;
X do {
X if (error = sleep((caddr_t)&softc->status,
X PWAIT | PCATCH))
X softc->status &= ~MIDI_FLUSH_SLEEP;
X } while (softc->status & MIDI_FLUSH_SLEEP);
X }
X }
X
X /* turn off any notes that might be stuck on */
X midi_reset_devices(softc);
X midi_fullreset(softc);
X
X softc->status &= ~MIDI_OPEN;
X return (error);
X}
X
Xint
Xmidiread(dev, uio, cred_p)
X dev_t dev;
X uio_t *uio;
X cred_t *cred_p;
X{
X struct event *event;
X register struct midi_softc *softc;
X int error, in, num_to_move, unit;
X
X unit = minor(dev);
X softc = &midi_sc[unit];
X
X if (softc->rqueue->count == 0 && softc->rpartial.len == 0) {
X if (softc->status & MIDI_NONBLOCK)
X return (EWOULDBLOCK);
X else {
X softc->status |= MIDI_RD_SLEEP;
X do {
X if (error = sleep((caddr_t)softc->rqueue,
X PWAIT | PCATCH))
X return (error);
X } while (softc->status & MIDI_RD_SLEEP);
X /* XXX maybe check for abort here */
X }
X }
X while (uio->uio_resid) {
X /*
X * dequeue an event if partial is empty
X */
X if (softc->rpartial.len == 0) {
X if (!midi_deq(softc->rqueue, &event)) {
X softc->status |= MIDI_RD_BLOCK;
X return (0);
X }
X midi_event2smf(softc, event, &softc->rpartial);
X styanmic_release(&event->data);
X }
X /* read out as much of rpartial as possible */
X num_to_move = MIN(softc->rpartial.len, uio->uio_resid);
X if (softc->rpartial.len <= STYNAMIC_SIZE) {
X if (uiomove(softc->rpartial.datas, num_to_move,
X UIO_READ, uio) == -1)
X return (-1);
X } else {
X if (uiomove(softc->rpartial.datad, num_to_move,
X UIO_READ, uio) == -1)
X return (-1);
X }
X stynamic_shift(&softc->rpartial, num_to_move);
X }
X return (0);
X}
X
Xint
Xmidiwrite(dev, uio, cred_p)
X dev_t dev;
X uio_t *uio;
X cred_t *cred_p;
X{
X register struct midi_softc *softc;
X struct event event;
X int convert, error, unit, iovec, empty_queue;
X
X unit = minor(dev);
X softc = &midi_sc[unit];
X
X if (softc->wqueue->count == 0)
X empty_queue = 1;
X else
X empty_queue = 0;
X
X /* check to see if we'll block */
X if (softc->status & MIDI_WR_BLOCK) {
X if (softc->status & MIDI_NONBLOCK)
X return (EWOULDBLOCK);
X else {
X softc->status |= MIDI_WR_SLEEP;
X do {
X if (error = sleep((caddr_t)softc->wqueue,
X PWAIT | PCATCH))
X return (error);
X } while (softc->status & MIDI_WR_SLEEP);
X }
X }
X /* if returns from sleep and should abort because of DRAIN */
X if (softc->status & MIDI_WR_ABORT) {
X softc->status &= ~MIDI_WR_ABORT;
X return (0);
X }
X
X stynamic_init(&event.data);
X while (uio->uio_resid) {
X /* block if queue is full */
X if (softc->wqueue->count == MIDI_Q_SIZE) {
X softc->status |= MIDI_WR_BLOCK;
X if (empty_queue) {
X midi_schedule_timeout(softc);
X empty_queue = 0;
X }
X if (softc->status & MIDI_NONBLOCK)
X return (0);
X else {
X softc->status |= MIDI_WR_SLEEP;
X do {
X if (error = sleep(softc->wqueue,
X PWAIT | PCATCH))
X return (error);
X } while (softc->status & MIDI_WR_SLEEP);
X }
X }
X
X /*
X * 1) get a complete event off queue
X * 2) convert it from SMF to board format
X * 3) deal with it
X */
X convert = midi_uio2event(softc, uio, &event);
X switch (convert) {
X case 0:
X break;
X case -1:
X /* not a complete event - we'll get it next time */
X if (empty_queue)
X midi_schedule_timeout(softc);
X return (0);
X case -2:
X /* it was a noop event */
X break;
X default:
X return (convert);
X }
X if (convert == -2)
X continue;
X
X if (midi_enq(softc->wqueue, &event) == -1)
X return (EIO);
X stynamic_release(&event.data);
X /* set flag so next time we cross LOW water we will SIGIO */
X if (softc->wqueue->count >= MIDI_LOW_WATER)
X softc->status |= MIDI_SENDIO;
X }
X
X if (empty_queue)
X midi_schedule_timeout(softc);
X
X return (0);
X}
X
X/*
X * XXXINTR
X * I don't know what ivec is. I'm really hoping it is something
X * useful like the unit number.
X * If it is the interrupt number, then we can loop through all the
X * midi_sc comparing ivec against softc->intr until we find the right
X * one. No biggie, I just don't know which way it works.
X * For for I'll assume by default that it is the interrupt number.
X */
Xint
Xmidiintr(ivec)
X int ivec;
X{
X register struct midi_softc *softc;
X register u_char code;
X register struct partial_event *pe;
X
X#if 1
X int i;
X
X for (i = 0; i < NumMidi && midi_sc[i].intr != ivec; i++);
X if (i == NumMidi) {
X printf("midi: ivec(%d) is not a valid MPU401 intr number\n");
X return;
X }
X softc = &midi_sc[i];
X#else
X softc = &midi_sc[ivec];
X#endif
X
X code = INB(softc->addr + MIDI_DATA);
X if (code == 0xfe && (softc->status & MIDI_NEED_ACK)) {
X softc->status &= ~MIDI_NEED_ACK;
X return (1);
X }
X /* throw away data if no one has the device open */
X if (!(softc->status & MIDI_READING))
X return (1);
X
X /* pass input data to out port if necessary */
X if (softc->status & MIDI_THRU) {
X if (!midi_wait_rdy_rcv(softc))
X printf("Couldn't pass data thru\n");
X else
X OUTB(softc->addr + MIDI_DATA, code);
X }
X pe = &softc->partial_event;
X
X /* check for realtime events */
X if ((code & 0xf8) == 0xf8) {
X switch (code) {
X case 0xfa: /* start */
X /* reset prev_incoming */
X softc->prev_incoming = lbolt;
X break;
X case 0xff: /* reset */
X /*
X * I don't really want to do a full reset
X * I'll just clear any event in progress
X */
X stynamic_release(&pe->event);
X pe->state = START;
X break;
X case 0xf8: /* timing clock */
X case 0xf9: /* undefined */
X case 0xfb: /* continue */
X case 0xfc: /* stop */
X case 0xfd: /* undefined */
X case 0xfe: /* active sensing */
X break;
X }
X return (1);
X }
XINTR_SWITCH:
X switch (pe->state) {
X case START:
X /* record when the time when the event started */
X pe->time = lbolt;
X pe->tempo = softc->rtempo;
X /* start collecting the input */
X stynamic_release(&pe->event);
X /* decide what state is next */
X if (!(code & 0x80)) {
X stynamic_add_byte(&pe->event, code);
X switch (pe->rs) {
X case 0x80:
X case 0x90:
X case 0xa0:
X case 0xb0:
X case 0xe0:
X /*
X * code is the first data byte, but
X * we still need to get the second
X */
X pe->state = NEEDDATA2;
X break;
X case 0xc0:
X case 0xd0:
X /* code is the only data byte */
X pe->state = START;
X midi_add_complete_event(softc);
X break;
X default:
X break;
X }
X } else {
X switch (code & 0xf0) {
X case 0x80:
X case 0x90:
X case 0xa0:
X case 0xb0:
X case 0xe0:
X pe->rs = code & 0xf0;
X stynamic_add_byte(&pe->event, code);
X pe->state = NEEDDATA1;
X break;
X case 0xc0:
X case 0xd0:
X pe->rs = code & 0xf0;
X stynamic_add_byte(&pe->event, code);
X pe->state = NEEDDATA2;
X break;
X default:
X switch (code) {
X case 0xf0: /* sysex */
X stynamic_add_byte(&pe->event, code);
X pe->state = SYSEX;
X break;
X case 0xf1: /* undefined */
X case 0xf4: /* undefined */
X case 0xf5: /* undefined */
X case 0xf6: /* tune request */
X case 0xf7: /* EOX (terminator) */
X /* ignore these */
X break;
X case 0xf2: /* song position */
X pe->state = SYSTEM2;
X break;
X case 0xf3: /* song select */
X pe->state = SYSTEM1;
X break;
X }
X break;
X }
X }
X break;
X case NEEDDATA1:
X stynamic_add_byte(&pe->event, code);
X pe->state = NEEDDATA2;
X break;
X case NEEDDATA2:
X stynamic_add_byte(&pe->event, code);
X pe->state = START;
X midi_add_complete_event(softc);
X break;
X case SYSEX:
X /* any non-data byte ends sysex */
X if (!(code & 0x80))
X stynamic_add_byte(&pe->event, code);
X else {
X stynamic_add_byte(&pe->event, 0xf7);
X midi_add_complete_event(softc);
X pe->state = START;
X if (code != 0xf7)
X goto INTR_SWITCH;
X }
X break;
X case SYSTEM1:
X /* throw away one data byte of a system message */
X pe->state = START;
X break;
X case SYSTEM2:
X /* throw away two data bytes of a system message */
X pe->state = SYSTEM1;
X break;
X }
X return (1);
X}
X
Xint
Xmidiioctl(dev, cmd, arg, mode, cred_p, rval_p)
X dev_t dev;
X int cmd, arg, mode;
X cred_t *cred_p;
X int *rval_p;
X{
X struct event *event;
X struct midi_softc *softc;
X register int error, unit;
X int i, ret, val;
X
X unit = minor(dev);
X softc = &midi_sc[unit];
X
X switch (cmd) {
X case FIOASYNC:
X case MASYNC:
X /*
X * Linux doesn't properly process the FIOASYNC
X * ioctl entry point, thus we have two. For
X * compatibility purposes, I'm duplicating it
X * here too.
X */
X
X copyin((caddr_t)arg, (caddr_t)&val, sizeof(int));
X if (!val)
X softc->status &= ~MIDI_ASYNC;
X else {
X struct proc *p;
X
X softc->status |= MIDI_ASYNC;
X if (softc->wqueue->count < MIDI_LOW_WATER
X && softc->status & MIDI_WRITING) {
X if (softc->pgid < 0)
X signal(-softc->pgid, SIGIO);
X else if ((p = prfind(softc->pgid)) != 0)
X psignal(p, SIGIO);
X }
X }
X break;
X case TIOCSPGRP:
X /*
X * XXXSIGNAL we need to check to be sure we can kill the
X * the process we are being told to kill
X */
X copyin((caddr_t)arg, (caddr_t)&val, sizeof(int));
X if ((ret = midi_killable(softc->owner, val) != 0)) != 0)
X return (ret);
X softc->pgid = val;
X break;
X case TIOCGPGRP:
X copyout((caddr_t)&softc->pgid, (caddr_t)arg, sizeof(int));
X break;
X case MRESET:
X if (!midi_fullreset(softc))
X return (EIO);
X break;
X case MSDIVISION:
X copyin((caddr_t)arg, (caddr_t)&val, sizeof(int));
X /* must recalculate play remainder */
X softc->premainder = softc->premainder * val / softc->division;
X softc->division = val;
X break;
X case MGDIVISION:
X copyout((caddr_t)&softc->division, (caddr_t)arg, sizeof(int));
X break;
X case MDRAIN:
X /* dequeue all everything */
X while (midi_deq(softc->rqueue, &event))
X stynamic_release(&event->data);
X while (midi_deq(softc->wqueue, &event))
X stynamic_release(&event->data);
X /* remove any events already being timed */
X if (softc->timeout_id != -1)
X untimeout(softc->timeout_id);
X softc->status &= ~MIDI_WR_BLOCK;
X softc->status |= MIDI_RD_BLOCK;
X if (softc->status & MIDI_WR_SLEEP) {
X softc->status &= ~MIDI_WR_SLEEP;
X softc->status |= MIDI_WR_ABORT;
X wakeup((caddr_t)softc->wqueue);
X }
X midi_reset_devices(softc);
X break;
X case MFLUSH:
X if (softc->wqueue->count != 0) {
X softc->status |= MIDI_FLUSH_SLEEP;
X do {
X if (error = sleep((caddr_t)&softc->status,
X PWAIT | PCATCH))
X return (error);
X } while (softc->status & MIDI_FLUSH_SLEEP);
X }
X break;
X case MGPLAYQ:
X copyout((caddr_t)&softc->wqueue->count, (caddr_t)arg,
X sizeof(int));
X break;
X case MGRECQ:
X copyout((caddr_t)&softc->rqueue->count, (caddr_t)arg,
X sizeof(int));
X break;
X case MGQAVAIL:
X val = MIDI_Q_SIZE - softc->wqueue->count;
X copyout((caddr_t)&val, (caddr_t)arg, sizeof(int));
X break;
X case MTHRU:
X copyin((caddr_t)arg, (caddr_t)&val, sizeof(int));
X if (val)
X softc->status |= MIDI_THRU;
X else
X softc->status &= ~MIDI_THRU;
X break;
X case MRECONPLAY:
X copyin((caddr_t)arg, (caddr_t)&val, sizeof(int));
X if (val)
X softc->status |= MIDI_RECONPLAY;
X else
X softc->status &= ~MIDI_RECONPLAY;
X break;
X default:
X return (ENOTTY);
X }
X return (0);
X}
X
X/*
X * XXXPOLL
X * I don't know how this is supposed to work. The SVR4/386
X * DDI/DKI reference manual doesn't explain it well enough for me.
X */
Xint
Xmidipoll(dev, events, anyyet, reventsp, phpp)
X dev_t dev;
X short events;
X int anyyet;
X short *reventsp;
X struct pollhead **phpp;
X{
X register struct midi_softc *softc;
X int unit;
X
X unit = minor(dev);
X softc = &midi_sc[unit];
X
X *reventsp = 0;
X if (events & POLLIN && !(softc->status & MIDI_RD_BLOCK))
X *reventsp |= POLLIN;
X if (events & POLLOUT && !(softc->status & MIDI_WR_BLOCK))
X *reventsp |= POLLOUT;
X if (*reventsp == 0)
X if (!anyyet)
X *phpp = &softc->pollhead;
X return (0);
X}
X
Xint
Xmidi_fullreset(softc)
X struct midi_softc *softc;
X{
X u_char pitch;
X struct event *event;
X
X /* dequeue all everything */
X while (midi_deq(softc->rqueue, &event))
X stynamic_release(&event->data);
X while (midi_deq(softc->wqueue, &event))
X stynamic_release(&event->data);
X /* remove any events already being timed */
X if (softc->timeout_id != -1)
X untimeout(softc->timeout_id);
X softc->timeout_id = -1;
X /* mark start time */
X softc->prev_incoming = lbolt;
X /* reset fractional count */
X softc->premainder = 0;
X softc->rremainder = 0;
X /* initialize some variables */
X /* this is 120 bpm when a quarter note == 1 beat */
X softc->ptempo = 500000;
X softc->rtempo = 500000;
X softc->prev_rtempo = 500000;
X
X /* clear noteon */
X for (pitch = 0; pitch <= 0x7f; pitch++)
X softc->noteon[pitch] = 0;
X softc->noteonrs = 0;
X
X /* clear running play state */
X softc->writers = 0;
X
X /* reset partial event stuff */
X stynamic_release(&softc->partial_event.event);
X softc->partial_event.state = START;
X stynamic_release(&softc->rpartial);
X stynamic_release(&softc->wpartial);
X softc->wpartialpos = 0;
X
X /* defaults to 120 clocks per beat */
X softc->division = 120;
X /* reset and enter uart mode */
X return (midi_uart(softc));
X}
X
Xint
Xmidi_wait_rdy_rcv(softc)
X struct midi_softc *softc;
X{
X int flag;
X register int i;
X
X for (i = 0; i < MIDI_TRIES; i++) {
X flag = INB(softc->addr + MIDI_STATUS) & MIDI_RDY_RCV;
X if (flag == 0)
X break;
X }
X if (i == MIDI_TRIES)
X return (0);
X return(1);
X}
X
Xint
Xmidi_send_command(softc, comm)
X struct midi_softc *softc;
X u_char comm;
X{
X int flag;
X register int i, s;
X unsigned char ack;
X
X /* writing command and setting flag must be atomic */
X s = spltty();
X OUTB(softc->addr + MIDI_COMMAND, comm);
X softc->status |= MIDI_NEED_ACK;
X splx(s);
X
X /* time out after MIDI_TRIES times */
X for (i = 0; i < MIDI_TRIES; i++) {
X /* did we pick up the ack via midiintr? */
X if (!(softc->status & MIDI_NEED_ACK))
X break;
X /* can we read a data byte? */
X flag = INB(softc->addr + MIDI_STATUS) & MIDI_DATA_AVL;
X if (flag == 0)
X break;
X }
X if (i == MIDI_TRIES)
X return (0);
X
X if (softc->status & MIDI_NEED_ACK) {
X ack = INB(softc->addr + MIDI_DATA);
X if (ack != MIDI_ACK)
X return (0);
X }
X softc->status &= ~MIDI_NEED_ACK;
X return (1);
X}
X
Xint
Xmidi_reset(softc)
X struct midi_softc *softc;
X{
X
X if (!midi_wait_rdy_rcv(softc))
X return (0);
X
X if (!midi_send_command(softc, MIDI_RESET))
X return (0);
X
X return (1);
X}
X
Xint
Xmidi_uart(softc)
X struct midi_softc *softc;
X{
X
X /*
X * first reset. We can't issue the UART command when already
X * in UART mode.
X */
X (void)midi_reset(softc);
X
X if (!midi_wait_rdy_rcv(softc))
X return (0);
X
X if (!midi_send_command(softc, MIDI_UART))
X return (0);
X return (1);
X}
X
Xint
Xmidi_event2smf(softc, event, smf)
X struct midi_softc *softc;
X struct event *event;
X struct stynamic *smf;
X{
X long tempo, smf_ticks;
X int tmp_len;
X u_char tmp_buf[4];
X
X /* convert from kernel ticks to SMF ticks */
X smf_ticks = midi_kernel2smf_tick(softc, event->tempo, event->time);
X tmp_len = midi_fix2var(smf_ticks, tmp_buf);
X stynamic_add_bytes(smf, tmp_buf, tmp_len);
X
X switch (event->type) {
X case NORMAL:
X stynamic_append(smf, &event->data);
X break;
X case TEMPO:
X /* this case just won't occur */
X stynamic_copy(&event->data, (void *)&tempo, sizeof(tempo));
X stynamic_add_byte(smf, 0xff);
X stynamic_add_byte(smf, 0x51);
X stynamic_add_byte(smf, 0x03);
X stynamic_add_byte(smf, (tempo & 0xff0000) >> 16);
X stynamic_add_byte(smf, (tempo & 0xff00) >> 8);
X stynamic_add_byte(smf, tempo & 0xff00);
X break;
X case SYSX:
X stynamic_add_byte(smf, 0xf0);
X /* skip over the leading 0xf0 */
X stynamic_shift(&event->data, 1);
X tmp_len = midi_fix2var(event->data.len, tmp_buf);
X stynamic_add_bytes(smf, tmp_buf, tmp_len);
X styanmic_append(smf, &event->data);
X break;
X }
X return (1);
X}
X
Xint
Xmidi_next_byte(softc, uio)
X struct midi_softc *softc;
X struct uio *uio;
X{
X int byte;
X
X /* if we're not at the end of a partial event, read from it */
X if (softc->wpartialpos < softc->wpartial.len) {
X byte = stynamic_get_byte(&softc->wpartial,
X softc->wpartialpos++);
X return (byte);
X } else {
X /* read from uio and copy uio onto partial event */
X if ((byte = uwritec(uio)) == -1) {
X /*
X * reset partialpos so next time through
X * we'll read from the partial event if
X * it is non-zero in length
X */
X softc->wpartialpos = 0;
X return (-1);
X }
X stynamic_add_byte(&softc->wpartial, byte);
X softc->wpartialpos = softc->wpartial.len;
X return (byte);
X }
X}
X
Xint
Xmidi_uio2event(softc, uio, event)
X struct midi_softc *softc;
X struct uio *uio;
X struct event *event;
X{
X u_long smf_ticks, ulen;
X long tempo;
X int byte, error, extra_byte, i, len, num_data_bytes;
X int rs_change;
X u_char meta_type, tmp_buf[256];
X
X /* copy in timing portion */
X len = 0;
X do {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[len++] = byte;
X } while (byte & 0x80);
X
X /* compute time in smf ticks */
X midi_var2fix(tmp_buf, &smf_ticks);
X smf_ticks += softc->write_noop_time;
X softc->write_noop_time = 0;
X
X /* now convert from smf to kernel */
X event->time = midi_smf2kernel_tick(softc, smf_ticks);
X
X /* get first byte of event data */
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X switch (byte) {
X case 0xf0:
X /* basic sysex type */
X event->type = SYSX;
X len = 0;
X do {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[len++] = byte;
X } while (byte & 0x80);
X midi_var2fix(tmp_buf, &ulen);
X stynamic_add_byte(&event->data, 0xf0);
X for (; ulen > 0; ulen--) {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X stynamic_add_byte(&event->data, byte);
X }
X break;
X case 0xf7:
X /* continued sysex type */
X event->type = SYSX;
X len = 0;
X do {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[len++] = byte;
X } while (byte & 0x80);
X midi_var2fix(smf, &ulen);
X for (; ulen > 0; ulen--) {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X stynamic_add_byte(&event->data, byte);
X }
X if (error = uiomove(event->data, event->length, UIO_WRITE,
X uio))
X return (error);
X break;
X case 0xff:
X /* meta events */
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X meta_type = byte;
X /* get length of meta data */
X len = 0;
X do {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[len++] = byte;
X } while (byte & 0x80);
X midi_var2fix(tmp_buf, &ulen);
X /* read it in - meta events are not over 256 in size */
X for (i = 0; i < ulen; i++) {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X }
X switch (meta_type) {
X default:
X /*
X * we'll skip these events, but we need to
X * save the timing info
X */
X softc->write_noop_time = smf_ticks;
X stynamic_release(&softc->wpartial);
X softc->wpartialpos = 0;
X return (-2);
X case 0x51:
X /* tempo event */
X event->type = TEMPO;
X tempo = 0;
X for (i = 0; i < 3; i++) {
X tempo = tempo << 8;
X tempo |= tmp_buf[i];
X }
X stynamic_add_bytes(&event->data, (u_char *)&tempo,
X sizeof(tempo));
X /*
X * change ptempo now, rtempo will change when
X * the event's time comes up
X */
X softc->ptempo = tempo;
X break;
X }
X break;
X default:
X if ((byte & 0xf0) == 0x80) {
X u_char rs_chan, rs_type;
X
X /* check note off events separately */
X tmp_buf[0] = byte;
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[1] = byte;
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[2] = byte;
X len = 3;
X /*
X * check to see if we can collapse and use
X * running state
X */
X rs_type = softc->writers & 0xf0;
X rs_chan = softc->writers & 0x0f;
X /*
X * collapse to running state if time is 0
X * and the running state is the same
X * or the running state is note on for the
X * same channel and the note off velocity is
X * zero.
X */
X if (event->time == 0 && (softc->writers == tmp_buf[0]
X || (tmp_buf[2] == 0 && rs_type == 0x90
X && rs_chan == (tmp_buf[0] & 0x0f)))) {
X tmp_buf[0] = tmp_buf[1];
X tmp_buf[1] = tmp_buf[2];
X len = 2;
X } else {
X softc->writers = tmp_buf[0];
X }
X } else {
X extra_byte = 0;
X rs_change = 0;
X if ((byte & 0x80) && (byte != softc->writers)) {
X softc->writers = byte;
X rs_change = 1;
X }
X len = 0;
X if (event->time != 0 || rs_change) {
X /*
X * stick in a mode byte if time is non-zero
X * This is so we don't confuse hardware that
X * is turned on while we're playing
X * also add it if the running state changes
X */
X tmp_buf[0] = softc->writers;
X len = 1;
X }
X if (byte & 0x80)
X extra_byte = 1;
X else {
X tmp_buf[len] = byte;
X len++;
X }
X
X switch (softc->writers & 0xf0) {
X case 0x80:
X case 0x90:
X case 0xa0:
X case 0xb0:
X case 0xe0:
X num_data_bytes = 1;
X break;
X default:
X num_data_bytes = 0;
X }
X for (i = 0; i < num_data_bytes + extra_byte; i++) {
X if ((byte = midi_next_byte(softc, uio)) == -1) {
X stynamic_release(&event->data);
X return (-1);
X }
X tmp_buf[len++] = byte;
X }
X }
X event->type = NORMAL;
X stynamic_add_bytes(&event->data, tmp_buf, len);
X }
X stynamic_release(&softc->wpartial);
X softc->wpartialpos = 0;
X return (0);
X}
X
Xint
Xmidi_fix2var(fix, var)
X u_long fix;
X u_char *var;
X{
X int i;
X unsigned char buf[4], *bptr;
X
X buf[0] = buf[1] = buf[2] = buf[3] = 0;
X bptr = buf;
X *bptr++ = fix & 0x7f;
X while ((fix >>= 7) > 0) {
X *bptr |= 0x80;
X *bptr++ += (fix & 0x7f);
X }
X
X i = 0;
X do {
X *var++ = *--bptr;
X i++;
X } while (bptr != buf);
X
X return (i);
X}
X
Xint
Xmidi_var2fix(var, fix)
X u_char *var;
X u_long *fix;
X{
X int delta;
X
X *fix = 0;
X delta = 0;
X do {
X *fix = (*fix << 7) + (*var & 0x7f);
X delta++;
X } while (*var++ & 0x80);
X
X return (delta);
X}
X
Xu_long
Xmidi_smf2kernel_tick(softc, smf)
X struct midi_softc *softc;
X long smf;
X{
X long long denominator, numerator;
X u_long kernel;
X
X numerator = (long long)softc->ptempo * Hz * smf + softc->premainder;
X denominator = 1000000 * (long long)softc->division;
X kernel = numerator / denominator;
X softc->premainder = numerator % denominator;
X return (kernel);
X}
X
Xu_long
Xmidi_kernel2smf_tick(softc, tempo, kernel)
X struct midi_softc *softc;
X long tempo, kernel;
X{
X long long numerator, denominator;
X u_long smf;
X
X if (softc->prev_rtempo != tempo) {
X /*
X * also update the rremainder to reflect tempo
X * change
X */
X softc->rremainder = softc->rremainder * tempo
X / softc->prev_rtempo;
X softc->prev_rtempo = tempo;
X }
X numerator = (long long)softc->division * 1000000 * kernel
X + softc->rremainder;
X denominator = (long long)tempo * Hz;
X smf = numerator / denominator;
X softc->rremainder = numerator % denominator;
X return (smf);
X}
X
Xvoid
Xmidi_add_complete_event(softc)
X struct midi_softc *softc;
X{
X struct timeval t;
X struct timeval curr;
X struct event event;
X struct partial_event *pe;
X long ticks;
X
X stynamic_init(&event.data);
X pe = &softc->partial_event;
X /* calculate delta time */
X ticks = softc->prev_incoming - pe->time;
X if (ticks < 0) {
X ticks = 0;
X pe->time = softc->prev_incoming;
X }
X event.time = ticks;
X event.tempo = pe->tempo;
X switch (stynamic_get_byte(&pe->event, 0)) {
X case 0xf0:
X /* sysex */
X event.type = SYSX;
X break;
X default:
X event.type = NORMAL;
X break;
X }
X stynamic_append(&event.data, &softc->partial_event.event);
X /* enqueue new event */
X midi_enq(softc->rqueue, &event);
X stynamic_release(&event.data);
X /* readjust previous event time */
X softc->prev_incoming = pe->time;
X
X softc->status &= ~MIDI_RD_BLOCK;
X if (softc->status & MIDI_RD_SLEEP) {
X softc->status &= ~MIDI_RD_SLEEP;
X wakeup((caddr_t)softc->rqueue);
X }
X if (softc->status & MIDI_ASYNC) {
X struct proc *p;
X
X if (softc->pgid < 0)
X signal(-softc->pgid, SIGIO);
X else if ((p = prfind(softc->pgid)) != 0)
X psignal(p, SIGIO);
X }
X
X /* notify poll that there is data to be read */
X /*
X * XXXPOLL - do I only want to do this is a poll is in
X * progress and anyyet is 0? Then I'll need to set
X * a status flag, and how do I know when to unset it after
X * the poll times out (ala select).
X */
X pollwakeup(&softc->pollhead, POLLIN);
X
X return;
X}
X
Xvoid
Xmidi_schedule_timeout(softc)
X struct midi_softc *softc;
X{
X struct event *event;
X
X if (!midi_peekq(softc->wqueue, &event))
X return;
X softc->timeout_id = timeout(midi_timeout, (caddr_t)softc,
X event->time);
X
X /* clear record timer? */
X if (softc->status & MIDI_RECONPLAY) {
X softc->prev_incoming = lbolt;
X /* clear flag */
X softc->status &= ~MIDI_RECONPLAY;
X }
X}
X
Xvoid
Xmidi_timeout(arg)
X caddr_t arg;
X{
X struct event *event;
X struct midi_softc *softc = (struct midi_softc *)arg;
X int i;
X
X /* send first event since we know it is ready */
X midi_deq(softc->wqueue, &event);
X midi_write_event(softc, event);
X stynamic_release(&event->data);
X
X /* process all events that also occur at this time (event->time == 0) */
X for(;;) {
X if (!midi_peekq(softc->wqueue, &event))
X return;
X if (event->time != 0)
X break;
X midi_deq(softc->wqueue, NULL);
X midi_write_event(softc, event);
X stynamic_release(&event->data);
X }
X
X /* setup timeout for next event */
X midi_schedule_timeout(softc);
X}
X
Xvoid
Xmidi_write_event(softc, event)
X struct midi_softc *softc;
X struct event *event;
X{
X int i, j;
X u_char bytes[4], channel, command, *dataptr;
X
X switch (event->type) {
X case TEMPO:
X stynamic_copy(&event->data, &softc->rtempo,
X sizeof(softc->rtempo));
X break;
X case NORMAL:
X /*
X * fourth byte might not be valid, but who cares,
X * we're only reading and in the kernel. We'll
X * ignore it if it isn't.
X */
X stynamic_copy(&event->data, &bytes, 4);
X if (!(bytes[0] & 0x80))
X dataptr = &bytes[0];
X else {
X softc->noteonrs = bytes[0];
X dataptr = &bytes[1];
X }
X command = softc->noteonrs & 0xf0;
X channel = softc->noteonrs & 0x0f;
X if (command == 0x90) {
X /*
X * set of clear appropriate bit in noteon
X * array depending on velocity value
X */
X if (dataptr[1] != 0)
X softc->noteon[dataptr[0]] |= 1 << channel;
X else
X softc->noteon[dataptr[0]] &= ~(1 << channel);
X }
X if (command == 0x80)
X /* clear bit */
X softc->noteon[dataptr[0]] &= ~(1 << channel);
X /* FALLTHRU */
X default:
X for (i = 0; i < event->data.len; i++) {
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA,
X stynamic_get_byte(&event->data, i));
X }
X break;
X }
X if (softc->wqueue->count < MIDI_LOW_WATER) {
X softc->status &= ~MIDI_WR_BLOCK;
X if (softc->status & MIDI_WR_SLEEP) {
X softc->status &= ~MIDI_WR_SLEEP;
X wakeup((caddr_t)softc->wqueue);
X }
X if (softc->status & MIDI_ASYNC &&
X (softc->status & MIDI_SENDIO || softc->wqueue->count
X == 0)) {
X struct proc *p;
X
X if (softc->pgid < 0)
X signal(-softc->pgid, SIGIO);
X else if ((p = prfind(softc->pgid)) != 0)
X psignal(p, SIGIO);
X }
X softc->status &= ~MIDI_SENDIO;
X /* notify poll that writes will succeed */
X /*
X * XXXPOLL - do I only want to do this is a poll is in
X * progress and anyyet is 0? Then I'll need to set
X * a status flag, and how do I know when to unset it after
X * the poll times out (ala select).
X */
X pollwakeup(&softc->pollhead, POLLOUT);
X }
X if (softc->status & MIDI_FLUSH_SLEEP && softc->wqueue->count == 0) {
X softc->status &= ~MIDI_FLUSH_SLEEP;
X wakeup((caddr_t)&softc->status);
X }
X}
X
X
X/*
X * try to reset the midi devices as best we can
X */
Xvoid
Xmidi_reset_devices(softc)
X struct midi_softc *softc;
X{
X int i;
X u_char channel, pitch;
X
X /* manual note off calls - turn off any note that is on */
X for (pitch = 0; pitch <= 0x7f; pitch++) {
X for (channel = 0; channel <= 0x0f; channel++) {
X if ((softc->noteon[pitch] >> (int)channel) & 0x01) {
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, channel | 0x90);
X
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, pitch);
X
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X }
X }
X softc->noteon[pitch] = 0;
X }
X for (channel = 0; channel <= 0x0f; channel++) {
X /*
X * send paramter event for all notes off for redundancy
X * some older synths don't support this
X */
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, channel | 0xb0);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0x7b);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X
X /* modulation controller to zero */
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0x01);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X
X /* reset all controllers */
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0x79);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X
X /* lift sustain pedal */
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0x40);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X
X /* center pitch wheel */
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0xe0 | channel);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0);
X if (!midi_wait_rdy_rcv(softc))
X break;
X OUTB(softc->addr + MIDI_DATA, 0x40);
X }
X softc->noteonrs = 0;
X}
X
Xvoid
Xmidi_initq(eq)
X struct event_queue *eq;
X{
X
X eq->count = 0;
X eq->end = &eq->events[MIDI_Q_SIZE - 1];
X eq->head = eq->events;
X eq->tail = eq->events;
X /* zero events to clear stynamic stuctures */
X bzero(eq->events, MIDI_Q_SIZE * sizeof(struct event));
X}
X
Xvoid
Xmidi_copy_event(e1, e2)
X struct event *e1, *e2;
X{
X short i;
X
X e1->time = e2->time;
X e1->type = e2->type;
X e1->tempo = e2->tempo;
X stynamic_release(&e1->data);
X stynamic_append(&e1->data, &e2->data);
X}
X
Xint
Xmidi_deq(eq, event)
X struct event_queue *eq;
X struct event **event;
X{
X int s;
X
X s = spltty();
X if (eq->count == 0) {
X splx(s);
X return (0);
X }
X if (event == NULL)
X eq->head++;
X else
X *event = eq->head++;
X if (eq->head > eq->end)
X eq->head = eq->events;
X eq->count--;
X splx(s);
X return (1);
X}
X
Xint
Xmidi_peekq(eq, event)
X struct event_queue *eq;
X struct event **event;
X{
X int s;
X
X s = spltty();
X if (eq->count == 0) {
X splx(s);
X return (0);
X }
X *event = eq->head;
X splx(s);
X return (1);
X}
X
Xint
Xmidi_enq(eq, event)
X struct event_queue *eq;
X struct event *event;
X{
X int s;
X
X s = spltty();
X if (eq->count == MIDI_Q_SIZE) {
X splx(s);
X return (0);
X }
X midi_copy_event(eq->tail++, event);
X if (eq->tail > eq->end)
X eq->tail = eq->events;
X eq->count++;
X splx(s);
X return (1);
X}
X
Xvoid
Xstynamic_add_byte(sty, byte)
X struct stynamic *sty;
X u_char byte;
X{
X int s;
X u_char *new_ptr;
X
X s = spltty();
X if (sty->len < STYNAMIC_SIZE)
X sty->datas[sty->len++] = byte;
X else {
X if (sty->len < sty->allocated) {
X sty->datad[sty->len++] = byte;
X } else {
X new_ptr = kmem_alloc(sty->allocated + STYNAMIC_ALLOC,
X KM_NOSLEEP);
X if (new_ptr == NULL) {
X printf("midi: out of memory\n");
X return;
X }
X if (sty->allocated == 0)
X bcopy(sty->datas, new_ptr, sty->len);
X else {
X bcopy(sty->datad, new_ptr, sty->len);
X kmem_free(sty->datad, sty->allocated);
X }
X sty->datad = new_ptr;
X sty->datad[sty->len++] = byte;
X sty->allocated += STYNAMIC_ALLOC;
X }
X }
X splx(s);
X}
X
Xvoid
Xstynamic_add_bytes(sty, bytes, num)
X struct stynamic *sty;
X u_char *bytes;
X int num;
X{
X int s, size_inc;
X u_char *new_ptr;
X
X s = spltty();
X if (sty->len + num <= STYNAMIC_SIZE) {
X bcopy(bytes, &sty->datas[sty->len], num);
X sty->len += num;
X } else {
X if (sty->len + num <= sty->allocated) {
X bcopy(bytes, &sty->datad[sty->len], num);
X sty->len += num;
X } else {
X size_inc = (num / STYNAMIC_ALLOC + 1) * STYNAMIC_ALLOC;
X new_ptr = kmem_alloc(sty->allocated + size_inc,
X KM_NOSLEEP);
X if (sty->allocated == 0)
X bcopy(sty->datas, new_ptr, sty->len);
X else {
X bcopy(sty->datad, new_ptr, sty->len);
X kmem_free(sty->datad, sty->allocated);
X }
X sty->datad = new_ptr;
X bcopy(bytes, &sty->datad[sty->len], num);
X sty->allocated += size_inc;
X sty->len += num;
X }
X }
X splx(s);
X}
X
Xu_char
Xstynamic_get_byte(sty, index)
X struct stynamic *sty;
X int index;
X{
X int s;
X
X s = spltty();
X if (sty->len <= 4)
X return (sty->datas[index]);
X else
X return (sty->datad[index]);
X splx(s);
X}
X
Xvoid
Xstynamic_copy(sty, dest, len)
X struct stynamic *sty;
X void *dest;
X int len;
X{
X int s;
X
X s = spltty();
X if (sty->len <= 4)
X bcopy(sty->datas, dest, len);
X else
X bcopy(sty->datad, dest, len);
X splx(s);
X}
X
Xvoid
Xstynamic_append(dest, src)
X struct stynamic *dest;
X struct stynamic *src;
X{
X
X if (src->len <= 4)
X stynamic_add_bytes(dest, src->datas, src->len);
X else
X stynamic_add_bytes(dest, src->datad, src->len);
X}
X
Xvoid
Xstynamic_copy_from(sty, index, dest, len)
X struct stynamic *sty;
X int index, len;
X void *dest;
X{
X int s;
X
X s = spltty();
X if (sty->len <= 4)
X bcopy(&sty->datas[index], dest, len);
X else
X bcopy(&sty->datad[index], dest, len);
X splx(s);
X}
X
X
Xvoid
Xstynamic_release(sty)
X struct stynamic *sty;
X{
X int s;
X
X s = spltty();
X if (sty->len > STYNAMIC_SIZE)
X kmem_free(sty->datad, sty->allocated);
X sty->len = 0;
X sty->allocated = 0;
X sty->datad = NULL;
X bzero(sty->datas, STYNAMIC_SIZE);
X splx(s);
X}
X
Xvoid
Xstynamic_shift(sty, num)
X struct stynamic *sty;
X int num;
X{
X int rem, s;
X u_char *ptr;
X
X if (sty->len <= num) {
X stynamic_release(sty);
X return;
X }
X s = spltty();
X if (sty->len > STYNAMIC_SIZE)
X ptr = &sty->datad[num];
X else
X ptr = &sty->datas[num];
X rem = sty->len - num;
X if (rem > STYNAMIC_SIZE)
X bcopy(ptr, sty->datad, rem);
X else {
X bcopy(ptr, sty->datas, rem);
X if (sty->datad != NULL) {
X kmem_free(sty->datad, sty->allocated);
X sty->datad = NULL;
X sty->allocated = 0;
X }
X }
X splx(s);
X sty->len = rem;
X}
X
Xvoid
Xstynamic_init(sty)
X struct stynamic *sty;
X{
X int s;
X
X s = spltty();
X sty->len = 0;
X sty->allocated = 0;
X sty->datad = NULL;
X bzero(sty->datas, STYNAMIC_SIZE);
X splx(s);
X}
X
Xvoid
Xstynamic_print(sty)
X struct stynamic *sty;
X{
X
X printf("\t\tlen = %d\n", sty->len);
X printf("\t\tallocated = %d\n", sty->allocated);
X printf("\t\tdatad = 0x%x\n", sty->datad);
X}
X
X/*
X * XXXSIGNAL
X * I have no idea how to verify that a process is killable under
X * SVR4. We need to check both individual processes and process
X * groups. My drivers don't even cope with broadcast kills, so
X * don't worry about that one.
X * See the BSD and LINUX versions for ideas on how to verify this.
X */
Xint
Xmidi_killable(owner, pid)
X proc_t *owner;
X int pid;
X{
X
X if (pid == 0)
X return (0);
X if (pid == -1)
X return (EPERM);
X return (0);
X}
END_OF_FILE
if test 42554 -ne `wc -c <'tclmidi-2.0/drivers/SVR4/midi.c'`; then
echo shar: \"'tclmidi-2.0/drivers/SVR4/midi.c'\" unpacked with wrong size!
fi
# end of 'tclmidi-2.0/drivers/SVR4/midi.c'
fi
if test -f 'tclmidi-2.0/rb/rb.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tclmidi-2.0/rb/rb.c'\"
else
echo shar: Extracting \"'tclmidi-2.0/rb/rb.c'\" \(13684 characters\)
sed "s/^X//" >'tclmidi-2.0/rb/rb.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include "rb.h"
X#include "list.h"
X
X#define isred(n) (n->s.red)
X#define isblack(n) (!isred(n))
X#define isleft(n) (n->s.left)
X#define isright(n) (!isleft(n))
X#define isint(n) (n->s.internal)
X#define isext(n) (!isint(n))
X#define ishead(n) (n->s.head)
X#define isroot(n) (n->s.root)
X#define setred(n) n->s.red = 1
X#define setblack(n) n->s.red = 0
X#define setleft(n) n->s.left = 1
X#define setright(n) n->s.left = 0
X#define sethead(n) n->s.head = 1
X#define setroot(n) n->s.root = 1
X#define setint(n) n->s.internal = 1
X#define setext(n) n->s.internal = 0
X#define setnormal(n) { n->s.root = 0; n ->s.head = 0; }
X#define sibling(n) ((isleft(n)) ? n->p.parent->c.child.right \
X : n->p.parent->c.child.left)
X
X#define mk_new_ext(new, kkkey, vvval) {\
X new = (Rb_node) malloc(sizeof(struct rb_node));\
X new->v.val = vvval;\
X new->k.key = kkkey;\
X setext(new);\
X setblack(new);\
X setnormal(new);\
X}
X
Xvoid
Xmk_new_int(l, r, p, il)
X Rb_node l, r, p;
X int il;
X{
X Rb_node new;
X
X new = (Rb_node) malloc(sizeof(struct rb_node));
X setint(new);
X setred(new);
X setnormal(new);
X new->c.child.left = l;
X new->c.child.right = r;
X new->p.parent = p;
X new->k.lext = l;
X new->v.rext = r;
X l->p.parent = new;
X r->p.parent = new;
X setleft(l);
X setright(r);
X if (ishead(p)) {
X p->p.root = new;
X setroot(new);
X } else if (il) {
X setleft(new);
X p->c.child.left = new;
X } else {
X setright(new);
X p->c.child.right = new;
X }
X recolor(new);
X}
X
X
XRb_node
Xlprev(n)
X Rb_node n;
X{
X if (ishead(n))
X return (n);
X while (!isroot(n)) {
X if (isright(n))
X return (n->p.parent);
X n = n->p.parent;
X }
X return (n->p.parent);
X}
X
XRb_node
Xrprev(n)
X Rb_node n;
X{
X if (ishead(n))
X return (n);
X while (!isroot(n)) {
X if (isleft(n))
X return (n->p.parent);
X n = n->p.parent;
X }
X return (n->p.parent);
X}
X
XRb_node
Xmake_rb()
X{
X Rb_node head;
X
X if ((head = (Rb_node)malloc(sizeof(struct rb_node))) == NULL)
X return (NULL);
X head->c.list.flink = head;
X head->c.list.blink = head;
X head->p.root = head;
X head->k.key = "";
X head->v.val = NULL;
X sethead(head);
X return (head);
X}
X
XRb_node
Xrb_find_key_n(n, key, fnd)
X Rb_node n;
X char *key;
X int *fnd;
X{
X int cmp;
X
X *fnd = 0;
X if (!ishead(n)) {
X fprintf(stderr, "rb_find_key_n called on non-head 0x%x\n",
X (int)n);
X exit(1);
X }
X if (n->p.root == n)
X return (n);
X cmp = strcmp(key, n->c.list.blink->k.key);
X if (cmp == 0) {
X *fnd = 1;
X return (n->c.list.blink);
X }
X if (cmp > 0)
X return (n);
X else
X n = n->p.root;
X while (1) {
X if (isext(n))
X return (n);
X cmp = strcmp(key, n->k.lext->k.key);
X if (cmp == 0) {
X *fnd = 1;
X return (n->k.lext);
X }
X if (cmp < 0)
X n = n->c.child.left;
X else
X n = n->c.child.right;
X }
X}
X
XRb_node
Xrb_find_key(n, key)
X Rb_node n;
X char *key;
X{
X int fnd;
X
X return (rb_find_key_n(n, key, &fnd));
X}
X
XRb_node
Xrb_find_ikey_n(n, ikey, fnd)
X Rb_node n;
X int ikey;
X int *fnd;
X{
X *fnd = 0;
X if (!ishead(n)) {
X fprintf(stderr, "rb_find_ikey_n called on non-head 0x%x\n",
X (int)n);
X exit(1);
X }
X if (n->p.root == n)
X return (n);
X if (ikey == n->c.list.blink->k.ikey) {
X *fnd = 1;
X return (n->c.list.blink);
X }
X if (ikey > n->c.list.blink->k.ikey)
X return (n);
X else
X n = n->p.root;
X while (1) {
X if (isext(n))
X return (n);
X if (ikey == n->k.lext->k.ikey) {
X *fnd = 1;
X return (n->k.lext);
X }
X n = (ikey < n->k.lext->k.ikey) ? n->c.child.left :
X n->c.child.right;
X }
X}
X
XRb_node
Xrb_find_ukey_n(n, ukey, fnd)
X register Rb_node n;
X unsigned long ukey;
X int *fnd;
X{
X
X *fnd = 0;
X if (!ishead(n)) {
X fprintf(stderr, "rb_find_ukey_n called on non-head 0x%x\n",
X (int)n);
X exit(1);
X }
X if (n->p.root == n)
X return (n);
X if (ukey == n->c.list.blink->k.ukey) {
X *fnd = 1;
X return (n->c.list.blink);
X }
X if (ukey > n->c.list.blink->k.ukey)
X return (n);
X else
X n = n->p.root;
X while (1) {
X if (isext(n))
X return (n);
X if (ukey == n->k.lext->k.ukey) {
X *fnd = 1;
X return (n->k.lext);
X }
X n = (ukey < n->k.lext->k.ukey) ? n->c.child.left :
X n->c.child.right;
X }
X}
X
XRb_node
Xrb_find_ikey(n, ikey)
X Rb_node n;
X int ikey;
X{
X int fnd;
X
X return (rb_find_ikey_n(n, ikey, &fnd));
X}
X
XRb_node
Xrb_find_ukey(n, ukey)
X Rb_node n;
X unsigned long ukey;
X{
X int fnd;
X
X return (rb_find_ukey_n(n, ukey, &fnd));
X}
X
XRb_node
Xrb_find_gkey_n(n, key, fxn, fnd)
X Rb_node n;
X char *key;
X int (*fxn)();
X int *fnd;
X{
X int cmp;
X
X *fnd = 0;
X if (!ishead(n)) {
X fprintf(stderr, "rb_find_key_n called on non-head 0x%x\n",
X (int)n);
X exit(1);
X }
X if (n->p.root == n)
X return (n);
X cmp = (*fxn)(key, n->c.list.blink->k.key);
X if (cmp == 0) {
X *fnd = 1;
X return (n->c.list.blink);
X }
X if (cmp > 0)
X return (n);
X else
X n = n->p.root;
X while (1) {
X if (isext(n))
X return (n);
X cmp = (*fxn)(key, n->k.lext->k.key);
X if (cmp == 0) {
X *fnd = 1;
X return (n->k.lext);
X }
X if (cmp < 0)
X n = n->c.child.left;
X else
X n = n->c.child.right;
X }
X}
X
XRb_node
Xrb_find_gkey(n, key, fxn)
X Rb_node n;
X char *key;
X int (*fxn)();
X{
X int fnd;
X
X return (rb_find_gkey_n(n, key, fxn, &fnd));
X}
XRb_node
Xrb_insert_b(n, key, val)
X Rb_node n;
X char *key;
X char *val;
X{
X Rb_node newleft, newright, newnode, p;
X
X if (ishead(n)) {
X if (n->p.root == n) {
X /* Tree is empty */
X mk_new_ext(newnode, key, val);
X insert((List)newnode, (List)n);
X n->p.root = newnode;
X newnode->p.parent = n;
X setroot(newnode);
X return (newnode);
X } else {
X mk_new_ext(newright, key, val);
X insert((List)newright, (List)n);
X newleft = newright->c.list.blink;
X setnormal(newleft);
X mk_new_int(newleft, newright, newleft->p.parent, isleft(newleft));
X p = rprev(newright);
X if (!ishead(p))
X p->k.lext = newright;
X return (newright);
X }
X } else {
X mk_new_ext(newleft, key, val);
X insert((List)newleft, (List)n);
X setnormal(n);
X mk_new_int(newleft, n, n->p.parent, isleft(n));
X p = lprev(newleft);
X if (!ishead(p))
X p->v.rext = newleft;
X return (newleft);
X }
X}
X
Xvoid
Xrecolor(n)
X Rb_node n;
X{
X Rb_node p, gp, s;
X int done = 0;
X
X while (!done) {
X if (isroot(n)) {
X setblack(n);
X return;
X }
X p = n->p.parent;
X
X if (isblack(p))
X return;
X
X if (isroot(p)) {
X setblack(p);
X return;
X }
X gp = p->p.parent;
X s = sibling(p);
X if (isred(s)) {
X setblack(p);
X setred(gp);
X setblack(s);
X n = gp;
X } else {
X done = 1;
X }
X }
X /* p's sibling is black, p is red, gp is black */
X
X if ((isleft(n) == 0) == (isleft(p) == 0)) {
X single_rotate(gp, isleft(n));
X setblack(p);
X setred(gp);
X } else {
X single_rotate(p, isleft(n));
X single_rotate(gp, isleft(n));
X setblack(n);
X setred(gp);
X }
X}
X
Xvoid
Xsingle_rotate(y, l)
X Rb_node y;
X int l;
X{
X int rl, ir;
X Rb_node x, yp;
X
X /* quiet warning */
X rl = 0;
X ir = isroot(y);
X yp = y->p.parent;
X if (!ir) {
X rl = isleft(y);
X }
X if (l) {
X x = y->c.child.left;
X y->c.child.left = x->c.child.right;
X setleft(y->c.child.left);
X y->c.child.left->p.parent = y;
X x->c.child.right = y;
X setright(y);
X } else {
X x = y->c.child.right;
X y->c.child.right = x->c.child.left;
X setright(y->c.child.right);
X y->c.child.right->p.parent = y;
X x->c.child.left = y;
X setleft(y);
X }
X
X x->p.parent = yp;
X y->p.parent = x;
X if (ir) {
X yp->p.root = x;
X setnormal(y);
X setroot(x);
X } else {
X if (rl) {
X yp->c.child.left = x;
X setleft(x);
X } else {
X yp->c.child.right = x;
X setright(x);
X }
X }
X}
X
Xvoid
Xrb_delete_node(n)
X Rb_node n;
X{
X Rb_node s, p, gp;
X char ir;
X
X if (isint(n)) {
X fprintf(stderr, "Cannot delete an internal node: 0x%x\n",
X (int)n);
X exit(1);
X }
X if (ishead(n)) {
X fprintf(stderr, "Cannot delete the head of an rb_tree: 0x%x\n",
X (int)n);
X exit(1);
X }
X delete_item((List)n); /* Delete it from the list */
X p = n->p.parent; /* The only node */
X if (isroot(n)) {
X p->p.root = p;
X free(n);
X return;
X }
X s = sibling(n); /* The only node after deletion */
X if (isroot(p)) {
X s->p.parent = p->p.parent;
X s->p.parent->p.root = s;
X setroot(s);
X free(p);
X free(n);
X return;
X }
X gp = p->p.parent; /* Set parent to sibling */
X s->p.parent = gp;
X if (isleft(p)) {
X gp->c.child.left = s;
X setleft(s);
X } else {
X gp->c.child.right = s;
X setright(s);
X }
X ir = isred(p);
X free(p);
X free(n);
X
X if (isext(s)) { /* Update proper rext and lext values */
X p = lprev(s);
X if (!ishead(p))
X p->v.rext = s;
X p = rprev(s);
X if (!ishead(p))
X p->k.lext = s;
X } else if (isblack(s)) {
X fprintf(stderr, "DELETION PROB -- sib is black, internal\n");
X exit(1);
X } else {
X p = lprev(s);
X if (!ishead(p))
X p->v.rext = s->c.child.left;
X p = rprev(s);
X if (!ishead(p))
X p->k.lext = s->c.child.right;
X setblack(s);
X return;
X }
X
X if (ir)
X return;
X
X /* Recolor */
X
X n = s;
X p = n->p.parent;
X s = sibling(n);
X while (isblack(p) && isblack(s) && isint(s) &&
X isblack(s->c.child.left) && isblack(s->c.child.right)) {
X setred(s);
X n = p;
X if (isroot(n))
X return;
X p = n->p.parent;
X s = sibling(n);
X }
X
X if (isblack(p) && isred(s)) { /* Rotation 2.3b */
X single_rotate(p, isright(n));
X setred(p);
X setblack(s);
X s = sibling(n);
X }
X {
X Rb_node x, z;
X char il;
X
X if (isext(s)) {
X fprintf(stderr,
X "DELETION ERROR: sibling not internal\n");
X exit(1);
X }
X il = isleft(n);
X x = il ? s->c.child.left : s->c.child.right;
X z = sibling(x);
X
X if (isred(z)) { /* Rotation 2.3f */
X single_rotate(p, !il);
X setblack(z);
X if (isred(p))
X setred(s);
X else
X setblack(s);
X setblack(p);
X } else if (isblack(x)) {
X /* Recoloring only (2.3c) */
X if (isred(s) || isblack(p)) {
X fprintf(stderr,
X "DELETION ERROR: 2.3c not quite right\n");
X exit(1);
X }
X setblack(p);
X setred(s);
X return;
X } else if (isred(p)) {
X /* 2.3d */
X single_rotate(s, il);
X single_rotate(p, !il);
X setblack(x);
X setred(s);
X return;
X } else {
X /* 2.3e */
X single_rotate(s, il);
X single_rotate(p, !il);
X setblack(x);
X return;
X }
X }
X}
X
Xvoid
Xrb_print_tree(t, level)
X Rb_node t;
X int level;
X{
X int i;
X
X if (ishead(t) && t->p.parent == t) {
X printf("tree 0x%x is empty\n",
X (int)t);
X } else if (ishead(t)) {
X printf("Head: 0x%x. Root = 0x%x\n", (int)t, (int)t->p.root);
X rb_print_tree(t->p.root, 0);
X } else {
X if (isext(t)) {
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Ext node 0x%x: %c,%c: p=0x%x, k=%s\n", (int)t,
X isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->p.parent, t->k.key);
X } else {
X rb_print_tree(t->c.child.left, level + 2);
X rb_print_tree(t->c.child.right, level + 2);
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%s,%s)\n",
X (int)t, isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->c.child.left, (int)t->c.child.right,
X (int)t->p.parent, t->k.lext->k.key,
X t->v.rext->k.key);
X }
X }
X}
X
Xvoid
Xrb_iprint_tree(t, level)
X Rb_node t;
X int level;
X{
X int i;
X
X if (ishead(t) && t->p.parent == t) {
X printf("tree 0x%x is empty\n", (int)t);
X } else if (ishead(t)) {
X printf("Head: 0x%x. Root = 0x%x, < = 0x%x, > = 0x%x\n",
X (int)t, (int)t->p.root, (int)t->c.list.blink,
X (int)t->c.list.flink);
X rb_iprint_tree(t->p.root, 0);
X } else {
X if (isext(t)) {
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Ext node 0x%x: %c,%c: p=0x%x, <=0x%x, >=0x%x k=%d\n",
X (int)t, isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->p.parent, (int)t->c.list.blink,
X (int)t->c.list.flink, t->k.ikey);
X } else {
X rb_iprint_tree(t->c.child.left, level + 2);
X rb_iprint_tree(t->c.child.right, level + 2);
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%d,%d)\n",
X (int)t, isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->c.child.left, (int)t->c.child.right,
X (int)t->p.parent, t->k.lext->k.ikey,
X t->v.rext->k.ikey);
X }
X }
X}
X
Xvoid
Xrb_uprint_tree(t, level)
X Rb_node t;
X int level;
X{
X int i;
X if (ishead(t) && t->p.parent == t) {
X printf("tree 0x%x is empty\n", (int)t);
X } else if (ishead(t)) {
X printf("Head: 0x%x. Root = 0x%x, < = 0x%x, > = 0x%x\n",
X (int)t, (int)t->p.root, (int)t->c.list.blink,
X (int)t->c.list.flink);
X rb_uprint_tree(t->p.root, 0);
X } else {
X if (isext(t)) {
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Ext node 0x%x: %c,%c: p=0x%x, <=0x%x, >=0x%x k=%lu\n",
X (int)t, isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->p.parent, (int)t->c.list.blink,
X (int)t->c.list.flink, t->k.ukey);
X } else {
X rb_uprint_tree(t->c.child.left, level + 2);
X rb_uprint_tree(t->c.child.right, level + 2);
X for (i = 0; i < level; i++)
X putchar(' ');
X printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%lu,%lu)\n",
X (int)t, isred(t) ? 'R' : 'B', isleft(t) ? 'l' : 'r',
X (int)t->c.child.left, (int)t->c.child.right,
X (int)t->p.parent, t->k.lext->k.ukey,
X t->v.rext->k.ukey);
X }
X }
X}
X
Xint
Xrb_nblack(n)
X Rb_node(n);
X{
X int nb;
X
X if (ishead(n) || isint(n)) {
X fprintf(stderr,
X "ERROR: rb_nblack called on a non-external node 0x%x\n",
X (int)n);
X exit(1);
X }
X nb = 0;
X while (!ishead(n)) {
X if (isblack(n))
X nb++;
X n = n->p.parent;
X }
X return (nb);
X}
X
Xint
Xrb_plength(n)
X Rb_node(n);
X{
X int pl;
X
X if (ishead(n) || isint(n)) {
X fprintf(stderr,
X "ERROR: rb_plength called on a non-external node 0x%x\n",
X (int)n);
X exit(1);
X }
X pl = 0;
X while (!ishead(n)) {
X pl++;
X n = n->p.parent;
X }
X return (pl);
X}
X
Xvoid
Xrb_free_tree(n)
X Rb_node(n);
X{
X
X if (!ishead(n)) {
X fprintf(stderr,
X "ERROR: Rb_free_tree called on a non-head node\n");
X exit(1);
X }
X while (rb_first(n) != nil(n)) {
X rb_delete_node(rb_first(n));
X }
X free(n);
X}
X
Xchar *
Xrb_val(n)
X Rb_node(n);
X{
X return (n->v.val);
X}
END_OF_FILE
if test 13684 -ne `wc -c <'tclmidi-2.0/rb/rb.c'`; then
echo shar: \"'tclmidi-2.0/rb/rb.c'\" unpacked with wrong size!
fi
# end of 'tclmidi-2.0/rb/rb.c'
fi
echo shar: End of archive 3 \(of 14\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 14 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...