#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 09/10/1992 22:19 UTC by tjt@wink
# Source directory /w0/tmp
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   3227 -rw-rw-r-- mf2rol/bankfile.c
#   9462 -rw-rw-r-- mf2rol/midifile.c
#    885 -rw-rw-r-- mf2rol/midifile.h
#     53 -rw-rw-r-- mf2rol/compile.bat
#   3799 -rw-rw-r-- mf2rol/listbnk.c
#  26278 -rw-rw-r-- mf2rol/mf2rol.c
#   1008 -rw-rw-r-- mf2rol/readme.txt
#
# ============= mf2rol/bankfile.c ==============
if test ! -d 'mf2rol'; then
    echo 'x - creating directory mf2rol'
    mkdir 'mf2rol'
fi
if test -f 'mf2rol/bankfile.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/bankfile.c (File already exists)'
else
echo 'x - extracting mf2rol/bankfile.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/bankfile.c' &&
#include <stdio.h>
X
/* Instrument bank file header */
typedef struct {
X   char      majorVersion;
X   char      minorVersion;
X   char      sig [6];            /* signature: "ADLIB-" */
X   unsigned  nrDefined;          /* number of list entries used */
X   unsigned  nrEntry;            /* number of total entries in list */
X   long      offsetIndex;        /* offset in file of start of name list */
X   long      offsetTimbre;       /* offset in file of start of data */
X   char      filler [8];         /* must be zero */
} BankHeader;
X
X
/* Name of instrument with a pointer to its position in the file */
typedef struct {
X   unsigned nrReference;       /* index into data section */
X   char  usedFlag;             /* 0 if this entry is not used */
X   char  TimbreName [9];       /* max 8 char's + NULL */
} BankEntry;
X
X
/* Operator structure */
typedef struct {
X   char  ksl;
X   char  freqMult;
X   char  feedBack;              /* used by operator 0 only */
X   char  attack;
X   char  sustLevel;
X   char  sustain;
X   char  decay;
X   char  release;
X   char  output;
X   char  am;
X   char  vib;
X   char  ksr;
X   char  fm;                    /* used by operator 0 only */
} Operator;
X
X
typedef struct {
X	char      mode;
X	char      percVoice;
X	Operator  op0;
X	Operator  op1;
X	char      wave0;            /* wave form for operator 0 */
X	char      wave1;            /* wave form for operator 1 */
} PackedTimbre;
X
struct dat {
X	char name[9];
X	char pmode;
X	int voicenum;
X	unsigned idx;
} *d;
X
BankHeader bh;
BankEntry be;
PackedTimbre pt;
X
FILE *fin;
badfile()
{
X	fprintf(stderr, "File is not an AdLib Instrument Bank file\n");
X	exit(1);
X	fclose(fin);
}
X
readbank(arg)
char *arg;
{
X	int i, j;
X	struct dat *q;
X	char *malloc();
X	int maxidx;
X
X	if ((fin=fopen(arg, "rb")) == NULL) {
X		fprintf(stderr, "Cannot open bank file: %s\n", arg);
X		exit(1);
X	};
X	fprintf(stderr, "    Reading instrument bank file %s\n", arg);
X	if (fread(&bh, 1, sizeof(BankHeader), fin) != sizeof(BankHeader))
X		badfile();
X	if (strncmp(bh.sig, "ADLIB-", 6) != 0)
X		badfile();
X	if ((d=(struct dat *) malloc(bh.nrDefined * sizeof(struct dat))) == NULL) {
X		fprintf(stderr, "Not enough memory.\n");
X		exit(1);
X	}
X	if (fseek(fin, bh.offsetIndex, 0) != 0)
X		badfile();
X	q = d;
X	maxidx = 0;
X	for (i=0; i<bh.nrEntry ;i++) {
X		if (fread(&be, 1, sizeof(BankEntry), fin) != sizeof(BankEntry))
X			badfile();
X		if (be.usedFlag) {
X			strcpy(q->name, be.TimbreName);
X			q->idx = be.nrReference;
X			if (be.nrReference > maxidx)
X				maxidx = be.nrReference;
X			q++;
X		}
X	}
X	if (fseek(fin, bh.offsetTimbre, 0) != 0)
X		badfile();
X	maxidx++;
X	for (i=0; i<maxidx; i++) {
X		if (fread(&pt, 1, sizeof(PackedTimbre), fin) != sizeof(PackedTimbre))
X			badfile();
X		for (j=0, q=d; j<bh.nrDefined; j++, q++)
X			if (q->idx == i)
X				break;
X		if (j < bh.nrDefined) {
X			q->pmode = pt.mode;
X			q->voicenum = pt.percVoice;
X		}
X	}
X	fclose(fin);
}
X
findtimbre(s)
char *s;
{
X	struct dat *q;
X	int i;
X
X	for (i=0, q=d; i<bh.nrDefined; i++, q++) {
X		if (strcmp(s, q->name) == 0) {
X			if (q->pmode)
X				return(q->voicenum);
X			else
X				return(0);
X		}
X	}
X	return(-1);
}
SHAR_EOF
chmod 0664 mf2rol/bankfile.c ||
echo 'restore of mf2rol/bankfile.c failed'
Wc_c="`wc -c < 'mf2rol/bankfile.c'`"
test 3227 -eq "$Wc_c" ||
	echo 'mf2rol/bankfile.c: original size 3227, current size' "$Wc_c"
