/***********************************************************************************
 *
 * Header File for the Squeak Interface to MIDI
 * 		Stephen T. Pope -- stp@create.ucsb.edu -- 1998.10.14
 *
 * Version History:
 *		0.0 -- 1997.07.13 - Creation based on "Sample OMS Application"
 *		0.1 -- 1997.07.28 - First full version (with output Q)
 *		1.0 -- 1997.08.29 - Made output Q an #ifdef
 *		0.4 -- 1997.10.13 - Separate headers, remove output Q code
 *		1.2 -- 1998.02.04 - Finally works with OMS (sans device dialog)
 *		1.31 -- 1998.03.18 - Restructured OMS version for "minimal" MIDI
 *		2.0B -- 1998.05.05 - Fixed controller caching, added flush ioctl
 *		2.2 -- 1998.10.10 - Ported to CodeWarrion Pro4 and OMS 2.5.3
 *
 * This file should be platform- and driver-independent.
 * 
 * Note: Most of the primitives fail only under extreme conditions, and return 
 * negative results for "normal" failure.
 * A return value of 0 normally means "success" or "true."
 *
 *	The Smalltalk primitive bindings are:
 *		(610 primitiveOpenMIDI)
 *		(611 primitiveCloseMIDI)
 *		(612 primitiveGetMIDIDeviceName)
 *		(613 primitivePutMIDIOn)
 *		(614 primitiveReadMIDIPacket)
 *		(615 primitiveReadMIDIControl)
 *		(616 primitiveMIDIioctl)
 */
 
int signalSemaphoreWithIndex(int index);
int stackValue(int offset);
int stackIntegerValue(int offset);
int success(int successValue);

/***********************************************************************************
 * External MIDI interface function prototypes (Smalltalk primitives)
 */
				// Open/start the MIDI interface. (Prim. 610) 
				// Answer the number of connected devices, or 0 if the driver's 
				// already open.
				// 'readSemaphore' is the index of the semaphore to signal on MIDI 
				// input if it's non-zero and input signalling is turned on (see the 
				// ioctl commands below).
				// 'readSocket' is the socket to read from; writeSocket will be 
				// readSocket + 1 (if readSocket's 0, don't use sockets at all).
				// (The socket is ignored in the default driver.)
int sqOpenMIDI(int readSemaphore, int inputSocket);

				// Close the MIDI interface and disconnect from the driver (611)
int sqCloseMIDI(void); 	

				// Get the name of a MIDI device. (612)
				// 'index' is a table index (up to the number of devices answered
				// by the sqOpenMIDI call).
				// 'name' is interpreted as (char *) and is written into--the Smalltalk
				// code must pre-allocate a ByteArray of size 64 or greater.
				// Answer the interface's direction  (see sqMIDIioPort struct below).
int sqGetMIDIDeviceName(int tableIndex, int deviceName);	

				// Send data to the given device now. (613)
				// 'message' is interpreted as (unsigned char *);
				// 'length' is the number of bytes of data to send.
				// 'interface' is the number of a device.
				// Answer the number of bytes written.
int sqMIDIPlaySizeOn(int MIDImessage, int length, int device);	

				// Read input into a MIDI packet. (614)
				// 'MIDIpacket' is interpreted as (MIDIPacket *) and is written into
				// with the time-stamp, flags, and length.
				// 'dataBuffer' is interpreted as (unsigned char *) and gets the MIDI
				// message data.
				// Answer the number of data bytes in the packet.
int sqReadMIDIPacket(int MIDIpacket, int maxSize, int dataBuffer);

				// Answer the last-read value of the selected MIDI controller(s)
				// (assuming controller value caching is turned on). (615)
				// Return 0 as a value for controllers for which no data has come
				// in (or should this be an error?).
				// The function stores results values into the array 'into', which
				// is interpreted as (int *).
				// Controller numbers of 0-127 are for the normal MIDI controllers, 
				// 		128-255 are for polyphonic key pressures;
				// 		256-271 are for channel pressures;
				//		272-287 are used for pitchBend.
				// The return value the number of values actually read.
