#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 6)."
# Contents:  cmdline.c phase2.c timdif.asm trans2.c
# Wrapped by lee@uhccux on Wed Mar 29 09:58:09 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cmdline.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmdline.c'\"
else
echo shar: Extracting \"'cmdline.c'\" \(10438 characters\)
sed "s/^X//" >'cmdline.c' <<'END_OF_FILE'
X/* cmdline.c -- command line parsing routines */
X/*
X * This module is designed to allow various modules to scan (and rescan)
X * the command line for applicable arguments.  The goal is to hide as
X * much information about switches and their names as possible so that
X * switches become more consistent across applications and so that the
X * author of an application need not do a lot of work to provide numerous
X * options.  Instead, each module scans the command line for its own
X * arguments.
X *
X * Command lines are of the following form:
X *	command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3
X * Note that there are three kinds of command line parameters:
X * (1) A Switch is a "-" followed by a name, e.g. "-s1"
X * (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2"
X * (3) An Argument is a name by itself, e.g. "arg1"
X * Note also that a switch followed by an argument looks just like an
X * option, so a list of valid option names is necessary to disambiguate.
X *
X * A main program that uses cmdline.c should do the following:
X *	(1) create an array of pointers to strings (char *names[]) that
X *		contains every possible option name
X *	(2) create another array of pointers to strings that contains
X *		every possible switch name
X *	(2) call cl_init(switches, nsw, options, nopt, argv, argc)
X * cl_init will report an error (to stderr) if it finds any illegal
X * switch or option names.
X *
X * Afterward, switches, options, and arguments can be accessed by
X * calling cl_switch, cl_option, and cl_arg.  If cl_switch or cl_option
X * is called with a switch name that was not mentioned in the call to 
X * cl_init, an error will result.  This indicates that the application
X * author omitted a valid switch or option name when calling cl_init.
X * This is an error because the full set of names is needed for error
X * checking and to distinguish arguments from options.
X *
X * cl_nswitch and cl_noption are similar to cl_switch and cl_option,
X * except they each take a list of equivalent switch or option names.  
X * This makes it simple to allow both verbose (-debug) and terse (-d) names.
X */
X
X/*****************************************************************************
X*	    Change Log
X*  Date	    | Change
X*-----------+-----------------------------------------------------------------
X* 13-Jun-86 | Created Change Log
X*  6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines
X*****************************************************************************/
X
X#include "cext.h"
X#include "stdio.h"
X#include "cmdline.h"
X
Xprivate char **voptions;	/* valid options */
Xprivate int noptions;		/* number of options */
Xprivate char **vswitches;	/* valid switches */
Xprivate int nswitches;		/* number of switches */
Xprivate char **argv;		/* command line argument vector */
Xprivate int argc;		/* length of argv */
X
Xprivate int cl_rdy = false;	/* set to true when initialized */
X
X/*****************************************************************************
X*	Routines local to this module
X*****************************************************************************/
Xprivate	void	check_names();
Xprivate int	find_match();
Xprivate int	find_string();
Xprivate	void	ready_check();
X
X/****************************************************************
X*			check_names
X* Inputs:
X*	char *names[]:	array of alternative switch or option names
X*	int nnames:	number of alternative switch or option names
X*	char *valid[]:	array of valid names
X*	int nvalid:	number of valid names
X* Effect:
X*	Checks that all names are in validnames.  If not, print
X*	an error message.
X*****************************************************************/
X
Xprivate void check_names(names, nnames, valid, nvalid)
X    char *names[];
X    int nnames;
X    char *valid[];
X    int nvalid;
X{
X    int i;	/* loop counters */
X    for (i = 0; i < nnames; i++) {
X	if (find_string(names[i], valid, nvalid) >= nvalid) {
X	    fprintf(stderr, "internal error detected by cmdline module:\n");
X	    fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]);
X	}
X    }
X}
X
X/****************************************************************
X*			cl_arg
X* Inputs:
X*	n: the index of the arg needed
X* Results:
X*	pointer to the nth arg, or NULL if none exists
X*	arg 0 is the command name
X*****************************************************************/
X
Xchar *cl_arg(n)
X    int n;
X{
X    int i = 1;
X    if (n <= 0) return argv[0];
X    while (i < argc) {
X	if (*argv[i] == '-') {
X	    if (find_string(argv[i], voptions, noptions) < noptions)
X		i += 2; /* skip name and option */
X	    else i += 1; /* skip over switch name */
X	} else if (n == 1) {
X	    return argv[i];
X	} else { /* skip over argument */
X	    n--;
X	    i++;
X	}
X    }
X    return NULL;
X}
X
X/*****************************************************************************
X*			cl_init
X* Inputs:
X*	char *switches[]:	array of switch names
X*	int nsw:		number of switch names
X*	char *options[]:	array of option names
X*	int nopt:		number of option names
X*	char *av:		array of command line fields (argv)
X*	int ac:			number of command line fields (argc)
X* Effect:
X*	Checks that all command line entries are valid.
X*	Saves info for use by other routines.
X* Returns:
X*	True if syntax checks OK, otherwise false
X*****************************************************************************/
X
Xboolean cl_init(switches, nsw, options, nopt, av, ac)
X    char *switches[];
X    int nsw;
X    char *options[];
X    int nopt;
X    char *av[];
X    int ac;
X{
X    int i;	/* index into argv */
X    boolean result = true;
X
X    vswitches = switches;	nswitches = nsw;
X    voptions = options;		noptions = nopt;
X    argv = av;			argc = ac;
X
X    for (i = 1; i < argc; i++) {  /* case fold lower */
X	int j;
X	for (j = 0; j < strlen(argv[i]); j++)
X	    argv[i][j] = tolower(argv[i][j]);
X    }
X
X    /* check command line syntax: */
X    i = 1;
X    while (i < argc) {
X	if (*argv[i] == '-') {
X	    if (find_string(argv[i], voptions, noptions) < noptions) {
X		i += 1; /* skip name and option */
X		if (i < argc && *argv[i] == '-') {
X		    fprintf(stderr, "missing argument after %s\n", argv[i-1]);
X		    result = false;
X		    i += 1;
X		}
X	    } else if (find_string(argv[i], vswitches, nswitches) < 
X		       nswitches) {
X		i += 1; /* skip over switch name */
X	    } else {
X		fprintf(stderr, "invalid switch: %s\n", argv[i]);
X		i += 1;
X		result = false;
X	    }
X	} else i++; /* skip over argument */
X    }
X    cl_rdy = true;
X    return result;
X}
X
X/****************************************************************
X*			cl_noption
X* Inputs:
X*	char *names[]:	array of alternative switch names
X*	int nnames:	number of alternative switch names
X* Result:
X*	returns pointer to  if one exists, otherwise null
X* Effect:
X*	looks for pattern in command line of the form "-n s",
X*	where n is a member of names.  Returns pointer to s.
X* Implementation:
X*	find the option name, then
X*	see if the switch is followed by a string that does
X*	not start with "-"
X*****************************************************************/
X
Xchar *cl_noption(names, nnames)
X    char *names[];
X    int nnames;
X{
X    int i;	/* index of switch */
X
X    ready_check();
X    check_names(names, nnames, voptions, noptions);
X    i = find_match(names, nnames) + 1; /* point at the option */
X    if (i < argc) { /* make sure option exists */
X	if (*(argv[i]) != '-') return argv[i];
X    }
X    return NULL;
X}
X
X/*****************************************************************
X*			cl_nswitch
X* Inputs:
X*	char *names[]:	array of alternative switch names
X*	int nnames:	number of alternative switch names
X* Effect:
X*	Checks that names is valid.
X*	Finds a pattern in command line of the form "-n", where
X*	n is a member of names.
X* Result:
X*	returns pointer to command line switch if one exists,
X*	otherwise null
X*****************************************************************/
X
Xchar *cl_nswitch(names, nnames)
X    char *names[];
X    int nnames;
X{
X    int i;	/* index of switch */
X
X    ready_check();
X    check_names(names, nnames, vswitches, nswitches);
X    i = find_match(names, nnames);
X    if (i < argc) return argv[i];
X    /* else */ return NULL;
X}
X
X/****************************************************************
X*			cl_option
X* Inputs:
X*	char *name:	option name
X* Outputs:
X*	returns char *: the option string if found, otherwise null
X****************************************************************/
X
Xchar *cl_option(name)
X    char *name;
X{
X    char *names[1];	/* array to hold name */
X
X    names[0] = name;
X    return cl_noption(names, 1);
X}
X
X/****************************************************************
X*			cl_switch
X* Inputs:
X*	char *name:	switch name
X* Outputs:
X*	boolean:	true if switch found
X****************************************************************/
X
Xboolean cl_switch(name)
X    char *name;
X{
X    char *names[1];	/* array to hold name */
X
X    names[0] = name;
X    return cl_nswitch(names, 1) != NULL;
X}
X
X/****************************************************************
X*			find_match
X* Inputs:
X*	char *names[]:	array of alternative switch or option names
X*	int nnames:	number of alternative switch or option names
X* Effect:
X*	Looks for command line switch that matches one of names.
X* Returns:
X*	Index of switch if found, argc if not found.
X*****************************************************************/
X
Xprivate int find_match(names, nnames)
X    char *names[];
X    int nnames;
X{
X    int j;	/* loop counter */
X    for (j = 0; j < argc; j++) {
X	if (find_string(argv[j], names, nnames) < nnames) return j;
X    }
X    return argc;
X}
X
X/****************************************************************
X*			find_string
X* Inputs:
X*	char *s:	string to find
X*	char *names[]:	array of strings
X*	int nnames:	number of strings
X* Effect:
X*	Looks for s in names
X* Returns:
X*	Index of s in names if found, nnames if not found
X*****************************************************************/
X
Xprivate int find_string(s, names, nnames)
X    char *s;
X    char *names[];
X    int nnames;
X{
X    int i; /* loop counter */
X    for (i = 0; i < nnames; i++) {
X	if (strcmp(s, names[i]) == 0) {
X	    return i;
X	}
X    }
X    return nnames;
X}
X
X/****************************************************************
X*			ready_check
X* Effect:
X*	Halt program if cl_rdy is not true.
X*****************************************************************/
Xprivate void ready_check()
X{
X    if (!cl_rdy) {
X	fprintf(stderr,
X	    "Internal error: cl_init was not called, see cmdline.c\n");
X	exit(1);
X    }
X}
END_OF_FILE
if test 10438 -ne `wc -c <'cmdline.c'`; then
    echo shar: \"'cmdline.c'\" unpacked with wrong size!