fi
# ============= mf2rol/midifile.c ==============
if test -f 'mf2rol/midifile.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/midifile.c (File already exists)'
else
echo 'x - extracting mf2rol/midifile.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/midifile.c' &&
/*
X * midifile
X * 
X * Read a MIDI file.  Externally-assigned function pointers are called
X * upon recognizing things in the file.
X */
X
#include "midifile.h"
X
#define NULLFUNC 0
#define NULL 0
#define EOF (-1)
X
char *strcpy(), *strcat();
void exit(), free();
X
/* public stuff */
X
/* Functions to be called while processing the MIDI file. */
int (*Mf_getc)() = NULLFUNC;
int (*Mf_error)() = NULLFUNC;
int (*Mf_header)() = NULLFUNC;
int (*Mf_trackstart)() = NULLFUNC;
int (*Mf_trackend)() = NULLFUNC;
int (*Mf_noteon)() = NULLFUNC;
int (*Mf_noteoff)() = NULLFUNC;
int (*Mf_pressure)() = NULLFUNC;
int (*Mf_parameter)() = NULLFUNC;
int (*Mf_pitchbend)() = NULLFUNC;
int (*Mf_program)() = NULLFUNC;
int (*Mf_chanpressure)() = NULLFUNC;
int (*Mf_sysex)() = NULLFUNC;
int (*Mf_arbitrary)() = NULLFUNC;
int (*Mf_metamisc)() = NULLFUNC;
int (*Mf_seqnum)() = NULLFUNC;
int (*Mf_eot)() = NULLFUNC;
int (*Mf_smpte)() = NULLFUNC;
int (*Mf_tempo)() = NULLFUNC;
int (*Mf_timesig)() = NULLFUNC;
int (*Mf_keysig)() = NULLFUNC;
int (*Mf_seqspecific)() = NULLFUNC;
int (*Mf_text)() = NULLFUNC;
X
int Mf_nomerge = 0;		/* 1 => continue'ed system exclusives are */
X				/* not collapsed. */
long Mf_currtime = 0L;		/* current time in delta-time units */
X
/* private stuff */
X
static long Mf_toberead = 0L;
X
static long readvarinum();
static long read32bit();
static long to32bit();
static int read16bit();
static int to16bit();
static char *msg();
X
midifile()	 	/* The only non-static function in this file. */
{
X	if ( Mf_getc == NULLFUNC )
X		mferror(""); 
X
X	readheader();
X	while ( readtrack() )
X		;
}
X
static
readmt(s)		/* read through the "MThd" or "MTrk" header string */
char *s;
{
X	int n = 0;
X	char *p = s;
X	int c;
X
X	while ( n++<4 && (c=(*Mf_getc)()) != EOF ) {
X		if ( c != *p++ ) {
X			char buff[32];
X			(void) strcpy(buff,"expecting ");
X			(void) strcat(buff,s);
X			if (strcmp(s, "MTrk") == 0) {
X				if ( Mf_error )
X					(*Mf_error)("expecting MTrk - assuming EOF");
X				return(EOF);
X			}
X			mferror(buff);
X		}
X	}
X	return(c);
}
X
static
egetc()			/* read a single character and abort on EOF */
{
X	int c = (*Mf_getc)();
X
X	if ( c == EOF )
X		mferror("unexpected EOF");
X	Mf_toberead--;
X	return(c);
}
X
static
readheader()		/* read a header chunk */
{
X	int format, ntrks, division;
X
X	if ( readmt("MThd") == EOF )
X		return(0);
X
X	Mf_toberead = read32bit();
X	format = read16bit();
X	ntrks = read16bit();
X	division = read16bit();
X
X	if ( Mf_header )
X		(*Mf_header)(format,ntrks,division);
X
X	/* flush any extra stuff, in case the length of header is not 6 */
X	while ( Mf_toberead > 0 )
X		(void) egetc();
X	return(0);
}
X
static
readtrack()		 /* read a track chunk */
{
X	/* This array is indexed by the high half of a status byte.  It's */
X	/* value is either the number of bytes needed (1 or 2) for a channel */
X	/* message, or 0 (meaning it's not  a channel message). */
X	static int chantype[] = {
X		0, 0, 0, 0, 0, 0, 0, 0,		/* 0x00 through 0x70 */
X		2, 2, 2, 2, 1, 1, 2, 0		/* 0x80 through 0xf0 */
X	};
X	long lookfor, lng;
X	int c, c1, type;
X	int sysexcontinue = 0;	/* 1 if last message was an unfinished sysex */
X	int running = 0;	/* 1 when running status used */
X	int status = 0;		/* (possibly running) status byte */
X	int needed;
X
X	if ( readmt("MTrk") == EOF )
X		return(0);
X
X	Mf_toberead = read32bit();
X	Mf_currtime = 0;
X
X	if ( Mf_trackstart )
X		(*Mf_trackstart)();
X
X	while ( Mf_toberead > 0 ) {
X
X		Mf_currtime += readvarinum();	/* delta time */
X
X		c = egetc();
X
X		if ( sysexcontinue && c != 0xf7 )
X			mferror("didn't find expected continuation of a sysex");
X
X		if ( (c & 0x80) == 0 ) {	 /* running status? */
X			if ( status == 0 )
X				mferror("unexpected running status");
X			running = 1;
X		}
X		else {
X			status = c;
X			running = 0;
X		}
X
X		needed = chantype[ (status>>4) & 0xf ];
X
X		if ( needed ) {		/* ie. is it a channel message? */
X
X			if ( running )
X				c1 = c;
X			else
X				c1 = egetc();
X			chanmessage( status, c1, (needed>1) ? egetc() : 0 );
X			continue;;
X		}
X
X		switch ( c ) {
X
X		case 0xff:			/* meta event */
X
X			type = egetc();
X			lng = readvarinum();
X			lookfor = Mf_toberead - lng;
X			msginit();
X
X			while ( Mf_toberead > lookfor )
X				msgadd(egetc());
X
X			metaevent(type);
X			break;
X
X		case 0xf0:		/* start of system exclusive */
X
X			lng = readvarinum();
X			lookfor = Mf_toberead - lng;
X			msginit();
X			msgadd(0xf0);
X
X			while ( Mf_toberead > lookfor )
X				msgadd(c=egetc());
X
X			if ( c==0xf7 || Mf_nomerge==0 )
X				sysex();
X			else
X				sysexcontinue = 1;  /* merge into next msg */
X			break;
X
X		case 0xf7:	/* sysex continuation or arbitrary stuff */
X
X			lng = readvarinum();
X			lookfor = Mf_toberead - lng;
X
X			if ( ! sysexcontinue )
X				msginit();
X
X			while ( Mf_toberead > lookfor )
X				msgadd(c=egetc());
X
X			if ( ! sysexcontinue ) {
X				if ( Mf_arbitrary )
X					(*Mf_arbitrary)(msgleng(),msg());
X			}
X			else if ( c == 0xf7 ) {
X				sysex();
X				sysexcontinue = 0;
X			}
X			break;
X		default:
X			badbyte(c);
X			break;
X		}
X	}
X	if ( Mf_trackend )
X		(*Mf_trackend)();
X	return(1);
}
X
static
badbyte(c)
int c;
{
X	char buff[32];
X
X	(void) sprintf(buff,"unexpected byte: 0x%02x",c);
X	mferror(buff);
}
X
static
metaevent(type)
{
X	int leng = msgleng();
X	char *m = msg();
X
X	switch  ( type ) {
X	case 0x00:
X		if ( Mf_seqnum )
X			(*Mf_seqnum)(to16bit(m[0],m[1]));
X		break;
X	case 0x01:	/* Text event */
X	case 0x02:	/* Copyright notice */
X	case 0x03:	/* Sequence/Track name */
X	case 0x04:	/* Instrument name */
X	case 0x05:	/* Lyric */
X	case 0x06:	/* Marker */
X	case 0x07:	/* Cue point */
X	case 0x08:
X	case 0x09:
X	case 0x0a:
X	case 0x0b:
X	case 0x0c:
X	case 0x0d:
X	case 0x0e:
X	case 0x0f:
X		/* These are all text events */
X		if ( Mf_text )
X			(*Mf_text)(type,leng,m);
X		break;
X	case 0x2f:	/* End of Track */
X		if ( Mf_eot )
X			(*Mf_eot)();
X		break;
X	case 0x51:	/* Set tempo */
X		if ( Mf_tempo )
X			(*Mf_tempo)(to32bit(0,m[0],m[1],m[2]));
X		break;
X	case 0x54:
X		if ( Mf_smpte )
X			(*Mf_smpte)(m[0],m[1],m[2],m[3],m[4]);
X		break;
X	case 0x58:
X		if ( Mf_timesig )
X			(*Mf_timesig)(m[0],m[1],m[2],m[3]);
X		break;
X	case 0x59:
X		if ( Mf_keysig )
X			(*Mf_keysig)(m[0],m[1]);
X		break;
X	case 0x7f:
X		if ( Mf_seqspecific )
X			(*Mf_seqspecific)(leng,m);
X		break;
X	default:
X		if ( Mf_metamisc )
X			(*Mf_metamisc)(type,leng,m);
X	}
}
X
static
sysex()
{
X	if ( Mf_sysex )
X		(*Mf_sysex)(msgleng(),msg());
}
X
static
chanmessage(status,c1,c2)
int status;
int c1, c2;
{
X	int chan = status & 0xf;
X
X	switch ( status & 0xf0 ) {
X	case NOTEOFF:
X		if ( Mf_noteoff )
X			(*Mf_noteoff)(chan,c1,c2);
X		break;
X	case NOTEON:
X		if ( Mf_noteon )
X			(*Mf_noteon)(chan,c1,c2);
X		break;
X	case PRESSURE:
X		if ( Mf_pressure )
X			(*Mf_pressure)(chan,c1,c2);
X		break;
X	case PARAMETER:
X		if ( Mf_parameter )
X			(*Mf_parameter)(chan,c1,c2);
X		break;
X	case PITCHBEND:
X		if ( Mf_pitchbend )
X			(*Mf_pitchbend)(chan,c1,c2);
X		break;
X	case PROGRAM:
X		if ( Mf_program )
X			(*Mf_program)(chan,c1);
X		break;
X	case CHANPRESSURE:
X		if ( Mf_chanpressure )
X			(*Mf_chanpressure)(chan,c1);
X		break;
X	}
}
X
/* readvarinum - read a varying-length number, and return the */
/* number of characters it took. */
X
static long
readvarinum()
{
X	long value;
X	int c;
X
X	c = egetc();
X	value = c;
X	if ( c & 0x80 ) {
X		value &= 0x7f;
X		do {
X			c = egetc();
X			value = (value << 7) + (c & 0x7f);
X		} while (c & 0x80);
X	}
X	return (value);
}
X
static long
to32bit(c1,c2,c3,c4)
{
X	long value = 0L;
X
X	value = (c1 & 0xff);
X	value = (value<<8) + (c2 & 0xff);
X	value = (value<<8) + (c3 & 0xff);
X	value = (value<<8) + (c4 & 0xff);
X	return (value);
}
X
static
to16bit(c1,c2)
int c1, c2;
{
X	return ((c1 & 0xff ) << 8) + (c2 & 0xff);
}
X
static long
read32bit()
{
X	int c1, c2, c3, c4;
X
X	c1 = egetc();
X	c2 = egetc();
X	c3 = egetc();
X	c4 = egetc();
X	return to32bit(c1,c2,c3,c4);
}
X
static
read16bit()
{
X	int c1, c2;
X	c1 = egetc();
X	c2 = egetc();
X	return to16bit(c1,c2);
}
X
static
mferror(s)
char *s;
{
X	if ( Mf_error )
X		(*Mf_error)(s);
X	exit(1);
}
X
/* The code below allows collection of a system exclusive message of */
/* arbitrary length.  The Msgbuff is expanded as necessary.  The only */
/* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */
X
#define MSGINCREMENT 256
static char *Msgbuff = NULL;	/* message buffer */
static int Msgsize = 0;		/* Size of currently allocated Msg */
static int Msgindex = 0;	/* index of next available location in Msg */
X
static
msginit()
{
X	Msgindex = 0;
}
X
static char *
msg()
{
X	return(Msgbuff);
}
X
static
msgleng()
{
X	return(Msgindex);
}
X
static
msgadd(c)
int c;
{
X	/* If necessary, allocate larger message buffer. */
X	if ( Msgindex >= Msgsize )
X		biggermsg();
X	Msgbuff[Msgindex++] = c;
}
X
static
biggermsg()
{
X	char *malloc();
X	char *newmess;
X	char *oldmess = Msgbuff;
X	int oldleng = Msgsize;
X
X	Msgsize += MSGINCREMENT;
X	newmess = malloc( (unsigned)(sizeof(char)*Msgsize) );
X
X	/* copy old message into larger new one */
X	if ( oldmess != NULL ) {
X		register char *p = newmess;
X		register char *q = oldmess;
X		register char *endq = &oldmess[oldleng];
X
X		for ( ; q!=endq ; p++,q++ )
X			*p = *q;
X		/* free(oldmess); */
X	}
X	Msgbuff = newmess;
}
SHAR_EOF
chmod 0664 mf2rol/midifile.c ||
echo 'restore of mf2rol/midifile.c failed'
Wc_c="`wc -c < 'mf2rol/midifile.c'`"
test 9462 -eq "$Wc_c" ||
	echo 'mf2rol/midifile.c: original size 9462, current size' "$Wc_c"