int sqReadMIDIControl(int fromController, int toController, int into);

				// General-purpose MIDI driver feature query/set call (like UNIX
				// device driver ioctl() calls). (616) 
				// 'which' selects the operation (see the flags defined below);
				// 'onOff' is a flag for choosing query/set/clear operations
				// Answer the result (true/false, or a number)
int sqMIDIioctl(int whichIoctl, int onOff);


/***********************************************************************************
 * MIDI Driver ioctl flags
 */
 
////////// ioctl selectors //////////

				// Is a MIDI driver installed? True iff the VM includes the MIDI 
				// prims and can successfully open the OS-level MIDI driver.
#define sqMIDIInstalled		1

				// What driver version is this? (May be platform-specific.)
#define sqMIDIVersion		2

				// Is there a time-stamped output buffer? If yes, you may use an 
				// extended version of the sqMIDIPlaySizeOn primitive that includes 
				// an offset time so you can schedule events in the future
				// (e.g., sqMIDIPlaySizeOnAt).
#define sqMIDIHasBuffer		3

				// Is there a 1-call note command? If yes, you may use an extended
				// version of the sqMIDIPlaySizeOn primitive that includes the note 
				// duration and schedules note-off messages in the driver.
				// (e.g., sqMIDIPlaySizeOnAtDur).
#define sqMIDIHasDurs		4

				// Does the driver have its own clock? If yes, there may be special
				// primitives to get/set its value.
#define sqMIDIHasClock		5

				// Should the driver signal a semaphore in input? If yes, the semaphore 
				// passed down in the sqOpenMIDI call will be signalled on all event 
				// input, and also on controller input of controller caching is turned off.
#define sqMIDIUseSemaphore	6

				// Should we echo in-coming events from the driver? If yes, all incoming 
				// packets are echo'ed immediately.
#define sqMIDIEcho			7

				// Should we cache controller values for polling? If yes, controller messages
				// do not trigger the read semaphore, but the controller values are stored in 
				// tables in the driver. If on, it is assumed that applications will poll for 
				// controller values using sqReadMIDIControl.
#define sqMIDIControllerCache	8

				// How many events are in the input Q? Answers the number of available packets.
#define sqMIDIEventsAvailable	9

				// Special flag to flush the driver's I/O buffers.
#define sqMIDIFlushDriver		10


////////// ioctl arguments //////////

#define sqMIDIQuery		0		// Query about the state of a feature or flag
#define sqMIDITurnOn	1		// Turn it on
#define sqMIDITurnOff	2		// Turn it off


/***********************************************************************************
 * MIDI Command Codes
 */

#define NoteOnCmd		0x90
#define NoteOffCmd		0x80
#define PgmChngCmd		0xC0
#define ControlCmd		0xB0
#define PolyPressCmd	0xA0
#define ChanPressCmd	0xD0
#define PchWheelCmd		0xE0
#define SysExCmd		0xF0


/***********************************************************************************
 * Event queue entry struct -- platform-dependent
 */
 
#define PKT_LEN		255

typedef struct sqMIDIEvent {
	long 			startTime;		// start time in clock ticks
	long			timeStamp;		// timestamp in arbitrary units
	unsigned char	flags;			// continutation, timestamped, etc.
	unsigned char	len;			// number of MIDI bytes
	unsigned char	data[PKT_LEN];		// MIDI data buffer
} sqMIDIEvent;


/***********************************************************************************
 * I/O Port struct -- platform-dependent
 */
typedef struct sqMIDIioPort {
	char	name[64];				// port name
	int		direction;				// port direction 1=in, 2=out, 3=both
} sqMIDIioPort;


/***********************************************************************************
 *    E N D
 */