fi
# end of 'cmdline.c'
fi
if test -f 'phase2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'phase2.c'\"
else
echo shar: Extracting \"'phase2.c'\" \(10058 characters\)
sed "s/^X//" >'phase2.c' <<'END_OF_FILE'
X/* phase2.c -- this module plays notes compiled and sorted in phase1 */
X
X/*****************************************************************************
X*	    Change Log
X*  Date	    | Change
X*-----------+-----------------------------------------------------------------
X* 31-Dec-85 | Created changelog
X* 31-Dec-85 | Add c:\ to include directives
X* 31-Dec-85 | Changed to use new CBREAK as well as kbhit
X*  1-Jan-86 | Added stop_reason
X*  1-Jan-86 | <rgd/jmn> Require musicfns.h before adagio.h
X*	    | stop_time is now long
X*	    | Turn off all notes in moreclean
X*	    | changed control logic in play
X*  1-Jan-86 | Added miditrace
X*  1-Jan-86 | Added command scanner at play request level
X* 18-Jan-86 | Gave priority to note offs.
X*	    | Created stop_check routine.
X* 21-Jan-86 | Added mpu_error_check to main loop
X*  3-Feb-86 | Changed help message slightly
X* 24-Mar-86 | Changed representation from note_struct to event_struct
X* 16-Jul-86 | Only pass upper case letters to tolower()
X*  7-Aug-86 | Initialize bend, touch, porta, mod, and foot controls
X*****************************************************************************/
X
X#include "cext.h"
X#include "stdio.h"
X#include "ctype.h"
X#include "adagio.h"
X#include "mpu.h"
X#include "userio.h"
X#include "phase2.h"
X
X#define stop_code ' '
Xchar stop_explanation[] = "Space bar";
X
Xextern int musictrace;
Xextern int miditrace;
Xextern int CBREAK;
X
X#define STOP_CC 1
X#define STOP_CBRK 2
X#define STOP_KEY 3
X
Xprivate long offset = 100;	/* time offset from clock to performance */
X
Xprivate int program[num_voices];	/* current program */
X
X/****************************************************************************
X* Routines local to this module
X****************************************************************************/
Xprivate	void	init_stuff();
Xprivate	void	moreclean();
Xprivate	void	play();
Xprivate	void	play_help();
Xprivate	void	print_status();
Xprivate boolean stop_check();
X
X/****************************************************************************
X*				  init_stuff
X* Effect: initializes this module (called by phase2()).
X****************************************************************************/
X
Xprivate void init_stuff()
X{
X    off_init();
X}
X
X/****************************************************************************
X*				moreclean
X* Inputs:
X*	event_type root: the score that was in progress
X*	int stop_reason: the reason the score was stopped
X* Effect: 
X*	prints a message to announce stopped state
X*	tells what was playing at the stop time
X* Implementation:
X*	What was playing is determined by reading the time and searching
X*	for notes that are on at that time.  If nothing is found on a
X*	given channel, it would be nice to print the last note played
X*	on the channel provided it was played within say 1 sec of the
X*	stop time.  This is unimplemented, but would help locate short
X*	notes.
X****************************************************************************/
X
Xprivate void moreclean(score, stop_reason)
X    event_type score;
X    int stop_reason;
X{
X    long stop_time;	/* time at which moreclean is called */
X    event_type n;	/* used to search the score */
X
X    stop_time = gettime() - offset;	/* get current time */
X
X    while (note_offs(0x7fffffff)) ;	/* turn off all notes */
X
X    printf ("\n	     * * STOPPED * *\n");
X
X    switch(stop_reason)
X       { /* reason for stopping */
X	case STOP_CC:	printf("Control-C seen\n");
X			break;
X	case STOP_CBRK: printf("Control-break seen\n");
X			break;
X	case STOP_KEY:	printf("%s hit\n",stop_explanation);
X			break;
X       } /* reason for stopping */
X
X    if (stop_time > 0)
X	printf ("Stopped at time = %ld (hundreths of a second). \n\n",
X		stop_time);
X
X    for (n = score; n != NULL; n = n->next) {
X	if (is_note(n) &&
X	    (n->ntime <= stop_time) &&
X	    (n->ntime + n->u.note.ndur) >= stop_time) {
X	    printf("Voice: %d was playing line: %d\n",
X		n->nvoice + 1, n->nline);
X	}
X    }
X}
X
X/****************************************************************************
X*				    phase2
X* Inputs:
X*	event_type root: Root of play list
X* Effect: 
X*	Plays the music
X****************************************************************************/
X
Xvoid phase2(root)
X    event_type root;
X{
X    char resp;
X    short done = false;
X    int truth;
X
X    init_stuff();
X    while (!done) { /* ask user */
X	truth = true;
X	printf ("\nType <RETURN> to play notes, q<RETURN> to quit, ?<RETURN> for help:");
X	while (true) { /* read input */
X	    resp = getchar();
X	    if (isupper(resp)) resp = tolower(resp);
X	    switch (resp) { /* decode */
X		case ' ':
X		    continue;	/* ignore spaces */
X		case '?': 
X		    play_help();
X		    readln(stdin);
X		    break;
X		case '-':
X		    truth = !truth;
X		    continue;	/* read next char */
X		case 't':
X		    trace(truth);
X		    readln(stdin);
X		    break;
X		case 'm':
X		    tracemidi(truth);
X		    readln(stdin);
X		    break;
X		case 'q':
X		    done = true;
X		    readln(stdin);
X		    break;
X		case 'r':
X		    readln(stdin);
X		    read_tuning("");
X		    break;
X		case 's':
X		    print_status();
X		    readln(stdin);
X		    break;
X		case '\n':
X		    CBREAK = 0;
X		    play(root);
X		    break;
X	    } /* decode */
X	    break;
X	} /* read input */
X    } /* ask user */
X}
X
X/****************************************************************************
X*				     play
X* Inputs:
X*	event_type score: Score to play
X* Effect: 
X*	Plays the score
X****************************************************************************/
X
Xprivate void play(score)
X    event_type score;
X{	
X    event_type event = score;	/* pointer to next note or control event */
X    short done = false;
X    int stop_reason;		/* ctrl-C, break, or space bar */
X    long time;			/* the current time */
X    int i;			/* index counter to initialize channels */
X
X    printf("Type %s to stop.\n",stop_explanation);
X
X    musicinit();  
X
X    /* Initialize all midi channels with reasonable start values: */
X    for (i = 1; i <= num_voices; i++) {
X	midi_program(i, 1);
X	program[i - 1] = 1;
X	midi_bend(i, 1 << 13);
X	midi_touch(i, 0);
X	midi_ctrl(i, PORTARATE, 99);
X	midi_ctrl(i, PORTASWITCH, 0);
X	midi_ctrl(i, MODWHEEL, 0);
X	midi_ctrl(i, FOOT, 99);
X    }
X
X    timereset();
X    l_restuntil(offset);
X
X    while (!done) { /* play it, Sam */
X	time = gettime() - offset; /* delay everything by offset */
X	done = true;
X	if (note_offs(time)) done = false;	/* still more note offs */
X	if (event != NULL) {  /* something to play */
X	    done = false;
X	    if (time >= event->ntime) {
X		if (is_note(event)) { /* play a note */
X		    /* check for correct program (preset) */
X		    if (event->u.note.nprogram != program[event->nvoice]) {
X			midi_program(event->nvoice+1, event->u.note.nprogram);
X			 program[event->nvoice] = event->u.note.nprogram;
X		    }
X		    /* if it is a note (not a rest) play it */
X		    if (event->u.note.npitch != NO_PITCH) {
X			midi_note(event->nvoice+1, event->u.note.npitch,
X				  event->u.note.nloud);
X			off_schedule(event->ntime + event->u.note.ndur,
X				     event->nvoice, event->u.note.npitch);
X		    }
X		} else {	/* send control info */
X		    switch (vc_ctrl(event->nvoice)) {
X			case 1: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     PORTARATE,
X					     event->u.ctrl.value);
X				break;
X			case 2: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     PORTASWITCH,
X					     event->u.ctrl.value);
X				break;
X			case 3: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     MODWHEEL,
X					     event->u.ctrl.value);
X				break;
X			case 4: midi_touch(vc_voice(event->nvoice) + 1,
X					   event->u.ctrl.value);
X				break;
X			case 5: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     FOOT,
X					     event->u.ctrl.value);
X				break;
X			case 6: midi_bend(vc_voice(event->nvoice) + 1,
X					  event->u.ctrl.value << 6);
X				break;
X			default: break;
X		    }
X		}
X		event = event->next;
X	    } else if (CBREAK || kbhit()) {
X		done = stop_check(&stop_reason);
X		if (done) { /* clean up */
X		    moreclean(score, stop_reason);
X		} /* clean up */
X	    } else mpu_error_check();
X	} /* something to play */
X    } /* play it, Sam */
X
X    musicterm();
X}
X
X/****************************************************************************
X*				   play_help
X* Effect: 
X*	Lists help for play option
X****************************************************************************/
X
Xprivate void play_help()
X{
X    fprintf(stderr," <return>	   Play music\n");
X    fprintf(stderr," q<return>	   Quit Adagio (Exit)\n\n");
X    fprintf(stderr," r<return>	   Read tuning file\n");
X    fprintf(stderr," m<return>	   Turn on MIDI byte trace\n");
X    fprintf(stderr,"-m<return>	   Turn off MIDI byte trace\n");
X    fprintf(stderr," s<return>	   Report state\n");
X    fprintf(stderr," t<return>	   Turn on music operation trace\n");
X    fprintf(stderr,"-t<return>	   Turn off music operation trace\n");
X    fprintf(stderr," ?<return>	   This message\n");
X}
X
X/****************************************************************************
X*				  print_status
X* Effect: 
X*	Informative output about state
X****************************************************************************/
X
Xprivate void print_status()
X{
X    fprintf(stderr,"MIDI trace (m option) %s\n",(miditrace ? "on" : "off"));
X    fprintf(stderr,"Music trace (t option) %s\n",(musictrace ? "on" : "off"));
X}
X
X/****************************************************************************
X*				     stop_check
X* Outputs:
X*	*reason is set to reason for stop
X*	true is returned iff play should stop
X* Effect: 
X*	Checks for break character or stop code from kbd
X****************************************************************************/
X
Xprivate boolean stop_check(reason)
X    int *reason;
X{
X    boolean done = false;
X    switch (CBREAK) { /* stop reason */
X	case 0: /* no stop code, try keyboard */
X	    done = (getch() == stop_code);
X	    if (done) *reason = STOP_KEY;
X	    break;
X	case 1: /* ctrl-break */
X	    done = true;
X	    if (kbhit()) getch();
X	    *reason = STOP_CBRK;
X	    break;
X	case 2: /* ctrl-C */
X	    done = true;
X	    *reason = STOP_CC;
X	    if (kbhit()) getch();
X	    break;
X    } /* stop reason */
X    return done;
X}
END_OF_FILE
if test 10058 -ne `wc -c <'phase2.c'`; then
    echo shar: \"'phase2.c'\" unpacked with wrong size!