fi
# ============= mf2rol/midifile.h ==============
if test -f 'mf2rol/midifile.h' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/midifile.h (File already exists)'
else
echo 'x - extracting mf2rol/midifile.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/midifile.h' &&
extern int (*Mf_getc)();
extern int (*Mf_header)();
extern int (*Mf_trackstart)();
extern int (*Mf_trackend)();
extern int (*Mf_noteon)();
extern int (*Mf_noteoff)();
extern int (*Mf_pressure)();
extern int (*Mf_parameter)();
extern int (*Mf_pitchbend)();
extern int (*Mf_program)();
extern int (*Mf_chanpressure)();
extern int (*Mf_sysex)();
extern int (*Mf_metamisc)();
extern int (*Mf_seqspecific)();
extern int (*Mf_seqnum)();
extern int (*Mf_text)();
extern int (*Mf_eot)();
extern int (*Mf_timesig)();
extern int (*Mf_smpte)();
extern int (*Mf_tempo)(long);
extern int (*Mf_keysig)();
extern int (*Mf_arbitrary)();
extern int (*Mf_error)();
extern long Mf_currtime;
extern int Mf_nomerge;
X
#define NOTEOFF 0x80
#define NOTEON 0x90
#define PRESSURE 0xa0
#define PARAMETER 0xb0
#define PITCHBEND 0xe0
#define PROGRAM 0xc0
#define CHANPRESSURE 0xd0
SHAR_EOF
chmod 0664 mf2rol/midifile.h ||
echo 'restore of mf2rol/midifile.h failed'
Wc_c="`wc -c < 'mf2rol/midifile.h'`"
test 885 -eq "$Wc_c" ||
	echo 'mf2rol/midifile.h: original size 885, current size' "$Wc_c"
fi
# ============= mf2rol/compile.bat ==============
if test -f 'mf2rol/compile.bat' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/compile.bat (File already exists)'
else
echo 'x - extracting mf2rol/compile.bat (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/compile.bat' &&
cl /AH mf2rol.c midifile.c bankfile.c
cl listbnk.c
SHAR_EOF
chmod 0664 mf2rol/compile.bat ||
echo 'restore of mf2rol/compile.bat failed'
Wc_c="`wc -c < 'mf2rol/compile.bat'`"
test 53 -eq "$Wc_c" ||
	echo 'mf2rol/compile.bat: original size 53, current size' "$Wc_c"
fi
# ============= mf2rol/listbnk.c ==============
if test -f 'mf2rol/listbnk.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/listbnk.c (File already exists)'
else
echo 'x - extracting mf2rol/listbnk.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/listbnk.c' &&
#include <stdio.h>
X
/* Instrument bank file header */
typedef struct {
X   char      majorVersion;
X   char      minorVersion;
X   char      sig [6];            /* signature: "ADLIB-" */
X   unsigned  nrDefined;          /* number of list entries used */
X   unsigned  nrEntry;            /* number of total entries in list */
X   long      offsetIndex;        /* offset in file of start of name list */
X   long      offsetTimbre;       /* offset in file of start of data */
X   char      filler [8];         /* must be zero */
} BankHeader;
X
X
/* Name of instrument with a pointer to its position in the file */
typedef struct {
X   unsigned nrReference;       /* index into data section */
X   char  usedFlag;             /* 0 if this entry is not used */
X   char  TimbreName [9];       /* max 8 char's + NULL */
} BankEntry;
X
X
/* Operator structure */
typedef struct {
X   char  ksl;
X   char  freqMult;
X   char  feedBack;              /* used by operator 0 only */
X   char  attack;
X   char  sustLevel;
X   char  sustain;
X   char  decay;
X   char  release;
X   char  output;
X   char  am;
X   char  vib;
X   char  ksr;
X   char  fm;                    /* used by operator 0 only */
} Operator;
X
X
typedef struct {
X	char      mode;
X	char      percVoice;
X	Operator  op0;
X	Operator  op1;
X	char      wave0;            /* wave form for operator 0 */
X	char      wave1;            /* wave form for operator 1 */
} PackedTimbre;
X
struct dat {
X	char name[9];
X	char pmode;
X	int voicenum;
X	unsigned idx;
};
X
BankHeader bh;
BankEntry be;
PackedTimbre pt;
X
FILE *fin;
badfile()
{
X	fprintf(stderr, "File is not an AdLib Instrument Bank file\n");
X	exit(1);
X	fclose(fin);
}
X
main(argc,argv)
int argc;
char *argv[];
{
X	int i, j;
X	struct dat *d, *q;
X	char *malloc();
X	int maxidx;
X
X	printcopy();
X	if (argc != 2) {
X		fprintf(stderr, "LISTBNK - This program lists the instruments within a .BNK file.\n");
X		fprintf(stderr, "Usage:\n    listbnk bnkfile\nExample:\n    listbnk standard.bnk\n");
X		fprintf(stderr, "Percussion instruments are labeled with a P followed by the\n");
X		fprintf(stderr, "voice number (06 through 10) the instrument is assigned to.\n");
X		exit(1);
X	}
X	if ((fin=fopen(argv[1], "rb")) == NULL) {
X		fprintf(stderr, "Cannot open file: %s\n", argv[1]);
X		exit(1);
X	};
X	if (fread(&bh, 1, sizeof(BankHeader), fin) != sizeof(BankHeader))
X		badfile();
X	if (strncmp(bh.sig, "ADLIB-", 6) != 0)
X		badfile();
X	if ((d=(struct dat *) malloc(bh.nrDefined * sizeof(struct dat))) == NULL) {
X		fprintf(stderr, "Not enough memory.\n");
X		exit(1);
X	}
X	if (fseek(fin, bh.offsetIndex, 0) != 0)
X		badfile();
X	q = d;
X	maxidx = 0;
X	for (i=0; i<bh.nrEntry ;i++) {
X		if (fread(&be, 1, sizeof(BankEntry), fin) != sizeof(BankEntry))
X			badfile();
X		if (be.usedFlag) {
X			strcpy(q->name, be.TimbreName);
X			q->idx = be.nrReference;
X			if (be.nrReference > maxidx)
X				maxidx = be.nrReference;
X			q++;
X		}
X	}
X	if (fseek(fin, bh.offsetTimbre, 0) != 0)
X		badfile();
X	maxidx++;
X	for (i=0; i<maxidx; i++) {
X		if (fread(&pt, 1, sizeof(PackedTimbre), fin) != sizeof(PackedTimbre))
X			badfile();
X		for (j=0, q=d; j<bh.nrDefined; j++, q++)
X			if (q->idx == i)
X				break;
X		if (j < bh.nrDefined) {
X			q->pmode = pt.mode;
X			q->voicenum = pt.percVoice;
X		}
X	}
X	printf("\nBank file %s contains %d instruments\n\n", argv[1], bh.nrDefined);
X	for (i=0, q=d; i<bh.nrDefined; i++, q++) {
X		if (q->pmode)
X			printf("  P%02d-%-8s", q->voicenum, q->name);
X		else
X			printf("      %-8s", q->name);
X		if ((i+1)%5 == 0)
X			printf("\n");
X	}
X	if (i%5 != 0)
X		printf("\n");
X	fclose(fin);
}
printcopy()
{
X	static char notice[] = "Bankfile Listing Utility  V1.0   A. A. Kapauan 1991";
X	fprintf(stderr, "\n%s\n\n", notice);
}
X
SHAR_EOF
chmod 0664 mf2rol/listbnk.c ||
echo 'restore of mf2rol/listbnk.c failed'
Wc_c="`wc -c < 'mf2rol/listbnk.c'`"
test 3799 -eq "$Wc_c" ||
	echo 'mf2rol/listbnk.c: original size 3799, current size' "$Wc_c"
