home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 31-Dec-85 | Created changelog
- * 31-Dec-85 | Add c:\ to include directives
- * 31-Dec-85 | Call setctl/clrctl to deal with ctrl-break intercept. Note that
- * | clrctl can be called several times, as might be the case during
- * | a ctrl-break abort
- * 1-Jan-86 | <rgd/jmn> Added keyloud
- * | Added initialized flag
- * 21-Jan-86 | Abort l_restuntil if Ctrl-C or Ctrl-Break is typed
- * 21-Jan-86 | Took out mpu_unknown, replaced with mpu_error_check
- * 3-Feb-86 | Fixed MIDI_PROGRAM and MIDI_CHANNEL to subtract one to account
- * | for MIDI encodings, e.g. channel 1 is represented by 0
- * 8-Feb-86 | Added midi_exclusive to turn on/off flag in mpu-401.
- * | Added midi_buffer function.
- * 18-Feb-86 | Changed midi_exclusive to exclusive.
- * | Added midi_exclusive to send an exclusive message.
- * 19-Feb-86 | Changed MC_SEND_... to MC_SND_... to avoid name clash
- * 23-Feb-86 | Added midi_control, midi_bend, midi_touch routines
- * 24-Feb-86 | Added call to init_asm from musicinit.
- * 26-Mar-86 | Added midi_cont call to enable continuous control messages
- * 18-Apr-86 | Cleaned up documentation, renamed midi_control to midi_ctrl
- * 2-Jun-86 | Added tuning definition code.
- * 30-Jun-86 | Added switch to use timdif.asm instead of MPU-401 for timing
- * 18-Jul-86 | Added DEBUG switch in parallel with DEBUG in AINTR.ASM
- * 29-Jul-86 | Changed trace flag checking to first initialization only.
- * 5-Aug-86 | Minor changes for Lattice C Version 3.00
- *****************************************************************************/
-
- /*
- * Driver for MPU-401
- *
- * This module initializes things and then issues commands to the
- * MPU-401 in response to higher-level operations like note( , , ).
- * Unlike examples in the MPU-401 manual, these routines do not wait
- * for Acks by polling the MPU-401. Instead, Acks and all other
- * input are handled by the interrupt routine (see aintr.asm), which
- * sets a flag whenever it sees an Ack. Therefore, these routines
- * just poll the Ack flag rather than directly reading the MPU-401.
- * This avoids the problem of the MPU-401 having data queued in front
- * of the Ack message.
- */
-
- /*
- * Interface Specifications for aintr.asm to mpu.c:
- *
- * aintr.asm is an interrupt handler that also parses midi data and
- * queues it for receipt by mpu.c. In this way, interrupts are hidden
- * from C programmers and yet the mpu-401 never hangs trying to deliver
- * data because the interrupt routine is always ready to read data.
- *
- * Data is parsed by aintr.asm in order to know how much data to read.
- * To avoid reparsing at the C level, the data is buffered in a
- * queue of messages rather than a simple byte stream. Each message
- * is a 4-byte block. The first byte is a status byte and the following
- * bytes (one or two) are data bytes.
- *
- * Note that timing is not specified. Later, we may add a parallel
- * buffer to store 4-byte timing blocks if it seems necessary.
- *
- * System exclusive messages are handled by copying the midi exclusive
- * data into a separate buffer provided by the application program
- * through the midi_buffer call.
- *
- */
-
- /* define DEBUG to enable some extra debugging */
- /* #define DEBUG 1 */
-
-
- /* define TIMDIF to use the timdif.asm module */
- /* #define TIMDIF 1 */
-
- #include "cext.h"
- #include "stdio.h"
- #include "atxt.h"
- #include "mpu.h"
- #include "midicode.h"
- #include "cmdline.h"
- #include "userio.h"
- #include "pitch.h"
- #include "cintr.h"
-
- #ifdef TIMDIF
- #include "timdif.h"
- #endif
-
- #define BREAKTEST if (CBREAK) { /* Ctrl-C or Ctrl-Break handler */ \
- al_nt_off();\
- printf("Exiting.\n");\
- musicterm();\
- exit(1);\
- }
- #define num_voices 16
-
- /****************************************************************************
- *
- * MPU 401 commands
- *
- ****************************************************************************/
-
- #define MC_RESET 0xff
- #define MC_SET_TEMPO 0xe0
- #define MC_TIMEBASE_192 0xc8
- #define MC_START_RECORDING 0x22
- #define MC_RECORD_COUNTER 0xab
- #define MC_ON_METRONOME 0x85
- #define MC_VERSION 0xac
- #define MC_REVISION 0xad
- #define MC_NO_MEASURE_END 0x8c
- #define MC_SND_MIDI 0xd0
- #define MC_SND_EXCLUSIVE 0xdf
- #define MC_EXCLUSIVE 0x96
- #define MC_OFF_BEND 0x86
- #define MC_ON_BEND 0x87
- #define MC_OFF_THRU 0x88
- #define MC_ON_THRU 0x89
-
- /****************************************************************************
- *
- * useful defines and macros
- *
- ****************************************************************************/
-
- #define MD_BEATS_PER_MINUTE 125 /* to get 400 ticks per sec */
- #define TICKS_TO_HUNDREDTHS(t) ((t) >> 2)
- #define HUNDREDTHS_TO_TICKS(h) ((h) << 2)
- #define NONE (-1)
-
- /****************************************************************************
- *
- * MPU-401 interface to IBM-XT
- *
- ****************************************************************************/
-
- #define DATAPORT 0x330 /* Input data port of MPU 401 */
- #define STATPORT 0x331 /* status and request port */
- #define COMPORT 0x331 /* Send MPU 401 commands to here */
- #define DSR (1<<7) /* This bit of STATPORT, when low,
- means the 401 has Data to send */
- #define DRR (1<<6) /* This bit of STATPORT, when low,
- means the 401 will take commands */
- #define ACK 0xfe /* Acknowledgement data code */
- #define IRQ 2 /* Interrupt request line of 401 */
- #define MAX_ACK_WAIT 1000
-
- /****************************************************************************
- *
- * exported flags
- *
- ****************************************************************************/
-
- boolean musictrace = false; /* enables printed trace of commands */
- boolean miditrace = false; /* enables printed trace of MIDI output */
-
- #define n_t_sw 2
- private char *t_switches[n_t_sw] = { "-t", "-trace" };
-
- #define n_m_sw 2
- private char *m_switches[n_m_sw] = { "-m", "-miditrace" };
-
- /****************************************************************************
- *
- * exported variables
- *
- ****************************************************************************/
-
- int keyloud; /* set to velocity of last getkey event */
-
-
- /****************************************************************************
- *
- * variables shared with aintr.asm
- *
- ****************************************************************************/
-
- int intnest = 0; /* do not touch...read-only except by aintr.asm */
- int rd_delay = 0; /* do not touch...read-only except by aintr.asm */
-
- int Unknown = ACK;
- int interror = 0; /* reports errors from interrupt handler */
- int timeerr = 0; /* reports timeout errors */
-
- #ifdef DEBUG
- int intcnt = 0; /* Count of interrupts taken */
- int loop_cnt, loop_max; /* iteration counts */
- #endif
-
- long Ticks; /* Number of clock ticks since init */
- int Ack; /* True if command has been acknowledged */
- char MidiTime, MidiStat = 0x90, Midi1, Midi2, Midi3; /* midi and time */
- char exclflag = 0; /* used by aintr, DO NOT TOUCH */
- int time_req = 0; /* set to 1 when Ack will be followed by data */
- int mpu_result; /* the data following the Ack */
-
-
- /****************************************************************************
- *
- * Variable set by BREAK module
- *
- ****************************************************************************/
-
- int CBREAK;
-
-
- /****************************************************************************
- *
- * variable imported from cintr.c
- *
- ****************************************************************************/
-
- extern int enabled;
-
-
- /****************************************************************************
- *
- * local module variables
- *
- ****************************************************************************/
-
- private int initialized = false; /* set by musicinit, cleared by musicterm */
- private boolean tune_flag = false; /* set by musicinit, never cleared */
- private boolean metroflag = false; /* flag to turn on metronome */
- private boolean mpuflag = true; /* true iff mpu401 present */
- private int len; /* length of trace string */
- private int last_cmd = 0; /* last mpu_command, used by trace */
- private int user_scale = false; /* true if user-defined scale */
- private int bend[num_voices]; /* current pitch bend on channel */
- private pitch_table pit_tab[128]; /* scale definition */
-
- /* "temporary" instrumentation: how long should we wait? */
- private int max_ack_wait = 0; /* maintained by mpu_wait */
-
- /****************************************************************************
- *
- * functions declared in this module
- *
- ****************************************************************************/
-
- private void fixup();
- private void mpu_command();
- private void mpu_drr_wait();
- private int mpu_read();
- private void mpu_wait();
- private void mpu_write();
- private void trace_mpu_command();
- private void wfa();
-
-
- /****************************************************************************
- *
- * Buffer
- * shares data with aintr.asm (the producer)
- *
- ****************************************************************************/
-
- #define BUFFERSIZE 1024
- byte buff[BUFFERSIZE]; /* data buffer */
- int buffhead = 0; /* buffer pointers */
- int bufftail = 0;
-
-
- /****************************************************************************
- *
- * System exclusive buffer variables (shared with aintr.asm)
- *
- ****************************************************************************/
-
- byte *xbuff = 0; /* address of the user-supplied buffer */
- int xbuffmas; /* mask for circular buffer address calculation */
- int xbuffhea = 0; /* buffer pointers */
- int xbufftai = 0;
-
- /****************************************************************************
- * exclusive
- * Inputs:
- * boolean onflag -- set to true to receive midi exclusive data
- * Effect:
- * Tells MPU401 to read exclusive messages into buffer
- ****************************************************************************/
-
- void exclusive(onflag)
- boolean onflag; /* on or off? */
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("exclusive: %d\n", onflag);
- mpu_command(MC_EXCLUSIVE | (onflag ? 1 : 0));
- }
-
- /****************************************************************************
- * fixup
- * Effect:
- * Print error message and call musicinit
- ****************************************************************************/
-
- private void fixup()
- {
- printf("You forgot to call musicinit. I'll do it for you.\n");
- musicinit();
- }
-
- /****************************************************************************
- * getbuf
- * Inputs:
- * boolean waitflag: true if routine should wait for data
- * byte * p: Pointer to data destination
- * Result: boolean
- * true if data was written to *p
- * false if data not written to *p
- * Effect:
- * copies data from buffer to *p
- * will wait for buffer to become nonempty if waitflag is true
- ****************************************************************************/
-
- boolean getbuf(waitflag, p)
- boolean waitflag; /* true if routine should wait for data */
- byte *p; /* pointer to data destination */
- {
- /* register int head;*/
-
- if (!initialized) fixup();
- if (waitflag) while (buffhead == bufftail) /* wait */ ;
- else if (buffhead == bufftail) return false;
-
- *(long *)p = *(long *)(buff+buffhead);
- buffhead += 4;
- if (buffhead >= BUFFERSIZE) buffhead = 0;
-
- /* the previous three lines are an optimization of:
- * head = buffhead;
- * *p++ = buff[head++];
- * *p++ = buff[head++];
- * *p++ = buff[head++];
- * head++;
- *
- * if (head >= BUFFERSIZE) head = 0;
- * buffhead = head;
- */
- return true;
- }
-
- /****************************************************************************
- * getkey
- * Inputs:
- * boolean waitflag: true if wait until key depression, false if
- * return immediately
- * Result: int
- * key number of key which has been depressed
- * It returns -1 if waitflag is false and no key has been pressed
- * If waitflag is true this routine will block until a key is pressed
- * Effect:
- * reads a key
- ****************************************************************************/
-
- int getkey(waitflag)
- {
- byte msg[4];
- int k;
-
- if (!initialized) fixup();
- while (true) { /* process data until you find a note */
- /* look for data and exit if none found */
- /* NOTE: waitflag will force waiting until data arrives */
- if (!getbuf(waitflag, msg)) { /* nothing there */
- k = -1;
- break;
- } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) {
- if (msg[2] == 0) { /* velocity 0 -> note off */
- keyloud = 0;
- k = (msg[1]-12) + 128;
- } else {
- keyloud = msg[2];
- k = (msg[1]-12);
- }
- break;
- } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) {
- keyloud = 0;
- k = (msg[1]-12) + 128;
- break;
- }
- }
- if (musictrace) {
- if (k != -1) printf("getkey got %d\n", k);
- }
- return k;
- }
-
- /****************************************************************************
- * gettime
- * Result: long
- * current timestamp from MPU-401
- * Return the time in 100ths of seconds since the last call to
- * musicinit or timereset
- * Effect:
- * Reads the MPU-401 time
- ****************************************************************************/
-
- /* just to make sure we're using the timdif module: */
- long gettime()
- {
- BREAKTEST /* abort if user typed Ctrl Break */
-
- if (!initialized) fixup();
- #ifndef TIMDIF
- time_req = 1; /* tell aintr.asm to read extra byte */
- mpu_command(MC_RECORD_COUNTER); /* Read counter */
- return TICKS_TO_HUNDREDTHS(Ticks);
- #else
- return ibm_time();
- #endif
- }
-
- /****************************************************************************
- * l_rest
- * Inputs:
- * long time: Amount of time to rest
- * Effect:
- * Waits until the amount of time specified has lapsed
- ****************************************************************************/
-
- void l_rest(time)
- long time;
- {
- if (!initialized) fixup();
- l_restuntil(time + gettime());
- }
-
- /****************************************************************************
- * l_restuntil
- * Inputs:
- * long time: Event time to rest until
- * Effect:
- * Waits until the specified time has been reached (absolute time)
- ****************************************************************************/
-
- void l_restuntil(time)
- long time;
- {
- while(time > gettime()) ;
- }
-
- /****************************************************************************
- * metronome
- * Inputs:
- * int onflag: true or false
- * Effect:
- * enables (true) or disables (false) MPU-401 metronome function.
- * must be called before musicinit
- ****************************************************************************/
-
- void metronome(onflag)
- int onflag;
- {
- metroflag = onflag;
- }
-
- /****************************************************************************
- * midi_bend
- * Inputs:
- * int channel: midi channel on which to send data
- * int value: pitch bend value
- * Effect:
- * Sends a midi pitch bend message
- ****************************************************************************/
-
- void midi_bend(channel, value)
- int channel, value;
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("midi_bend: ch %d, val %d\n", channel, value);
- bend[MIDI_CHANNEL(channel)] = value;
- mpu_command(MC_SND_MIDI);
- mpu_write(MIDI_BEND | MIDI_CHANNEL(channel));
- mpu_write(MIDI_DATA(value));
- mpu_write(MIDI_DATA(value>>7));
- }
-
- /****************************************************************************
- * midi_buffer
- * Inputs:
- * byte * buffer: the buffer address
- * int size: number of bytes in buffer
- * Returns:
- * false if size is less than 16 or buffer is NULL, otherwise true
- * Effect:
- * tells interrupt routine to store system exclusive messages in
- * buffer. The largest power of 2 bytes less than size will be
- * used. xbuffhea and xbufftai will be initialized to zero,
- * and xbufftai will be one greater than the index of the last
- * system exclusive byte read from mpu401.
- ****************************************************************************/
-
- int midi_buffer(buffer, size)
- byte *buffer;
- int size;
- {
- int mask;
- mask = 16 - 1;
- if (size < 16 || buffer == NULL) return false;
- while (mask < size && mask > 0) mask = (mask << 1) + 1;
- xbuff = NULL; /* turn off buffering */
- xbuffmas = mask >> 1;
- xbuffhea = xbufftai = 0;
- xbuff = buffer; /* set buffer, turn on buffering */
- return true;
- }
-
- /****************************************************************************
- * midi_cont
- * Inputs:
- * boolean onflag: true or false
- * Effect:
- * enables (true) or disables (false) continuous control info from
- * MPU-401 to host.
- ****************************************************************************/
-
- void midi_cont(onflag)
- boolean onflag;
- {
- if (onflag) mpu_command(MC_ON_BEND);
- else mpu_command(MC_OFF_BEND);
- }
-
- /****************************************************************************
- * midi_ctrl
- * Inputs:
- * int channel: midi channel on which to send data
- * int control: control number
- * int value: control value
- * Effect:
- * Sends a midi control change message
- ****************************************************************************/
-
- void midi_ctrl(channel, control, value)
- int channel, control, value;
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("midi_ctrl: ch %d, ctrl %d, val %d\n",
- channel, control, value);
- mpu_command(MC_SND_MIDI);
- mpu_write(MIDI_CTRL | MIDI_CHANNEL(channel));
- mpu_write(MIDI_DATA(control));
- mpu_write(MIDI_DATA(value));
- }
-
- /****************************************************************************
- * midi_exclusive
- * Inputs:
- * byte * msg: pointer to a midi exclusive message, terminated by 0xF7
- * Effect:
- * Sends a midi exclusive message
- ****************************************************************************/
-
- void midi_exclusive(msg)
- byte *msg; /* the data to be sent */
- {
- int i; /* can DX7 keep up? */
-
- /* if user mistakenly called midi_exclusive instead of exclusive,
- * the argument will be true or false, both of which are highly
- * unlikely valid arguments for midi_exclusive:
- */
- if (msg == (byte *) false || msg == (byte *) true) {
- printf("midi_exclusive: invalid argument %d.\n", (int) msg);
- if (initialized) musicterm();
- exit(1);
- }
-
- if (!initialized) fixup();
- if (musictrace) printf("midi_exclusive\n");
- mpu_command(MC_SND_EXCLUSIVE);
- while (*msg != MIDI_EOX) {
- mpu_write(*msg);
- msg++;
- /* This is a delay loop. Without it, your DX7 will crash. */
- for (i = (ATXT() == ISAT ? 4 : 2); i > 0; i--) {
- BREAKTEST
- }
- }
- mpu_write(MIDI_EOX);
- }
-
- /****************************************************************************
- * midi_note
- * Inputs:
- * int channel: midi channel on which to send data
- * int pitch: midi pitch code
- * int velocity: velocity with which to sound it (0=> release)
- * Effect:
- * Sends a midi note-play request out
- ****************************************************************************/
-
- void midi_note(channel, pitch, velocity)
- int channel, pitch, velocity;
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("midi_note: ch %d, key %d, vel %d\n",
- channel, pitch, velocity);
- if (user_scale) {
- /* check for correct pitch bend */
- if ((pit_tab[pitch+12].pbend != bend[MIDI_CHANNEL(channel)]) &&
- (velocity != 0)) {
- midi_bend(channel, pit_tab[pitch+12].pbend);
- bend[channel] = pit_tab[pitch+12].pbend;
- }
- pitch = pit_tab[pitch+12].ppitch;
- }
- mpu_command(MC_SND_MIDI);
- mpu_write(MIDI_ON_NOTE | MIDI_CHANNEL(channel));
- mpu_write(MIDI_DATA(12 + pitch)); /* cmu standard to midi standard */
- mpu_write(MIDI_DATA(velocity));
- }
-
- /****************************************************************************
- * midi_program
- * Inputs:
- * int channel: Channel on which to send midi program change request
- * int program: Program number to send (decremented by 1 before
- * being sent as midi data)
- * Effect:
- * Sends a program change request out the channel
- ****************************************************************************/
-
- void midi_program(channel, program)
- int channel; /* midi channel */
- int program; /* the program number */
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("midi_program: ch %d, prog %d\n",
- channel, program);
- mpu_command(MC_SND_MIDI);
- mpu_write(MIDI_CH_PROGRAM | MIDI_CHANNEL(channel));
- mpu_write(MIDI_PROGRAM(program));
- }
-
- /****************************************************************************
- * midi_thru
- * Inputs:
- * boolean onflag: true or false
- * Effect:
- * enables (true) or disables (false) midi thru info from
- * MPU-401 to host. (Default is set; reset with cmdline -block.)
- ****************************************************************************/
-
- void midi_thru(onflag)
- boolean onflag;
- {
- if (onflag) mpu_command(MC_ON_THRU);
- else mpu_command(MC_OFF_THRU);
- }
-
- /****************************************************************************
- * midi_touch
- * Inputs:
- * int channel: midi channel on which to send data
- * int value: control value
- * Effect:
- * Sends a midi after touch message
- ****************************************************************************/
-
- void midi_touch(channel, value)
- int channel, value;
- {
- if (!initialized) fixup();
- if (musictrace)
- printf("midi_touch: ch %d, val %d\n", channel, value);
- mpu_command(MC_SND_MIDI);
- mpu_write(MIDI_TOUCH | MIDI_CHANNEL(channel));
- mpu_write(MIDI_DATA(value));
- }
-
- /****************************************************************************
- * mpu_command
- * Inputs:
- * int c: Character to write to MPU-401 command port
- * Effect:
- * Writes the data to the MPU-401 command port
- ****************************************************************************/
-
- private void mpu_command(c)
- int c;
- {
- if (!mpuflag) { /* simulated */
- trace_mpu_command(c);
- } else { /* real */
- if (miditrace) trace_mpu_command(c);
- mpu_drr_wait();
- Ack = 0;
- outp(COMPORT, c);
- if (enabled) mpu_wait();
- else wfa();
- }
- }
-
- /****************************************************************************
- * mpu_drr_wait
- * Effect:
- * Waits until the MPU-401 is ready to receive data
- ****************************************************************************/
-
- #define MAX_TRIES 2000
-
- private void mpu_drr_wait()
- {
- int i;
-
- if (!mpuflag) return; /* always ready if not there! */
-
- for (i = 0; i < MAX_TRIES; i++)
- if ((inp(STATPORT) & DRR) == 0) break;
- #ifdef DEBUG
- if (i == MAX_TRIES)
- printf("mpu-401 not ready to receive; intcnt=%d\n",intcnt);
- #endif
- }
-
- /****************************************************************************
- * mpu_error_check
- * Effect:
- * Reports any errors originating in the interrupt handler
- ****************************************************************************/
-
- void mpu_error_check()
- {
- if (Unknown != ACK) {
- printf("Unknown command: %x\n", Unknown);
- Unknown = ACK;
- }
- if (interror != 0) {
- char *cause;
- switch (interror) {
- case NESTERR: cause = "nested interrupts"; break;
- case BUFFERR: cause = "buffer overflow"; break;
- case CMDERR: cause = "unknown command"; break;
- default: cause = ""; break;
- }
- printf("interror: %s\n", cause);
- if (*cause == 0) printf("%d\n", interror);
-
- interror = 0;
- }
- if (timeerr != 0) {
- if (timeerr == TIMEOUT) printf("timeerr: timeout error\n");
- else printf("timeerr = %d\n", timeerr);
- timeerr = 0;
- }
- }
-
- /****************************************************************************
- * mpu_read
- * Result: int
- * character read from MPU-401
- * Effect:
- * Reads the MPU-401
- ****************************************************************************/
-
- private int mpu_read()
- {
- int delay;
- for (delay = 0; delay < 2000; delay++) {
- if ((inp(STATPORT) & DSR) == 0)
- return inp(DATAPORT);
- }
- #ifdef DEBUG
- printf("mpu_read: DSR never went low, returning 0, intcnt=%d\n",intcnt);
- #endif
- return 0;
- }
-
- /****************************************************************************
- * mpu_wait
- * Effect:
- * Called when interrupts are enabled. Polls the 'Ack' flag, which is
- * set by the interrupt handler. If more than MAX_ACK_WAIT iterations
- * occur without 'Ack' being set, issues an error message.
- * Ack is cleared when it is detected.
- ****************************************************************************/
-
- private void mpu_wait()
- {
- int ackcnt; /* delay counter */
-
- if (!mpuflag) return;
-
- for (ackcnt = 0; ackcnt < MAX_ACK_WAIT; ackcnt++) {
- if (Ack) {
- if (max_ack_wait < ackcnt) max_ack_wait = ackcnt;
- Ack = 0;
- return;
- }
- }
- #ifdef DEBUG
- printf("mpu_wait: No ack; incnt = %d\n",intcnt);
- #endif
- }
-
- /****************************************************************************
- * mpu_write
- * Inputs:
- * int c: Character to write to MPU-401 data port
- * Effect:
- * Writes the data to the MPU-401 data port
- ****************************************************************************/
-
- private void mpu_write(c)
- int c;
- {
- if (!mpuflag) { /* simulate */
- printf("%02x",c);
- len += 2;
- } else { /* real */
- if (miditrace) { /* trace */
- printf("%02x",c);
- len += 2;
- } /* trace */
- mpu_drr_wait();
- outp(DATAPORT, c);
- }
- }
-
- /****************************************************************************
- * mpuexists
- * Inputs:
- * boolean flag: true or false
- * Effect:
- * if argument is false, indicates no mpu is on the machine, so
- * simulate mpu-401 (for debugging only)
- ****************************************************************************/
-
- void mpuexists(flag)
- boolean flag;
- {
- mpuflag = flag;
- }
-
- /*****************************************************************
- * set_pitch_default
- *****************************************************************/
- private void set_pitch_default()
- {
- int i;
-
- for (i = 0; i < 128; i++) {
- pit_tab[i].pbend = 8192;
- pit_tab[i].ppitch = i;
- }
- }
-
- /*****************************************************************
- * read_tuning
- *****************************************************************/
-
- void read_tuning(filename)
- char *filename;
- {
- int index, pit, lineno = 0;
- float bend;
- FILE *fpp;
-
- user_scale = true;
- set_pitch_default();
- fpp = fileopen(filename, "tun", "r", "Tuning definition file");
- while ((fscanf(fpp, "%d %d %f\n", &index, &pit, &bend) > 2) &&
- (lineno < 128)) {
- lineno++;
- if (index >= -12 && index <= 115) {
- pit_tab[index+12].pbend = (int)(8192 * bend/100 + 8192);
- pit_tab[index+12].ppitch = pit;
- }
- }
- }
-
-
- /****************************************************************************
- * musicinit
- * Effect:
- * Initialize the mpu 401 device driver
- * Initialize mpu 401
- * Reset 401, change defaults
- * Set up interrupts
- * Start up mpu record clock
- ****************************************************************************/
-
- void musicinit()
- {
- int version, revision;
- int i;
- char *filename;
-
- if (!tune_flag) { /* do this code only once */
- miditrace = (cl_nswitch(m_switches, n_m_sw) != NULL);
- musictrace = (cl_nswitch(t_switches, n_t_sw) != NULL);
-
- tune_flag = true;
- filename = cl_option("-tune");
- if (filename != NULL) {
- read_tuning(filename);
- }
-
- intr_init();
- }
-
- last_cmd = 0;
-
- #ifdef TIMDIF
- if (!initialized) settime();
- #endif
-
- initialized = true;
-
- intr_disable(IRQ); /* Turn off 401 interrupts */
-
- for (i = 0; i < 100; i++) { /* flush out buffer, ignore DSR */
- inp(DATAPORT);
- }
-
- mpu_command(MC_RESET); /* Reset the device */
-
- mpu_command(MC_VERSION);
- version = mpu_read();
-
- mpu_command(MC_REVISION);
- revision = mpu_read();
-
- mpu_command(MC_SET_TEMPO); /* Set tempo and timebase to get */
- mpu_write(MD_BEATS_PER_MINUTE); /* 400 ticks per second */
-
- mpu_command(MC_TIMEBASE_192);
-
- if (metroflag)
- mpu_command(MC_ON_METRONOME); /* Just for debugging */
-
- mpu_command(MC_NO_MEASURE_END); /* Don't want measure end bytes */
-
- init_asm(); /* Do any asm init needed(aintr.asm)*/
- intr_routine(IRQ); /* Set up vector */
-
- CBREAK = false;
- setctl(); /* Set up ctrl-break intercept */
-
- #ifdef DEBUG
- loop_max = 0;
- #endif
- intr_enable(IRQ); /* allow 401 interrupts */
-
- if (user_scale) {
- for (i = 0; i < num_voices; i++) {
- midi_bend(i, 8192);
- bend[i] = 8192;
- }
- }
- midi_thru(!(cl_switch("-block"))); /* set MIDI thru on MPU-401 */
-
- timereset(); /* Reset clock */
- }
-
- /****************************************************************************
- * musicterm
- * Effect:
- * Cleans up; disables MPU-401 interrupts; resets MIDI devices
- ****************************************************************************/
-
- void musicterm()
- {
- if (initialized) {
- #ifdef TIMDIF
- cletime();
- #endif
- intr_disable(IRQ); /* No more 401 interrupts */
- #ifdef DEBUG
- printf("loop_max is %d\n", loop_max);
- #endif
- clrctl(); /* reset ctrl-break handler */
- intr_cleanup(IRQ); /* Restore default vector */
- mpu_command(MC_RESET); /* Reset the device */
- initialized = false;
- }
- /* printf("maximum successful wait for ack: %d\n", max_ack_wait);*/
- }
-
- /****************************************************************************
- * random
- * Inputs:
- * int lo: Lower limit of value
- * int hi: Upper limit of value
- * Result: int
- * random number (lo <= result <= hi)
- ****************************************************************************/
-
- private long seed = 1534781;
-
- int random(lo, hi)
- int lo, hi;
- {
- seed *= 13;
- seed += 1874351;
- return (int) (lo +
- (((hi + 1 - lo) * ((0x00ffff00 & seed) >> 8)) >> 16));
- }
-
- /****************************************************************************
- * timereset
- * Effect:
- * Resets the time on the MPU-401. Ticks is reset to 0
- ****************************************************************************/
-
- void timereset()
- {
- if (!initialized) fixup();
- if (musictrace) printf("timereset()\n");
- Ticks = 0; /* Reset clock */
- mpu_command(MC_START_RECORDING); /* Starts up clock */
- #ifdef TIMDIF
- cletime();
- settime();
- #endif
- }
-
- /****************************************************************************
- * trace
- * Inputs:
- * boolean flag: true for trace on
- * Effect:
- * turns tracing on (flag == true) or off (flag == false)
- ****************************************************************************/
- void trace(flag)
- boolean flag;
- {
- musictrace = flag;
- }
-
- /****************************************************************************
- * tracemidi
- * Inputs:
- * boolean flag: true for trace on
- * Effect:
- * turns midi tracing on (flag == true) or off (flag == false)
- ****************************************************************************/
- void tracemidi(flag)
- boolean flag;
- {
- miditrace = flag;
- }
-
- /****************************************************************************
- * trace_mpu_command
- * Inputs:
- * int c: Command
- * Effect:
- * Writes command to stdout
- ****************************************************************************/
-
- private void trace_mpu_command(c)
- int c;
- {
- char * p;
- char buf[10];
-
- switch(c) { /* decode */
- case MC_RESET:
- p = " RESET:";
- break;
- case MC_ON_METRONOME:
- p =" MET-ON:";
- break;
- case MC_SET_TEMPO:
- p =" TEMPO:";
- break;
- case MC_TIMEBASE_192:
- p =" TIME-192:";
- break;
- case MC_START_RECORDING:
- p =" REC-ON:";
- break;
- case MC_VERSION:
- p =" VERSION:";
- break;
- case MC_REVISION:
- p =" REVISION:";
- break;
- case MC_NO_MEASURE_END:
- p =" NO-MEAS-END:";
- break;
- case MC_SND_MIDI:
- p =" MIDI:";
- break;
- case MC_RECORD_COUNTER:
- if (last_cmd == c) p = "#";
- else p = " COUNTER:";
- break;
- case MC_ON_BEND:
- p = "Bender:On";
- break;
- case MC_OFF_BEND:
- p = "Bender:Off";
- break;
- case MC_ON_THRU:
- p = "Thru:On";
- break;
- case MC_OFF_THRU:
- p = "Thru:Off";
- break;
- default:sprintf(buf," %02x",c);
- p = buf;
- break;
- } /* decode */
-
- last_cmd = c;
-
- if (len + strlen(p) > 70) { /* overflow */
- printf("\n");
- len = 0;
- } /* overflow */
- len += strlen(p);
- printf("%s",p);
- }
-
- /****************************************************************************
- * wfa
- * Effect:
- * Waits for an acknowledgement from the MPU-401. Will not wait more
- * than MAX_ACK_WAIT iterations thru its loop.
- * Conditions:
- * Called only if interrupts are not enabled, and the MPU-401 is
- * being polled
- ****************************************************************************/
-
-
- private void wfa()
- {
- int ackcnt;
- int x;
-
- if (!mpuflag) return;
-
- for (ackcnt = 0; ackcnt < MAX_ACK_WAIT; ackcnt++)
- if ((x = mpu_read()) == ACK) break;
- #ifdef DEBUG
- else printf("wfa: got %x; intcnt = %d\n", x, intcnt);
- #endif
- }
-
-
- /* From here my own routine begins */
-
- al_nt_off()
- {
- static int c;
- for (c = 0; c < 16; c++) {
- mpu_write( 0xb0 + c);
- mpu_write(123);
- mpu_write(0);
- }
- }
-
-