fi
# end of 'phase2.c'
fi
if test -f 'timdif.asm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'timdif.asm'\"
else
echo shar: Extracting \"'timdif.asm'\" \(12902 characters\)
sed "s/^X//" >'timdif.asm' <<'END_OF_FILE'
X;version 1 released 6-10-86
X	title timdif - real time at different than clock rate
Xdebug=-1 ;set to -1 to turn on debugging code
X;written by Aaron Wohl
X;       for Roger Dannerberg
X;        at The Center for the Arts and technolagy
X;           Carnegie Mellon University
X;	    5000 Forbes Ave
X;	    Pittsburgh, PA 15xxx
X;
X;change log:
X; Jun 10 86 avw	  - release version 1
X; Jun 04 86 avw	  - create from wohl's personal timer.asm
X;
X;this module provides a 32bit timer that counts at a rate different than
X;the ~54ms time provided by the bios.  It is currently configured to
X;count in 10ms tics.
X;
X;The idea is to do subtractions and keep a remainder instead of dividing
X;the bios and timer chip time to save divide or multiply instructions.
X;This is probably only a good idea if the rate you want is near the
X;bios rate.
X;
X;things to do:
X; change dodiv to be alot smarter and faster.  it currently loops
X; subtracting divr from rem, instead subtract 3*divr and see if there
X; is a borrow and go from there.  this will decrease the maximum divide time.
X
X;************************************************************************
X;*									*
X;*	Module interface specifications					*
X;*									*
X;************************************************************************
X; ibm_time - this routine is the reason this module exists, it returns the
X;	   current time in 10ms tics.
X;     note:ibm_time() may not be called with interupts disabled
X;usage: unsigned long i,ibm_time(); i=ibm_time();
X;
X; cletime - stop our timer.  crash the system if timer not currently running.
X;usage: cletime();
X;
X; settime - zero our timer and start counting.  crash the system if our timer
X;	   is already running.
X;	   if debbuging, also zero the value gettic() returns (see gettic)
X;usage: settime();
X;
X; overall usage:
X;  a) call settime() to start the timer
X;  b) call ibm_time() as many times as you like to get the time.
X;  c) call cletime() to stop timing
X;  d) exit the program, or if you like, goto step a)
X
X;************************************************************************
X;*									*
X;*	Module debug interface specifications				*
X;*									*
X;************************************************************************
X; gettic - return high precision (8253 counter 0) reading from when
X;	   the latest interupt happened.  latest meaning the most late, the
X;	   interupt delayed for the longest time. usefull for debugging to see
X;	   if someone is leaving the interups off for too long.
X;     note:we must be called with debug on for gettic to function, always
X;	   returns zero otherwise
X; usage: int i,getic(); i=gettic();
X;
X; getbtim - return the 32bit bios time (it counts in ~54ms tics).
X;	    usefull for debugging.  since the rest of this module runs
X;	    off the same clock, this time (when converted to 10ms ticks)
X;	    should never be more then 6 (10ms) ticks different.
X;usage: unsigned long i,getbtim(); i=getbtim();
X;
X
X;************************************************************************
X;*									*
X;*	Timeing constants, linkages, libraries				*
X;*									*
X;************************************************************************
X
Xdivr	equ 3054545		;divider for 11931.81667 to get 10ms
Xdivlow	equ 09bd1h		;low word of divr
Xdivhig	equ 0002eh		;high word of divr
X
X	include macsym.lib	;control constructs
X	include prcsym.lib	;procedure data declarators
X	cmods_			;set linkage mode to c small model
X
X
X;************************************************************************
X;*									*
X;*	data global to timdif						*
X;*									*
X;************************************************************************
X
X;define memory location of timer interupt vector
Xivec	segment at 0
X	org	8h*4
Xtimvec	label word
Xivec	ends
X
X	dseg timdat
X	if debug
Xtictim	dw 0			;remeber when ticks happen
X	endif
X
X;remainder from previous divisions as a 32 bit number low byte to high byte
X;also, used to remember part of current second already used
Xrem	label dword
Xrem0w	label word		;a few names for things since we
Xrem0b	db 0			; sometimes do byte operations and sometimes
Xrem1w	label word		; do word operations
Xrem1b	db 0
Xrem2w	label word
Xrem2b	db 0
Xrem3b	db 0
X
Xnow	label dword			;current time in our units
Xnow0w	dw 0				;for returning result to user
Xnow2w	dw 0
X	endds
X
X
X	pseg prog
X;************************************************************************
X;*									*
X;*	dodiv - divide bx(low word) ax(high word)			*
X;*		by tivr							*
X;*		result in cx, remainder in ax,bx
X;*									*
X;*									*
X;************************************************************************
X
X;do divide
Xdodiv	proc near
X	mov cx,0		;initilize result of division
X	do_
X	 inc cx			;divide happend one more time
X	 sub bx,divlow
X	 sbb ax,divhig
X	 jnc top_		;loop till we borrow
X	od_
X	dec cx			;correct for going once to many times
X	add bx,divlow		;undo last subtract
X	adc ax,divhig
X	ret
Xdodiv	endp
X
X;************************************************************************
X;*									*
X;*	Timer routine to piggy back on bios timer interupt		*
X;*	data addressed by cs for interupt routine			*
X;*									*
X;************************************************************************
X
Xromwd	label word		;word address of rom tim
Xromtim	dd ?			;rom timer interupt address
Xtimds	dw ?			;data segment for timer routines
X
X;************************************************************************
X;*									*
X;*	Macro to read time into ax					*
X;*	This is not a routine to save the subroutine call overhead	*
X;*									*
X;************************************************************************
Xtimprt	equ 040h		;timer 0 port
Xtimcmd	equ (timprt+3)		;timer control port
Xlatcmd	equ 000h		;command to latch a time, timer 0
Xmodcmd	equ 034h		;set to mode 2 instead of mode 3
X
X;************************************************************************
X;*									*
X;*	Routine to return to user, when the latest timer tick happened	*
X;*									*
X;************************************************************************
X	public gettic
X	prcent gettic
X	if debug
X	  mov ax,tictim
X	else
X	  xor ax,ax
X	endif
X	prcexi gettic		;return the tic time to lattice c
X
X;************************************************************************
X;*									*
X;*	Routine for returning the current bios time			*
X;*	getbtim - return a 32bit time in our bios tics			*
X;*	only used to check our accuracy					*
X;*									*
X;************************************************************************
X	public getbtim
X	prcent getbtim,,,<,ds>
X	mov ax,040h		;address of rom data
X	mov ds,ax
X	cli
X	mov bx,ds:[06ch]	;get high and low words of the time
X	mov ax,ds:[06eh]
X	sti
X	prcexi getbtim		;return the time to lattice c
X
X;read a latched time into cx cl=low, cx=high
XREDTIM	macro
X	mov al,latcmd		;latch a timer
X	out timcmd,al		;send command to 8153
X	in al,timprt		;get low byte of time
X	mov cl,al		;save it
X	in al,timprt		;get high byte of the time
X	mov ch,al
X	neg cx
X	endm
X
X
X;************************************************************************
X;*									*
X;*	Routine for returning the current time				*
X;*	ibm_time - return a 32bit time in our units			*
X;*									*
X;************************************************************************
X	public ibm_time
X	prcent ibm_time
X
X	do_
X	 push es		;free up es to point to
X	 mov ax,040h		;address of rom data
X	 mov es,ax
X	 cli
X	 REDTIM			;read timer into ax
X	 sti			;do next instruction, then ints on
X	 mov bx,es:[06ch]	;(interupts off here, see sti def) get time
X	 cli
X	 cmp bx,es:[06ch]	;time change? set z flag if ok
X	 pop es
X	 jnz top_		;if time changed then counter is wrong
X	od_
X;note: interupts are off when exiting the loop! so that now doesn't
X;      get bashed on by the timer interupt code while we are updating it
X;note: the 8253 timer counts down, so ax has the negative of the part of
X;      the tick
X	mov bx,rem0w		;get low word of remainder
X	mov ax,rem2w		;get high word
X	add bh,cl
X	adc al,ch
X	adc ah,0
X
X	call dodiv		;fixup now to be correct
X
X	add cx,now0w		;get now plus part of tick
X	mov ax,0
X	adc ax,now2w
X	sti			;done, allow interupts now
X	mov bx,cx		;put low bits where lattice c wants them
X	prcexi ibm_time         ;return bx,ax (current time)
X
X;************************************************************************
X;*									*
X;*	Routine for stopping our timer					*
X;*	cletime - stop timer remove patch into bios timer		*
X;*									*
X;************************************************************************
X
X;clear the timer interupt routine
X	public cletime
X	prcent cletime,,,<,ds>
X	assume ds:ivec		;address current vectors
X	mov ax,ivec
X	mov ds,ax
X	
X	cli
X	mov ax,romwd
X	mov timvec,ax		;restore original interupt vector
X	mov ax,romwd[2]
X	mov timvec[2],ax
X	sti
X	
X	assume ds:dgroup
X	prcexi cletime
X;************************************************************************
X;*									*
X;*	Routine for starting our timer					*
X;*	settime - zero now (time starts from zero), also patch into	*
X;*		 bios timer interupt so we can call timint on each	*
X;*		 timer tick						*
X;*									*
X;************************************************************************
X
X	public settime
X	prcent settime,,,<,ds>
X
X	xor ax,ax		;get a zero
X	if debug
X	 mov tictim,ax		;clear latest tick time
X	endif
X	mov now0w,ax		;clear now
X	mov now2w,ax
X	mov rem0w,ax		;clear remainder
X    	mov rem2w,ax
X
X;change the timer to mode 2 (rate generator ) so we can see what part of the
X;current tick we are in.  the rom sets it to mode 3 (square wave).  mode 3
X;counts by two then twidiles the counter output line.  thus if read the
X;timer you can't tell which half of the tick you are in.  mode 2 counts
X;by one then gives a one clock pulse tick, which is just fine with
X;the 8259 interupt controller chip.
X	mov al,034h		;set timer mode
X	cli			;lets not mess with the time interupt routine
X	out timcmd,al
X	xor al,al		;something to send to timer for time
X	out timprt,al		;after setting mode need to send a time
X	out timprt,al		;to restart the timer
X	sti
X
X	mov ax,ds		;save stack segment
X	mov timds,ax
X
X	assume ds:ivec		;address current vectors
X	mov ax,ivec
X	mov ds,ax
X	
X	mov ax,timvec		;save original interupt vector
X	mov romwd,ax
X	mov ax,timvec[2]
X	mov romwd[2],ax
X
X	mov ax,cs		;get new code segment
X	mov bx,offset timint	;code routine
X	cli
X	mov timvec,bx		;set new timer offset
X	mov timvec[2],ax	;set new timer segment
X	sti
X
X	assume ds:dgroup
X	prcexi settime
X
X;************************************************************************
X;*									*
X;*	More timer routine to piggy back on bios timer interupt		*
X;*	This page has the code that gets called by the hardware		*
X;*	Instead of the bios code					*
X;*	It saves AX,BX,CX,DS then falls into the next page of code	*
X;*	on the users stack.						*
X;*									*
X;************************************************************************
X
X;new timer interupt
X	public timint;for debugging only
Xtimint	proc far
X	assume ds:nothing,es:nothing,ss:nothing	;we know nothing, nothing
X;note: it is safe to use 5 stack levels in a timer routine since the
X;      bios interupt we replace does.  (save 4 regs, allowing one stack
X;      level left for the call to dodiv)
X	push ax
X	push bx
X	push cx
X	push ds
X	mov ax,timds		;set new ss and sp
X	mov ds,ax		;set ds for user routine
X	assume ds:dgroup,ss:dgroup
X
X;************************************************************************
X;*									*
X;*	More timer routine to piggy back on bios timer interupt		*
X;*	We take care of keeping our time up to date			*
X;*									*
X;*	Debugging code, remember what part of a tick interupts happen	*
X;*									*
X;************************************************************************
X	if debug
X	  REDTIM		;see when it is
X	  cmp tictim,cx		;later than before?
X	  ifskp_ nc		;remember time if yes
X	   mov tictim,cx	;remember it
X	  endif_
X	endif
X
X;************************************************************************
X;*									*
X;*	More timer routine to piggy back on bios timer interupt		*
X;*	We take care of keeping our time up to date			*
X;*									*
X;************************************************************************
X
X;get number to divide
X	mov bx,rem0w		;get low word of remainder
X	mov ax,rem2w		;get high word
X	inc ah			;one more tick has passed
X
X	call dodiv		;update now accordingly
X
X;put back current remainder
X	mov rem0w,bx
X	mov rem2w,ax
X
X;add result into now
X	add now0w,cx		;move the time forward
X	ifskp_ nc		;carry out of low word?
X	 inc now2w		;had a carry, propagate it
X	endif_
X
X;************************************************************************
X;*									*
X;*	NOTE: execution runs into this page from above (save call/ret)	*
X;*	More timer routine to piggy back on bios timer interupt		*
X;*	This page restores AX,BX,CX,DS,SS,SP then jumps to the normal	*
X;*	bios code.							*
X;*									*
X;************************************************************************
X
X	assume ds:nothing,ss:nothing
X	pop ds
X	pop cx
X	pop bx
X	pop ax
X	jmp romtim
Xtimint	endp
X
X	endps
X	end
END_OF_FILE
if test 12902 -ne `wc -c <'timdif.asm'`; then
    echo shar: \"'timdif.asm'\" unpacked with wrong size!