fi
# ============= mf2rol/mf2rol.c ==============
if test -f 'mf2rol/mf2rol.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/mf2rol.c (File already exists)'
else
echo 'x - extracting mf2rol/mf2rol.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/mf2rol.c' &&
/*
X * mf2rol
X *
X * Convert a MIDI file to AdLib .ROL
X */
X
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "midifile.h"
X
#define MAXTRACK 128
#define CHUNKSIZE 0x8000
#define NR_VOICES 11
X
char filler44[44] = {
0,0,4,0,
92,114,111,108,108,92,100,101,102,97,117,108,116,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
X
char filler5[5] = {
48,0,56,0,0};
X
char filler143[143] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,
0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,2,0,
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
1,0,1,0,1,0,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84,101,109,112,111,0,43,42,-16,67,-16,67,43,42,70};
X
char fillernote[15] = {
86,111,105,120,32,32,48,0,-16,67,0,0,-68,51,-53};
char fillerinstrum[15] = {
84,105,109,98,114,101,32,32,48,0,86,111,105,120,32};
char fillervolume[15] = {
86,111,108,117,109,101,32,32,48,0,84,105,109,98,114};
char fillerpitch[15] = {
80,105,116,99,104,32,32,48,0,0,84,105,109,98,114};
X
/* structure used to store midifile events internally */
struct i_event {
X	long i_time;
X	int trk;
X	char chan;
X	char type;
X	char v1;
X	char v2;
X	struct i_event *next;
};
#define getmemEvent() ((struct i_event *) getmem(sizeof(struct i_event)))
X
/* structure used to store timbre assignment rules internally */
int ntrules;
struct timrule {
X	char name[9];
X	char track;
X	char channel;
X	char patch;
X	char note;
X	char percus;
X	int  offset;
} *trulebase;
/* name of timbre bank file */
char bankfile[64];
X
/* variables defining tempo */
int division;
float basictempo;
int beats_measure;
int notebeat;
int ticks_beat;
long maxquarter;
int clocks_click;
int sper24;
X
/* flag for percussion mode */
int ispercussion;
X
/* event types for struct i_event */
#define I_NOTEOFF  0
#define I_PATCH    1
#define I_TEMPO    2
#define I_NOTEON   3
#define I_PRESSURE 4
#define I_PITCH    5
/*
char *etypestr[]={"off", "patch", "tempo", "on", "pressure", "pitch"};
*/
X
struct i_event *i_curr;
struct i_event *i_trkbase[MAXTRACK];
struct i_event *i_trkptr[MAXTRACK];
X
int i_ntrks;
char patchmap[16][16];
char chanuse[16];
char curpatch[16];
X
char *alloc_base;
char *alloc_limit;
X
typedef int Time;
struct sTempoEvent {
X		Time    time;
X		float   tempo;
X		struct sTempoEvent *next;
X	} ;
typedef struct sTempoEvent TempoEvent;
#define getmemTempo() ((TempoEvent *) getmem(sizeof(TempoEvent)))
struct sNoteEvent {
X		Time			ontime;
X		Time			offtime;
X		char             note;
X		char             offset;
X		struct sNoteEvent *next;
X	} ;
typedef struct sNoteEvent NoteEvent;
#define getmemNote() ((NoteEvent *) getmem(sizeof(NoteEvent)))
struct sInstrumEvent {
X		Time time;
X		char instrumName[ 9];
X		char filler;
X		int     timbreIndex;
X		struct sInstrumEvent *next;
X	} ;
typedef struct sInstrumEvent InstrumEvent;
#define getmemInstrum() ((InstrumEvent *) getmem(sizeof(InstrumEvent)))
struct sVolumeEvent {
X		Time time;
X		float volume;
X		struct sVolumeEvent *next;
X	} ;
typedef struct sVolumeEvent VolumeEvent;
#define getmemVolume() ((VolumeEvent *) getmem(sizeof(VolumeEvent)))
struct sPitchEvent {
X		Time time;
X		float pitch;
X		struct sPitchEvent *next;
X	} ;
typedef struct sPitchEvent PitchEvent;
#define getmemPitch() ((PitchEvent *) getmem(sizeof(PitchEvent)))
X
TempoEvent *hTempoEvent;
TempoEvent *cTempoEvent;
struct hlisth {
X	NoteEvent *hNoteEvent;
X	InstrumEvent *hInstrumEvent;
X	VolumeEvent *hVolumeEvent;
X	PitchEvent *hPitchEvent;
X	NoteEvent *cNoteEvent;
X	InstrumEvent *cInstrumEvent;
X	VolumeEvent *cVolumeEvent;
X	PitchEvent *cPitchEvent;
} vocs[NR_VOICES];
X
struct vst {
X	char timbre[9];
X	char on;
X	int timeon;
X	int note;
X	int chan;
} vocstat[NR_VOICES];
X
static FILE *F;
X
filegetc()
{
X	return(getc(F));
}
X
outofmem()
{
X	fprintf(stderr, "\nError: Out of Memory. Sorry!\n");
X	exit(1);
}
X
char *getmem(size)
{
X	char *p;
X	/*
X	static int chunknum = 0;
X	*/
X
X	p = alloc_base;
X	alloc_base += size;
X	if (alloc_base >= alloc_limit) {
X		/*
X		printf("Allocating 32K chunk %d\n", ++chunknum);
X		*/
X		alloc_base = malloc(CHUNKSIZE);
X		if (alloc_base == NULL)
X			outofmem();
X		alloc_limit = alloc_base + CHUNKSIZE;
X		p = alloc_base;
X		alloc_base += size;
X	}
X	return(p);
}
char *nextarg(s)
char *s;
{
X	while ((*s != 0) && (*s != ' ') && (*s != '\t') && (*s != '\n'))
X		s++;
X	if ((*s == 0) || (*s == '\n'))
X		return(NULL);
X	while ((*s == ' ') || (*s == '\t'))
X		s++;
X	if ((*s == 0) || (*s == '\n'))
X		return(NULL);
X	return(s);
}
copyarg(s1, s2)
char *s1, *s2;
{
X	while ((*s2 != ' ') && (*s2 != '\t') && (*s2 != '\n') && (*s2 != 0)) {
X		if (islower(*s2))
X			*s1 = toupper(*s2);
X		else
X			*s1 = *s2;
X		s1++;
X		s2++;
X	}
X	*s1 = 0;
}
scanerr(s)
char *s;
{
X	fprintf(stderr, "Syntax error: %s", s);
X	exit(1);
}
readrules(s)
char *s;
{
X	FILE *fin;
X	char buf[128];
X	struct timrule *t;
X	char *s1, *s2;
X	int v;
X
X	*bankfile = 0;
X	ispercussion = 0;
X	if ((fin = fopen(s, "r")) == NULL) {
X		fprintf(stderr, "Error: Can't open rule file %s.\n", s);
X		exit(1);
X	}
X	printf("Scanning rule file...\n");
X	ntrules = 1;
X	while (fgets(buf, 128, fin) != NULL)
X		if (strncmp(buf, "assign", 6) == 0)
X			ntrules++;
X	trulebase = (struct timrule *) malloc(ntrules * sizeof(struct timrule));
X	ntrules = 0;
X	fseek(fin, 0L, 0);
X	if (trulebase == NULL)
X		outofmem();
X	t = trulebase;
X	while (fgets(buf, 128, fin) != NULL) {
X		if ((*buf == '#') || (*buf == '\n') || (*buf == 0))
X			continue;
X		if (strncmp(buf, "assign", 6) == 0) {
X			if (*bankfile == 0) {
X				fprintf(stderr, "Error: Bankfile must come before assign\n");
X				exit(1);
X			}
X			s1 = nextarg(buf);
X			s2 = t->name;
X			copyarg(s2, s1);
X			if (strlen(s2) > 8) {
X				fprintf(stderr, "Error: instrument name longer than 8 characters\n");
X				exit(1);
X			}
X			if (strcmp(s2, "MUTE")==0)
X				v=0;
X			else if ((v=findtimbre(s2)) < 0) {
X				fprintf(stderr, "Error: cannot find instrument %s\n", s2);
X				exit(1);
X			}
X			while (*s2 != 0) {
X				if (isupper(*s2))
X					*s2 = tolower(*s2);
X				s2++;
X			}
X			t->percus = v;
X			s1 = nextarg(s1);
X			if (s1 == NULL)
X				scanerr(buf);
X			if (*s1 == '*')
X				t->track = -1;
X			else
X				t->track = atoi(s1);
X			s1 = nextarg(s1);
X			if (s1 == NULL)
X				scanerr(buf);
X			if (*s1 == '*')
X				t->channel = -1;
X			else
X				t->channel = atoi(s1);
X			s1 = nextarg(s1);
X			if (s1 == NULL)
X				scanerr(buf);
X			if (*s1 == '*')
X				t->patch = -1;
X			else
X				t->patch = atoi(s1);
X			s1 = nextarg(s1);
X			if (s1 == NULL)
X				scanerr(buf);
X			if (*s1 == '*')
X				t->note = -1;
X			else
X				t->note = atoi(s1);
X			s1 = nextarg(s1);
X			if (s1 == NULL)
X				t->offset = 0;
X			if (*s1 == '*')
X				t->offset = 0;
X			else
X				t->offset = atoi(s1);
X			/*
X			printf("%s %d %d %d %d %d\n",t->name,t->track,t->channel,t->patch,t->note,t->percus);
X			*/
X			ntrules++;
X			t++;
X		} else if (strncmp(buf, "percussion", 10) == 0) {
X			s1 = nextarg(buf);
X			if (s1 == NULL)
X				scanerr(buf);
X			if ((*s1 == 'y') || (*s1=='Y'))
X				ispercussion = 1;
X		} else if (strncmp(buf, "bankfile", 8) == 0) {
X			if (*bankfile != 0) {
X				fprintf(stderr, "Error: Multiple bankfiles\n");
X				exit(1);
X			}
X			s1 = nextarg(buf);
X			if (s1 == NULL)
X				scanerr(buf);
X			copyarg(bankfile, s1);
X			readbank(bankfile);
X		} else {
X			scanerr(buf);
X		}
X	}
X	printf("Scanning done.\n    %d assignment rules.\n", ntrules);
X	fclose(fin);
}
initevent()
{
X	int i;
X	TempoEvent *te;
X	NoteEvent *ne;
X	InstrumEvent *ie;
X	VolumeEvent *ve;
X	PitchEvent *pe;
X
X	hTempoEvent = cTempoEvent = getmemTempo();
X	hTempoEvent->next = NULL;
X	for (i=0; i<NR_VOICES; i++) {
X		vocstat[i].on = 0;
X		ne = vocs[i].hNoteEvent = vocs[i].cNoteEvent = getmemNote();
X		ne->next = NULL;
X		ie = vocs[i].hInstrumEvent = vocs[i].cInstrumEvent = getmemInstrum();
X		ie->next = NULL;
X		ve = vocs[i].hVolumeEvent = vocs[i].cVolumeEvent = getmemVolume();
X		ve->next = NULL;
X		pe = vocs[i].hPitchEvent = vocs[i].cPitchEvent = getmemPitch();
X		pe->next = NULL;
X	}
X	for (i=0; i<16; i++)
X		curpatch[i] = 0;
X
}
struct timrule *whattimbre(track, channel, patch, note)
{
X	int i;
X	struct timrule *p;
X	static struct timrule dflt = { "piano1", 0,0,0,0,0,0 };
X
X	p = trulebase;
X	i = ntrules;
X	while (i > 0) {
X		if ( ((p->track<0) || (p->track==track))
X			&& ((p->channel<0) || (p->channel==channel))
X			&& ((p->patch<0) || (p->patch==patch))
X			&& ((p->note<0) || (p->note==note)) )
X				return(p);
X		p++;
X		i--;
X	}
X	return(&dflt);
}
X
putevent(time, track, type, channel, arg1, arg2)
long time;
int track, type, channel, arg1, arg2;
{
X	int i, j;
X	int rtime;
X	int patch;
X	int v;
X	int lim;
X	int nfree;
X	int least;
X	struct timrule *timb;
X	TempoEvent *te;
X	NoteEvent *ne;
X	InstrumEvent *ie;
X	VolumeEvent *ve;
X	PitchEvent *pe;
X	long micro;
X	float tempofactor;
X
X	/*
X	printf("T=%ld type=%s chan=%d arg1=%d arg2=%d\n",time,etypestr[type],channel,arg1,arg2);
X	*/
X	rtime = (time * (long)ticks_beat) / (long)division;
X	if (rtime<0) {
X		fprintf(stderr, "Error: Tune too long for ROL\n");
X		exit(1);
X	}
X	switch (type) {
X	case I_NOTEON:
X		if (arg1 < 1)
X			break;
X		/* check if this note is already on */
X		for (i=0; i<NR_VOICES; i++)
X			if ((vocstat[i].on != 0) && (vocstat[i].note==arg1) &&
X				(vocstat[i].chan==channel))
X				break;
X		/* if already on then ignore this */
X		if (i<NR_VOICES)
X			break;
X		patch = curpatch[channel];
X		timb = whattimbre(track, channel+1, patch, arg1);
X		/* ignore if mute note */
X		if (strcmp(timb->name, "mute")==0)
X			break;
X		if (timb->percus) {
X			/* percussion timbre */
X			if (ispercussion)
X				/* if percussion timbre then we HAVE to use designated voice */
X				v = timb->percus;
X			else {
X				fprintf(stderr, "Error: Percussion timbre %s used but percussion mode not set\n", timb->name);
X				exit(1);
X			}
X			/*
X			printf("voice %d trk %d chan %d patch %d note %d timbre %s\n",
X			v, track, channel+1, patch, arg1, timb->name);
X			*/
X		} else {
X			/* non-percussion timbre */
X			if (ispercussion)
X				lim = 6;
X			else
X				lim = 9;
X			nfree = 0;
X			/* count number of free voices */
X			for (i=0; i<lim; i++)
X				if (vocstat[i].on == 0) {
X					v = i;
X					nfree++;
X				}
X
X			if (nfree > 1) {
X				/* more than one free voice */
X				/* search for one with one of the required timbre */
X				for (i=0; i<lim; i++)
X						if ((vocstat[i].on==0) && 
X						(strcmp(vocstat[i].timbre, timb->name)==0))
X							break;
X				if (i<lim) {
X					/* found one */
X					v = i;
X				} else {
X					/* no match so just get the first free voice */
X					for (i=0; i<lim; i++)
X						if (vocstat[i].on == 0)
X							break;
X					v = i;
X				}
X			} else if (nfree == 0) {
X				/* no free voice so bump somebody off */
X				/*
X				printf("Bump");
X				*/
X				least = vocstat[0].timeon;
X				v = 0;
X				for (i=0; i<lim; i++) {
X					/*
X					printf(" %d", vocstat[i].timeon);
X					*/
X					if (vocstat[i].timeon < least) {
X						least = vocstat[i].timeon;
X						v = i;
X					}
X				}
X				/*
X				printf("\nLeast was %d on voice %d\n", least, v);
X				*/
X			} else {
X				/* one free voice, no choice */
X				;
X			}
X		}
X		/* v is now set to the selected voice */
X		/* bump off old sound if necessary */
X		if (vocstat[v].on) {
X			(vocs[v].cNoteEvent)->offtime = rtime;
X			vocstat[v].on = 0;
X		}
X		/* change timbre if necessary */
X		if (strcmp(vocstat[v].timbre, timb->name) != 0) {
X			ie = vocs[v].cInstrumEvent;
X			ie->next = getmemInstrum();
X			ie = ie->next;
X			ie->time = rtime;
X			strcpy(ie->instrumName, timb->name);
X			ie->filler = 0;
X			ie->timbreIndex = 0;
X			ie->next = NULL;
X			vocs[v].cInstrumEvent = ie;
X			strcpy(vocstat[v].timbre, timb->name);
X			/*
X			printf("New timbre voice %d to %s %lx\n",v,timb->name, ie);
X			*/
X		}
X		ne = vocs[v].cNoteEvent;
X		ne->next = getmemNote();
X		ne = ne->next;
X		ne->ontime = rtime;
X		ne->offtime = rtime+1;
X		ne->note = arg1;
X		ne->offset = timb->offset;
X		ne->next = NULL;
X		vocs[v].cNoteEvent = ne;
X		vocstat[v].on = 1;
X		vocstat[v].timeon = rtime;
X		vocstat[v].note = arg1;
X		vocstat[v].chan = channel;
X		break;
X
X	case I_PATCH:
X		curpatch[channel] = arg1;
X		break;
X
X	case I_NOTEOFF:
X		/* look for this note to turn off */
X		for (i=0; i<NR_VOICES; i++)
X			if ((vocstat[i].on != 0) && (vocstat[i].note==arg1) &&
X				(vocstat[i].chan==channel))
X				break;
X		/* turn off this note if found */
X		if (i < NR_VOICES) {
X			v = i;
X			(vocs[v].cNoteEvent)->offtime = rtime;
X			vocstat[v].on = 0;
X		}
X		break;
X
X	case I_TEMPO:
X		micro = ((long) arg1) << 16;
X		micro &= 0xffff00;
X		micro |= (((long) arg2) << 8) & 0xff00;
X		micro &= 0xffff00;
X		tempofactor = 60000000.0/((float) micro);
X		tempofactor = tempofactor/basictempo;
X		te = cTempoEvent;
X		te->next = getmemTempo();
X		te = te->next;
X		te->next = NULL;
X		te->time = rtime;
X		te->tempo = tempofactor;
X		cTempoEvent = te;
X		break;
X
X	default:
X		break;
X	}
X
}
X
buildrol(fp)
FILE *fp;
{
X	int i;
X	int n, l;
X	int comp;
X	int totime;
X	int totime2;
X	float f;
X	TempoEvent *te;
X	NoteEvent *ne;
X	InstrumEvent *ie;
X	VolumeEvent *ve;
X	PitchEvent *pe;
X	char pm;
X
X	/* gererate header */
X	fwrite(filler44, 1, 44, fp);
X	fwrite(&ticks_beat, 2, 1, fp);
X	fwrite(&beats_measure, 2, 1, fp);
X	fwrite(filler5, 1, 5, fp);
X	if (ispercussion)
X		pm = 0;
X	else
X		pm = 1;
X	fwrite(&pm, 1, 1, fp);
X	fwrite(filler143, 1, 143, fp);
X	fwrite(&basictempo, 4, 1, fp);
X
X	/* generate tempo track */
X	n = 1;
X	te = hTempoEvent;
X	while (te->next != NULL) {
X		n++;
X		te = te->next;
X	}
X	hTempoEvent->time = 0;
X	hTempoEvent->tempo = 1.0;
X	te = hTempoEvent;
X	if ((n>1) && ((hTempoEvent->next)->time == 0)) {
X		te = te->next;
X		n--;
X	}
X	fwrite(&n, 2, 1, fp);
X	while (te != NULL) {
X		fwrite(te, 6, 1, fp);
X		te = te->next;
X	}
X	/* generate all voice tracks */
X	for (i=0; i<NR_VOICES; i++) {
X		/* note events */
X		fwrite(fillernote, 1, 15, fp);
X		ne = vocs[i].hNoteEvent;
X		ne->offtime = 0;
X		n++;
X		while (ne->next != NULL) {
X			ne = ne->next;
X			n++;
X		}
X		totime = ne->offtime;
X		fwrite(&totime, 2, 1, fp);
X		/*
X		printf("Buildrol voc %d total note time is %d\n", i, totime);
X		*/
X		if (totime > 0) {
X			/* if first note doesn't start at 0 then generate space */
X			totime2 = 0;
X			ne = vocs[i].hNoteEvent;
X			ne = ne->next;
X			if (ne->ontime > 0) {
X				n = 0;
X				fwrite(&n, 2, 1, fp);
X				n = ne->ontime;
X				totime2 += n;
X				fwrite(&n, 2, 1, fp);
X			}
X			ne = vocs[i].hNoteEvent;
X			while (ne->next != NULL) {
X				ne = ne->next;
X				n = ne->note + ne->offset;
X				l = ne->offtime - ne->ontime;
X				comp = 0;
X				if (l > 0) {
X					fwrite(&n, 2, 1, fp);
X					totime2 += l;
X					fwrite(&l, 2, 1, fp);
X				} else {
X					if (ne->next != NULL) {
X						l = ((ne->next)->ontime) - (ne->offtime);
X						if (l > 1) {
X							comp = 1;
X							l = 1;
X							n = ne->note + ne->offset;
X							fwrite(&n, 2, 1, fp);
X							totime2 += l;
X							fwrite(&l, 2, 1, fp);
X						}
X					}
X				}
X				if (ne->next != NULL) {
X					n = 0;
X					l = ((ne->next)->ontime) - (ne->offtime);
X					l -= comp;
X					if (l > 0) {
X						fwrite(&n, 2, 1, fp);
X						totime2 += l;
X						fwrite(&l, 2, 1, fp);
X					}
X				}
X			}
X			/*
X			printf("actual summed time %d\n", totime2);
X			*/
X			if (totime != totime2) {
X				fprintf(stderr, "Inconsistent track length voice:%d last:%d sum:%d\n", i, totime, totime2);
X			}
X		}
X		/* Instrument Events */
X		fwrite(fillerinstrum, 1, 15, fp);
X		ie = vocs[i].hInstrumEvent;
X		n = 0;
X		while (ie->next != NULL) {
X			n++;
X			ie = ie->next;
X		}
X		if (n == 0) {
X			n++;
X			ie = vocs[i].hInstrumEvent;
X			strcpy(ie->instrumName, "piano1");
X			ie->filler = 0;
X			ie->timbreIndex = 0;
X			ie->time = 0;
X		} else {
X			ie = vocs[i].hInstrumEvent;
X			ie = ie->next;
X			ie->time = 0;
X		}
X		/*
X		printf("Buildrol instrum voc %d ninstrum %d\n", i, n);
X		*/
X		fwrite(&n, 2, 1, fp);
X		while (ie != NULL) {
X			/*
X			printf("  instrum %s\n", ie->instrumName);
X			*/
X			fwrite(ie, 14, 1, fp);
X			ie = ie->next;
X		}
X		fwrite(fillervolume, 1, 15, fp);
X		n = 1;
X		fwrite(&n, 2, 1, fp);
X		n = 0;
X		fwrite(&n, 2, 1, fp);
X		f = 0.75;
X		fwrite(&f, 4, 1, fp);
X		fwrite(fillerpitch, 1, 15, fp);
X		n = 1;
X		fwrite(&n, 2, 1, fp);
X		n = 0;
X		fwrite(&n, 2, 1, fp);
X		f = 1.0;
X		fwrite(&f, 4, 1, fp);
X
X	} /* for */
}
main(argc,argv)
char **argv;
{
X	FILE *efopen();
X	FILE *fp;
X	int i,j;
X	long mintime;
X	struct i_event *p;
X	int minidx;
X	char *q;
X	char ofilen[128];
X	char mintype;
X
X	printcopy();
X	if ( argc > 1 )
X		F = efopen(argv[1],"rb");
X	else {
X		fprintf(stderr, "MF2ROL - Covert Standard MIDI File to AdLib .ROL\n");
X		fprintf(stderr, "Usage:\n    mf2rol <midifile> <config-file>\n");
X		exit(1);
X	}
X	ntrules = -1;
X	trulebase = NULL;
X	if (argc > 2)
X		readrules(argv[2]);
X
X	i_ntrks = 0;
X	for (i=0; i<16; i++)
X		for (j=0; j<16; j++)
X			patchmap[i][j] = -1;
X	for (i=0; i<16; i++)
X		chanuse[i] = 0;
X
X	beats_measure = 0;
X	ticks_beat = 12;
X	maxquarter = 0;
X	clocks_click = 0;
X	sper24 = 0;
X	notebeat = 0;
X
X	alloc_base = malloc(CHUNKSIZE);
X	if (alloc_base == NULL)
X		outofmem();
X	alloc_limit = alloc_base + CHUNKSIZE;
X
X	for (i=0; i<MAXTRACK; i++) {
X		i_trkbase[i] = NULL;
X		i_trkptr[i] = NULL;
X	}
X
X	initfuncs();
X	Mf_getc = filegetc;
X	printf("Scanning Midi File: %s\n", argv[1]);
X	midifile();
X	fclose(F);
X	printf("Scanning done.\nChannels used:");
X	for (i=0; i<16; i++)
X		if (chanuse[i])
X			printf(" %d", i+1);
X	printf("\nPatches (programs) used:\n");
X	minidx = 0;
X	for (i=0; i<16; i++)
X		if (patchmap[i][0] != -1) {
X			minidx = 1;
X			printf(" Channel %d:", i+1);
X			for (j=0; j<16; j++)
X				if (patchmap[i][j] != -1)
X					printf(" %d", patchmap[i][j]);
X			printf("\n");
X		}
X	if (minidx == 0)
X		printf(" None.\n");
X
X	/* if no tempo was specified use 120 BPM or 500K microseconds */
X	if (maxquarter == 0)
X		maxquarter = 500000L;
X	maxquarter &= 0xffff00;
X	basictempo = 60000000.0/((float) maxquarter);
X
X	initevent();
X
X	/* play out the events in time-order */
X	printf("Assigning voices.\n");
X	for (i=0; i<i_ntrks; i++)
X		i_trkptr[i] = i_trkbase[i]->next;
X	do {
X		mintime = 0x7fffffffL;
X		mintype = 100;
X		p = NULL;
X		for (i=0; i<i_ntrks; i++) {
X			if (i_trkptr[i] == NULL)
X				continue;
X			if ((i_trkptr[i]->i_time < mintime) ||
X				((i_trkptr[i]->i_time == mintime) && (i_trkptr[i]->type < mintype))) {
X				p = i_trkptr[i];
X				mintime = p->i_time;
X				mintype = p->type;
X				minidx = i;
X			}
X		}
X		if (p != NULL) {
X			putevent(p->i_time, p->trk, p->type, p->chan, p->v1, p->v2);
X			/*
X			printf("Time=%ld Track=%d Event=%d Chan=%d V1=%d V2=%d\n", p->i_time, minidx+1,
X			p->type, p->chan, p->v1, p->v2);
X			*/
X			i_trkptr[minidx] = p->next;
X		}
X	} while (p != NULL);
X	strcpy(ofilen, argv[1]);
X	q = ofilen + strlen(ofilen);
X	while (q > ofilen) {
X		q--;
X		if (*q == '.')
X			break;
X	}
X	if (*q == '.')
X		*q = 0;
X	strcat(ofilen, ".rol");
X	fp = fopen(ofilen, "wb");
X	if (fp == NULL) {
X		fprintf(stderr, "Error: Cannot create output file %s\n", ofilen);
X		exit(1);
X	}
X	printf("Building .ROL file: %s\n", ofilen);
X	buildrol(fp);
X	fclose(fp);
X	printf("Conversion complete.\n");
X	exit(0);
}
X
FILE *
efopen(name,mode)
char *name;
char *mode;
{
X	FILE *f;
X
X	if ( (f=fopen(name,mode)) == NULL ) {
X		(void) fprintf(stderr,"Error: Can't open MIDI file %s.\n",name);
X		exit(1);
X	}
X	return(f);
}
X
error(s)
char *s;
{
X	fprintf(stderr,"Error: %s\n",s);
}
X
txt_header(format,ntrks,div)
{
X	/*
X	printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,div);
X	*/
X	division = div;
}
X
txt_trackstart()
{
X	struct i_event *p;
X	/*
X	printf("Track start\n");
X	*/
X	if (i_ntrks>=MAXTRACK) {
X		fprintf(stderr,"Error: Too many tracks\n");
X		exit(1);
X	}
X	p = getmemEvent();
X	i_trkbase[i_ntrks] = p;
X	i_trkptr[i_ntrks] = p;
X	p->next = NULL;
}
X
txt_trackend()
{
X	/*
X	printf("Track end\n");
X	*/
X	i_ntrks++;
}
X
txt_noteon(chan,pitch,vol)
{
X	struct i_event *p;
X	/*
X	prtime();
X	printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
X	*/
X	i_curr = getmemEvent();
X	p = i_trkptr[i_ntrks];
X	p->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->chan = chan;
X	i_curr->v1 = pitch;
X	i_curr->v2 = vol;
X	i_curr->trk = i_ntrks+1;
X	if (vol == 0)
X		i_curr->type = I_NOTEOFF;
X	else
X		i_curr->type = I_NOTEON;
X	chanuse[chan] = 1;
}
X
txt_noteoff(chan,pitch,vol)
{
X	struct i_event *p;
X	/*
X	prtime();
X	printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
X	*/
X	i_curr = getmemEvent();
X	p = i_trkptr[i_ntrks];
X	p->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->chan = chan;
X	i_curr->v1 = pitch;
X	i_curr->v2 = vol;
X	i_curr->trk = i_ntrks+1;
X	i_curr->type = I_NOTEOFF;
}
X
txt_pressure(chan,pitch,press)
{
X	/*
X	prtime();
X	printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press);
X	*/
}
X
txt_parameter(chan,control,value)
{
X	/*
X	prtime();
X	printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value);
X	*/
}
X
txt_pitchbend(chan,msb,lsb)
{
X	struct i_event *p;
X	/*
X	prtime();
X	printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb);
X	*/
X	/*
X	i_curr = getmemEvent();
X	p = i_trkptr[i_ntrks];
X	p->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->chan = chan;
X	i_curr->v1 = msb;
X	i_curr->v2 = lsb;
X	i_curr->type = I_PITCH;
X	i_curr->trk = i_ntrks+1;
X	*/
}
X
txt_program(chan,program)
{
X	struct i_event *pp;
X	char *p;
X	int i;
X
X	/*
X	prtime();
X	printf("Program, chan=%d program=%d\n",chan+1,program);
X	*/
X	i_curr = getmemEvent();
X	pp = i_trkptr[i_ntrks];
X	pp->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->chan = chan;
X	i_curr->v1 = program;
X	i_curr->type = I_PATCH;
X	i_curr->trk = i_ntrks+1;
X	/* install program number for this channel into patch table */
X	p = &(patchmap[chan][0]);
X	for (i=0; i<16; i++,p++)
X		if (*p == program)
X			return(0);
X	p = &(patchmap[chan][0]);
X	for (i=0; i<16; i++,p++)
X		if (*p == -1) {
X			*p = program;
X			return(0);
X		}
}
X
txt_chanpressure(chan,press)
{
X	struct i_event *p;
X	/*
X	prtime();
X	printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press);
X	*/
X	/*
X	i_curr = getmemEvent();
X	p = i_trkptr[i_ntrks];
X	p->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->chan = chan;
X	i_curr->v1 = press;
X	i_curr->type = I_PRESSURE;
X	i_curr->trk = i_ntrks+1;
X	*/
}
X
txt_sysex(leng,mess)
char *mess;
{
X	/*
X	prtime();
X	printf("Sysex, leng=%d\n",leng);
X	*/
}
X
txt_metamisc(type,leng,mess)
char *mess;
{
X	/*
X	prtime();
X	printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng);
X	*/
}
X
txt_metaspecial(type,leng,mess)
char *mess;
{
X	/*
X	prtime();
X	printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng);
X	*/
}
X
txt_metatext(type,leng,mess)
char *mess;
{
X	static char *ttype[] = {
X		NULL,
X		"Text Event",           /* type=0x01 */
X		"Copyright",            /* type=0x02 */
X		"Track Name",
X		"Instrument",           /* ...       */
X		"Lyric",
X		"Marker",
X		"Cue Point",            /* type=0x07 */
X		"Unrecognized"
X	};
X	int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
X	register int n, c;
X	register char *p = mess;
X
X	if ( type < 1 || type > unrecognized )
X		type = unrecognized;
X	printf(" Trk:%2d: %s: ",i_ntrks+1, ttype[type]);
X	for ( n=0; n<leng; n++ ) {
X		c = *p++;
X		printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
X	}
X	printf("\n");
}
X
txt_metaseq(num)
{
X	/*
X	prtime();
X	printf("Meta event, sequence number = %d\n",num);
X	*/
}
X
txt_metaeot()
{
X	/*
X	prtime();
X	printf("Meta event, end of track\n");
X	*/
}
X
txt_keysig(sf,mi)
{
X	/*
X	prtime();
X	printf("Key signature, sharp/flats=%d  minor=%d\n",sf,mi);
X	*/
}
X
txt_tempo(long tempo)
{
X	struct i_event *p;
X	/*
X	prtime();
X	printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo);
X	*/
X	i_curr = getmemEvent();
X	p = i_trkptr[i_ntrks];
X	p->next = i_curr;
X	i_curr->next = NULL;
X	i_trkptr[i_ntrks] = i_curr;
X
X	i_curr->i_time = Mf_currtime;
X	i_curr->trk = i_ntrks+1;
X	i_curr->chan = 0;
X	i_curr->v1 = (tempo>>16) & 0xff;
X	i_curr->v2 = (tempo>>8) & 0xff;
X	i_curr->type = I_TEMPO;
X	if (tempo > maxquarter)
X		maxquarter = tempo;
}
X
txt_timesig(nn,dd,cc,bb)
{
X	int denom = 1;
X	while ( dd-- > 0 )
X		denom *= 2;
X	/*
X	prtime();
X	printf("Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d\n",
X		nn,denom,cc,bb);
X	*/
X	if (nn > beats_measure) {
X		beats_measure = nn;
X		notebeat = denom;
X		clocks_click = cc;
X		sper24 = bb;
X	}
}
X
txt_smpte(hr,mn,se,fr,ff)
{
X	/*
X	prtime();
X	printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
X		hr,mn,se,fr,ff);
X	*/
}
X
txt_arbitrary(leng,mess)
char *mess;
{
X	/*
X	prtime();
X	printf("Arbitrary bytes, leng=%d\n",leng);
X	*/
}
X
prtime()
{
X	/*
X	printf("Time=%ld  ",Mf_currtime);
X	*/
}
X
printcopy()
{
X	static char notice[] = "MIDI File to .ROL converter.  V1.1   A. A. Kapauan 1991";
X	fprintf(stderr, "\n%s\n\n", notice);
}
X
initfuncs()
{
X	Mf_error = error;
X	Mf_header =  txt_header;
X	Mf_trackstart =  txt_trackstart;
X	Mf_trackend =  txt_trackend;
X	Mf_noteon =  txt_noteon;
X	Mf_noteoff =  txt_noteoff;
X	Mf_pressure =  txt_pressure;
X	Mf_parameter =  txt_parameter;
X	Mf_pitchbend =  txt_pitchbend;
X	Mf_program =  txt_program;
X	Mf_chanpressure =  txt_chanpressure;
X	Mf_sysex =  txt_sysex;
X	Mf_metamisc =  txt_metamisc;
X	Mf_seqnum =  txt_metaseq;
X	Mf_eot =  txt_metaeot;
X	Mf_timesig =  txt_timesig;
X	Mf_smpte =  txt_smpte;
X	Mf_tempo =  txt_tempo;
X	Mf_keysig =  txt_keysig;
X	Mf_seqspecific =  txt_metaspecial;
X	Mf_text =  txt_metatext;
X	Mf_arbitrary =  txt_arbitrary;
}
SHAR_EOF
chmod 0664 mf2rol/mf2rol.c ||
echo 'restore of mf2rol/mf2rol.c failed'
Wc_c="`wc -c < 'mf2rol/mf2rol.c'`"
test 26278 -eq "$Wc_c" ||
	echo 'mf2rol/mf2rol.c: original size 26278, current size' "$Wc_c"
