/* EPS.C * Various general-purpose I/O routines to exchange SysEx information * between an EPS and a Roland MPU-401. * The routines to do more specific data transfer (e.g., get wavesample * data) are in separate files. * * Copyright (C) 1991 by Andrew Arensburger. Permission is granted to * use, copy and/or distribute this file freely for non-commercial purposes, * as long as this notice remains intact. Any commercial use is prohibited * without express permission from the author. * * If you make any changes, fix bugs, etc., please send them to me that I * might coordinate fixes and improvements. */ #include #include "mpu.h" #define EPS_GLOBAL #include "eps.h" #undef EPS_GLOBAL unsigned long *pc_clock = (unsigned long *) 0x46cL; /* Pointer to the PC clock */ int last_response; /* Status of last 'response' message */ char *err_msgs[] = { /* Error codes corresponding to each of the * possible EPS responses. */ "OK", "Wait", "Insert system disk", "Invalid parameter number", "Invalid parameter value", "Invalid instrument", "Invalid layer", "Layer in use", "Invalid wavesample", "Wavesample in use", "Invalid wavesample data range", "File not found", "Memory full", "Instrument in use", "No more layers", "No more wavesamples", "", "Wavesample is a copy", "Zone too big", "Sequencer must be stopped", "Disk access in progress", "Disk full", "Loop is too long", "Nak", "No layer edit", "No more pitch tables", "Cross fade length is zero", "Cross fade length is greater than 50%", "Loop start too close to sample start", "Loop end too close to sample end", "Quiet layer" }; /* WAIT * Do nothing for 'ticks' PC clock ticks. */ wait(ticks) int ticks; { unsigned long t; t = *pc_clock; /* Record initial time */ while (*pc_clock < (t + ticks)) ; /* Wait */ } /* TIMEOUT * Wait for up to 'ticks'. If by that time, no data has come * in to the MPU from the EPS, then a timeout has occured, and * 'timeout()' returns 1. Otherwise, 'timeout()' returns 0. */ int timeout(ticks) int ticks; /* # of ticks to wait before timeout */ { unsigned long t; t = *pc_clock; /* Save current time */ while (*pc_clock < (t + ticks)) /* Wait for timeout */ if (DSR) return(0); /* No timeout */ return(1); /* Timeout has occured */ } /* SEND12 * Send a 12-bit word to the EPS. The 12-bit quantity * 0000 xxxx xxyy yyyy * becomes * 00xx xxxx * 00yy yyyy */ send12(word) ushort word; /* 12-bit word, right-justified in 'word' */ { mpu_sbyte((word >> 6) & 0x3f); /* High 6 bits */ mpu_sbyte(word & 0x3f); /* Low 6 bits */ } /* RECV12 * Receive a 12-byte word from the EPS. The pair of words * 00xx xxxx * 00yy yyyy * become * 0000 xxxx xxyy yyyy */ ushort recv12() { ushort retval; /* Return value */ retval = mpu_rbyte() << 6; /* High 6 bits */ retval |= mpu_rbyte(); /* Low 6 bits */ return(retval); } /* SEND16 * Send a 16-bit word to the EPS. The 16-bit quantity * 0000 HHHH hhhh hhll llll * becomes * 0000 HHHH * 00hh hhhh * 00ll llll */ send16(word) ushort word; /* 16-bit word to be sent */ { mpu_sbyte(word >> 12); /* High 4 bits */ mpu_sbyte((word >> 6) & 0x3f); /* Middle 6 bits */ mpu_sbyte(word & 0x3f); /* Low 6 bits */ } /* RECV16 * Receive a 16-bit word from the EPS. The triplet of words * 0000 HHHH * 00hh hhhh * 00ll llll * become * HHHH hhhh hhll llll */ ushort recv16() { ushort retval; /* Return value */ retval = mpu_rbyte() << 6; /* High 4 bits */ retval |= mpu_rbyte(); /* Middle 6 bits */ retval <<= 6; retval |= mpu_rbyte(); /* Low 6 bits */ return(retval); } /* SEND_OFF * Send a 20-bit word (typically wavedata offsets) to the EPS as * a pair of 12-bit words. */ send_off(word) ulong word; /* 20-bit word, right-justified */ { send12((ushort) (word >> 12)); /* Send high 12 bits */ send12((ushort) word & 0x0fffL); /* Send low 12 bits */ } /* RECV_OFF * Receive a 20-bit word (typically a wavesample offset) from the * EPS. */ ulong recv_off() { return(((ulong) recv12() << 12) | recv12()); } /* SEND_HEAD * Send the head of a SysEx message. */ send_head(chan) uchar chan; { mpu_sbyte(0xf0); /* SysEx status byte */ mpu_sbyte(0x0f); /* Ensoniq code */ mpu_sbyte(0x03); /* EPS ID code */ mpu_sbyte(chan & 0x0f); /* Base MIDI channel */ } /* SEND_TAIL * Send the tail of a SysEx message */ send_tail() { mpu_sbyte(0xf7); } /* RECV_HEAD * Receive the head of a SysEx message. The MIDI channel number is * put in (* chan), unless 'chan == NULL'. 'recv_head()' returns * -1 in case of error. */ int recv_head(chan) uchar *chan; { uchar status; /* Flush any extraneous garbage before the message head */ while (!DSR) ; status = flush_nonsysx(); if (status != 0xf0 || /* SysEx status byte */ (uchar) mpu_rbyte() != 0x0f || /* Ensoniq manufacturer code */ (uchar) mpu_rbyte() != 0x03) /* EPS ID code */ return(-1); if (chan != NULL) /* Base MIDI channel */ *chan = (uchar) mpu_rbyte(); else mpu_rbyte(); return(0); } /* RECV_TAIL * Receive the tail of a SysEx message, and discard it. Kind of a * pretty NO-OP. */ int recv_tail() { return(mpu_rbyte() == 0xf7 ? 0 : -1); } /* SEND_RESPONSE * Send a 'Response' message to the EPS, with base channel 'bchan' and * response 'r'. */ send_response(bchan,r) ushort bchan,r; { send_head(bchan); mpu_sbyte(0x01); /* Response */ send12(r); /* Response status */ send_tail(); } /* RECV_RESPONSE * Receive a response from the EPS. Put the base chan in '* bchan' (unless * '*bchan == NULL'), and return the response code. */ int recv_response(bchan) uchar *bchan; { int retval; if (recv_head(bchan) < 0 || mpu_rbyte() != 0x01) /* Read head and 'response' */ return(-1); last_response = retval = (int) recv12(); recv_tail(); return(retval); }