fi
# end of 'timdif.asm'
fi
if test -f 'trans2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'trans2.c'\"
else
echo shar: Extracting \"'trans2.c'\" \(10251 characters\)
sed "s/^X//" >'trans2.c' <<'END_OF_FILE'
X/* trans2.c -- replacement for phase2.c for use in record program */
X
X/*****************************************************************************
X*	    Change Log
X*  Date	    | Change
X*-----------+-----------------------------------------------------------------
X* 31-Dec-85 | Created changelog
X* 31-Dec-85 | Add c:\ to include directives
X* 31-Dec-85 | Changed to use new CBREAK as well as kbhit
X*  1-Jan-86 | Added stop_reason
X*  1-Jan-86 | <rgd/jmn> Require musicfns.h before adagio.h
X*	    | stop_time is now long
X*	    | Turn off all notes in moreclean
X*	    | changed control logic in play
X*  1-Jan-86 | Added miditrace
X*  1-Jan-86 | Added command scanner at play request level
X* 18-Jan-86 | Gave priority to note offs.
X*	    | Created stop_check routine.
X* 21-Jan-86 | Added mpu_error_check to main loop
X*  3-Feb-86 | Changed help message slightly
X*  7-Feb-86 | Adapted from phase2 of adagio system to do overdubs
X* 21-May-86 | Pulled over lots of code from latest phase2
X*  7-Aug-86 | Initialize bend, touch, porta, mod, and foot controls
X*****************************************************************************/
X/*    This module plays notes compiled and sorted in phase1 and
X *    records from the keyboard
X */
X
X#include "cext.h"
X#include "stdio.h"
X#include "adagio.h"
X#include "mpu.h"
X#include "record.h"
X#include "userio.h"
X#include "trans2.h"
X
X#define stop_code ' '
Xchar stop_explanation[] = "Space bar";
X
Xextern int musictrace;
Xextern int miditrace;
Xextern int CBREAK;
Xextern char outfile[];	/* output file from command line */
X
X#define STOP_CC 1
X#define STOP_CBRK 2
X#define STOP_KEY 3
X#define STOP_SPACE 4
X
Xprivate long offset = 100;	/* time offset from clock to performance */
X
Xprivate int program[num_voices];	/* current program */
X
X/****************************************************************************
X* routines declared in this module
X****************************************************************************/
Xprivate void	init_stuff();
Xprivate void	moreclean();
Xprivate void	play();
Xprivate void	play_help();
Xprivate void	print_status();
Xprivate boolean stop_check();
X
X/****************************************************************************
X*				  init_stuff
X* Effect: 
X*	one-time initializations to prepare for playing and recording
X****************************************************************************/
X
Xprivate void init_stuff()
X{
X    off_init();
X}
X
X/****************************************************************************
X*				moreclean
X* Inputs:
X*	event_type score: the score that was in progress
X*	int stop_reason: the reason the score was stopped
X* Effect: 
X*	prints a message to announce stopped state
X*	tells what was playing at the stop time
X* Implementation:
X*	What was playing is determined by reading the time and searching
X*	for notes that are on at that time.  If nothing is found on a
X*	given channel, it would be nice to print the last note played
X*	on the channel provided it was played within say 1 sec of the
X*	stop time.  This is unimplemented, but would help locate short
X*	notes.
X****************************************************************************/
X
Xprivate void moreclean(score, stop_reason)
X   event_type score;
X   int stop_reason;
X{
X    long stop_time;
X    event_type n;
X
X    while (note_offs(0x7fffffff)) ;	/* turn off all notes */
X
X    printf ("\n	     * * STOPPED * *\n");
X
X    switch(stop_reason)
X       { /* reason for stopping */
X	case STOP_CC:	printf("Control-C seen\n");
X			break;
X	case STOP_CBRK: printf("Control-break seen\n");
X			break;
X	case STOP_KEY:	printf("%s hit\n",stop_explanation);
X			break;
X	case STOP_SPACE:printf("Out of space for recording\n");
X			break;
X       } /* reason for stopping */
X
X    stop_time = gettime() - offset;
X    if (stop_time > 0)
X	printf ("Stopped at time = %ld (hundreths of a second). \n\n",
X		stop_time);
X
X    for (n = score; n != NULL; n = n->next) {
X	if (is_note(n) &&
X	    (n->ntime <= stop_time) &&
X	    (n->ntime + n->u.note.ndur) >= stop_time) {
X	    printf("Voice: %d was playing line: %d\n",
X		n->nvoice + 1, n->nline);
X	}
X    }
X}
X
X/****************************************************************************
X*				    phase2
X* Inputs:
X*	event_type root: Root of play list
X* Effect: 
X*	Plays the music
X****************************************************************************/
X
Xvoid phase2(root)
X   event_type root;
X   {
X    char resp;
X    short done = false;
X    int truth = true;
X
X    init_stuff();
X
X    while (!done) 
X       { /* ask user */
X	truth = true;
X	printf ("\nType <RETURN> to record, q<RETURN> to quit, ?<RETURN> for help:");
X	while(true)
X	   { /* read input */
X	    resp = getchar();
X	    switch(tolower(resp))
X	       { /* decode */
X		case ' ':
X			continue;	/* ignore spaces */
X		case '?': 
X			play_help();
X			readln(stdin);
X			break;
X		case '-':
X			truth = !truth;
X			continue;	/* read next char */
X		case 't':
X			musictrace = truth;
X			readln(stdin);
X			break;
X		case 'm':
X			miditrace = truth;
X			readln(stdin);
X			break;
X		case 'q':
X			done = true;
X			readln(stdin);
X			break;
X		case 's':
X			print_status();
X			readln(stdin);
X			break;
X		case '\n':
X			CBREAK = 0;
X			play(root);
X			break;
X	       } /* decode */
X	    break;
X	   } /* read input */
X       } /* ask user */
X}
X
X/****************************************************************************
X*				     play
X* Inputs:
X*	event_type score: Score to play
X* Effect: 
X*	Plays the score
X****************************************************************************/
X
Xprivate void play(score)
X    event_type score;
X{	
X    event_type event = score;	/* save first pointer for moreclean */
X    short done = false;
X    int stop_reason;
X    long time = 0;
X    int i;
X
X    musicinit();
X    /* initialize midi recording */
X    if (!rec_init(outfile, askbool("Pitch bend, etc. on", false))) {	
X	printf("No space for recording, use a smaller adagio file\n");
X	musicterm();
X	exit(1);
X    }
X
X    printf("Type %s to stop.\n",stop_explanation);
X
X    /* Initialize all midi channels with reasonable start values: */
X    for (i = 1; i <= num_voices; i++) {
X	midi_program(i, 1);
X	program[i - 1] = 1;
X	midi_bend(i, 0);
X	midi_touch(i, 0);
X	midi_ctrl(i, PORTARATE, 99);
X	midi_ctrl(i, PORTASWITCH, 0);
X	midi_ctrl(i, MODWHEEL, 0);
X	midi_ctrl(i, FOOT, 99);
X    }
X
X    timereset();
X    l_restuntil(offset);
X
X    while (!done) { /* play it, Sam */
X	time = gettime() - offset; /* delay everything by offset */
X	if (rec_poll(time)) {	/* record anything that's there */
X	    done = true;
X	    stop_reason = STOP_SPACE;
X	}
X	if (CBREAK || kbhit()) {
X	    done |= stop_check(&stop_reason);
X	}
X	note_offs(time);
X	if (done) { /* clean up */
X	    moreclean(score, stop_reason);
X	    rec_final(true);	/* write out recorded data */
X	} else if (event != NULL) {	/* something to play */
X	    if (time >= event->ntime) {
X		if (is_note(event)) { /* play a note */
X		    /* check for correct program (preset) */
X		    if (event->u.note.nprogram != program[event->nvoice]) {
X			midi_program(event->nvoice+1, event->u.note.nprogram);
X			 program[event->nvoice] = event->u.note.nprogram;
X		    }
X		    /* if it is a note (not a rest) play it */
X		    if (event->u.note.npitch != NO_PITCH) {
X			midi_note(event->nvoice+1, event->u.note.npitch,
X				  event->u.note.nloud);
X			off_schedule(event->ntime + event->u.note.ndur,
X				     event->nvoice, event->u.note.npitch);
X		    }
X		} else {	/* send control info */
X		    switch (vc_ctrl(event->nvoice)) {
X			case 1: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     PORTARATE,
X					     event->u.ctrl.value);
X				break;
X			case 2: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     PORTASWITCH,
X					     event->u.ctrl.value);
X				break;
X			case 3: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     MODWHEEL,
X					     event->u.ctrl.value);
X				break;
X			case 4: midi_touch(vc_voice(event->nvoice) + 1,
X					   event->u.ctrl.value);
X				break;
X			case 5: midi_ctrl(vc_voice(event->nvoice) + 1,
X					     FOOT,
X					     event->u.ctrl.value);
X				break;
X			case 6: midi_bend(vc_voice(event->nvoice) + 1,
X					  event->u.ctrl.value << 6);
X				break;
X			default: break;
X		    }
X		}
X		event = event->next;
X	    }
X	} else mpu_error_check();
X    } /* play it, Sam */
X
X/* Debugging:
X *  i = gettic();
X *  printf("Max Latency is %d\n", i);
X */
X    musicterm();
X}
X
X/****************************************************************************
X*				   play_help
X* Effect: 
X*	Lists help for play option
X****************************************************************************/
X
Xprivate void play_help()
X{
X    fprintf(stderr," <return>	   Play music\n");
X    fprintf(stderr," q<return>	   Quit Adagio (Exit)\n\n");
X    fprintf(stderr," m<return>	   Turn on MIDI byte trace\n");
X    fprintf(stderr,"-m<return>	   Turn off MIDI byte trace\n");
X    fprintf(stderr," s<return>	   Report state\n");
X    fprintf(stderr," t<return>	   Turn on music operation trace\n");
X    fprintf(stderr,"-t<return>	   Turn off music operation trace\n");
X    fprintf(stderr," ?<return>	   This message\n");
X}
X
X/****************************************************************************
X*				  print_status
X* Effect: 
X*	Informative output about state
X****************************************************************************/
X
Xprivate void print_status()
X    {
X     fprintf(stderr,"MIDI trace (m option) %s\n",(miditrace ? "on" : "off"));
X     fprintf(stderr,"Music trace (t option) %s\n",(musictrace ? "on" : "off"));
X    }
X
X/****************************************************************************
X*				     stop_check
X* Outputs:
X*	*reason is set to reason for stop
X*	true is returned iff play should stop
X* Effect: 
X*	Checks for break character or stop code from kbd
X****************************************************************************/
Xprivate boolean stop_check(reason)
X    int *reason;
X{
X    boolean done = false;
X    switch(CBREAK) { /* stop reason */
X	case 0: /* no stop code, try keyboard */
X	    done = (getch() == stop_code);
X	    if (done) *reason = STOP_KEY;
X	    break;
X	case 1: /* ctrl-break */
X	    done = true;
X	    if (kbhit()) getch();
X	    *reason = STOP_CBRK;
X	    break;
X	case 2: /* ctrl-C */
X	    done = true;
X	    *reason = STOP_CC;
X	    if (kbhit()) getch();
X	    break;
X    } /* stop reason */
X    return done;
X}
END_OF_FILE
if test 10251 -ne `wc -c <'trans2.c'`; then
    echo shar: \"'trans2.c'\" unpacked with wrong size!
fi
# end of 'trans2.c'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