fi
# ============= mf2rol/readme.txt ==============
if test -f 'mf2rol/readme.txt' -a X"$1" != X"-c"; then
	echo 'x - skipping mf2rol/readme.txt (File already exists)'
else
echo 'x - extracting mf2rol/readme.txt (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mf2rol/readme.txt' &&
Sept 1992.
Here's the source code of the mf2rol program. It was written for DOS
and the Microsoft C compiler V6.0 about 2 years ago. Before submitting this
to the archive I made sure the source compiled clean. Unfortunately, I
blew away C 6.0 to make room for C/C++ 7.0, so I made a couple of changes
to remove all compiler warning messages.
X
Please take note that this code was not written to be portable. If you will
observe, the .ROL file contains some (binary) floating point values which
are probably processor dependent. Of course, you may attempt a port, but
you're on your own. This code is provided as-is and without warranty or
support. And, please don't ask me for the .ROL file spec. -- I just reverse-
engineered the format using a .ROL reader I had come across.
X
Thanks to Tim Thompson for providing the MIDI file reader code. I basically
hacked mftext and stuffed in the necessary stuff to build the event list
needed to create the .ROL file.
X
A. Kapauan aak@iexist.att.com
SHAR_EOF
chmod 0664 mf2rol/readme.txt ||
echo 'restore of mf2rol/readme.txt failed'
Wc_c="`wc -c < 'mf2rol/readme.txt'`"
test 1008 -eq "$Wc_c" ||
	echo 'mf2rol/readme.txt: original size 1008, current size' "$Wc_c"
fi
exit 0
