ftp.nice.ch/pub/next/unix/music/cm.sd.tar.gz#/midi/next-2-0-midi.c

This is next-2-0-midi.c in view mode; [Download] [Up]

/* 
 * this code is adapted from sources written by Boynton
 * and Massie in /NextDeveloper/Examples/MidiDriver. 
 * if in Franz on next, compile by: cc -DEXCL next-2-0-midi.c -c -O
 */

#ifndef EXCL
	#ifndef  AKCL
		#error "missing compilation flags: need AKCL or EXCL !"
	#endif
#endif
	
#import <mach.h>
#import <stdio.h>
#import <stdlib.h>
#import <fcntl.h>
#import <mach_error.h>
#import <servers/netname.h>
#import <strings.h>
#import <midi/midi_server.h>
#import <midi/midi_reply_handler.h>
#import <midi/midi_timer.h>
#import <midi/midi_timer_reply_handler.h>
#import <midi/midi_error.h>
#import <midi/midi_timer_error.h>

typedef struct {
    int quanta;	
    unsigned int metaevent:1;
    unsigned int ndata:7;
    unsigned char data[3];
} midievent_t;

port_t midiPort;
port_t ownerPort;
port_t negotiationPort;
port_t timerPort;
port_t timerReplyPort;
port_t xmitPort;
port_t xmitReplyPort;
port_t recvPort;
port_t recvReplyPort;
port_set_name_t portSet;

u_int quantaTime = 0;
u_int quantaSize = 1000;

int midiopen(int port);
int midiclose();
int midistarttimer();
int midistoptimer();
int midisetquantasize(int usec);
int midisettime(int qtime);
int midigettime(int *databuf);
int midireadmessages();
int midiwritemessage(int msg, int qtime);
int midihush();
int midiflush();

kern_return_t myTimerReplyHandler (
  void *arg, 
	timeval_t timeval,
  u_int quanta, u_int quantumSize,
  u_int realUsecPerQuantum,
  boolean_t timerExpired,
  boolean_t timerStopped,
  boolean_t timerForward
);

midi_timer_reply_t midiTimerReply = {
	myTimerReplyHandler,
	0,
	0
};

kern_return_t myRecvRawDataHandler(
  void * arg,
	midi_raw_t rawData,
  u_int rawDataCnt
);

kern_return_t myRecvCookedDataHandler(
  void *arg,
  midi_cooked_t cookedData,
  u_int cookedDataCnt
);

kern_return_t myRecvPackedDataHandler(
  void * arg,
  u_int quanta,
  midi_packed_t packedData,
  u_int packedDataCnt
);

kern_return_t myQueueNotifyHandler(
  void * arg,
  u_int queueSize
);

midi_reply_t midiReply = {
	myRecvRawDataHandler,
	myRecvCookedDataHandler,
	myRecvPackedDataHandler,
	myQueueNotifyHandler,
	0,
	0
};

#define max(a, b) ((a) > (b) ? (a) : (b))

u_int queue_max = max(MIDI_COOKED_DATA_MAX, MIDI_RAW_DATA_MAX)*2;

int midiopen(int port)
{
	kern_return_t r;
	char *midiPortName;

	if (port==0)
		midiPortName="midi0";
	else if (port==1)
		midiPortName="midi1";
	else return KERN_FAILURE;
	r = netname_look_up(NameServerPort, "", midiPortName, &midiPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("timer_track: netname_look_up error", r);
		return r;
	}
	r = port_allocate(task_self(), &ownerPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("allocate owner port", r);
		return r;
	}
	negotiationPort = PORT_NULL;
	r = midi_set_owner(midiPort, ownerPort, &negotiationPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("become owner", r);
		return r;
	}
	r = midi_get_out_timer_port(midiPort, &timerPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("output timer port", r);
		return r;
	}
	r = midi_get_xmit(midiPort, ownerPort, &xmitPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("xmit port", r);
		return r;
	}
	r = midi_get_recv(midiPort, ownerPort, &recvPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("recv port", r);
		return r;
	}
	r = port_allocate(task_self(), &timerReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("allocate timer reply port", r);
		return r;
	}
	r = port_allocate(task_self(), &xmitReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("allocate xmit reply port", r);
		return r;
	}
	r = port_allocate(task_self(), &recvReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("allocate recv reply port", r);
		return r;
	}
	r = midi_set_proto(xmitPort, MIDI_PROTO_COOKED, FALSE,
                           MIDI_PROTO_SYNC_SYS, 10, 2, queue_max);
	if (r != KERN_SUCCESS)
	{
		mach_error("midi_set_proto", r);
		return r;
	}
	r = midi_set_sys_ignores(recvPort, (MIDI_IGNORE_ACTIVE_SENS
					    | MIDI_IGNORE_TIMING_CLCK
					    | MIDI_IGNORE_START
					    | MIDI_IGNORE_CONTINUE
					    | MIDI_IGNORE_STOP
					    | MIDI_IGNORE_SONG_POS_P));
	if (r != KERN_SUCCESS)
	{
		mach_error("midi_set_sys_ignores", r);
		return r;
	}
	r = midi_set_proto(recvPort, MIDI_PROTO_COOKED, FALSE,
			   MIDI_PROTO_SYNC_SYS, 10, 2, 8192);
	if (r != KERN_SUCCESS)
	{
		mach_error("midi_set_proto", r);
		return r;
	}
	r = midi_get_data(recvPort, recvReplyPort);
	if (r != KERN_SUCCESS)
	{
		midi_timer_error("midi_get_data", r);
		return r;
	}
	r = port_set_allocate(task_self(), &portSet);
	if (r != KERN_SUCCESS)
	{
		mach_error("allocate port set", r);
		return r;
	}
	r = port_set_add(task_self(), portSet, timerReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("add timer_reply_port to set", r);
		return r;
	}
	r = port_set_add(task_self(), portSet, xmitReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("add xmit_reply_port to set", r);
		return r;
	}
	r = port_set_add(task_self(), portSet, recvReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("add recv_reply_port to set", r);
		return r;
	}
	r = timer_start(timerPort, ownerPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("timer start", r);
		return r;
	}
	return KERN_SUCCESS;
}


int midiclose()
{
	kern_return_t r;

	r = port_set_deallocate(task_self(), portSet);
	if (r != KERN_SUCCESS)
	{
		mach_error("deallocate port set", r);
		return r;
	}
	r = port_deallocate(task_self(), xmitReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("deallocate xmit reply port", r);
		return r;
	}
	r = port_deallocate(task_self(), recvReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("deallocate recv reply port", r);
		return r;
	}
	r = port_deallocate(task_self(), timerReplyPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("deallocate timer reply port", r);
		return r;
	}
	r = port_deallocate(task_self(), ownerPort);
	if (r != KERN_SUCCESS)
	{
		mach_error("deallocate owner port", r);
		return r;
	}
	return KERN_SUCCESS;
}


int midistarttimer()
{
	kern_return_t r;

	r = timer_start(timerPort, ownerPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("timer start", r);
		return r;
	}
	return KERN_SUCCESS;
}


int midistoptimer()
{
	kern_return_t r;

	r = timer_stop(timerPort, ownerPort);
	if (r != KERN_SUCCESS)
	{
		midi_error("timer stop", r);
		return r;
	}
	return KERN_SUCCESS;
}


int midisetquantasize(int usec)
{
	kern_return_t r;

	r = timer_set_quantum(timerPort,ownerPort,(u_int)usec);
	if (r != KERN_SUCCESS) 
	{
		midi_error("timer set quantum", r);
		return r;
	}
	quantaSize=(u_int)usec;
	return KERN_SUCCESS;
}


int midisettime(int qtime)    /* time in quanta */
{
	kern_return_t r;
	long utim = qtime*quantaSize;
	timeval_t time; 

	time.tv_sec=utim/1000000;
	time.tv_usec=utim-(time.tv_sec*1000000);
	
	r = timer_set(timerPort, ownerPort, time);
	if (r != KERN_SUCCESS)
	{
		midi_error("timer set time", r);
		return r;
	}
	return KERN_SUCCESS;
}


int midigettime(int *databuf)
{
	msg_header_t *msg;
	kern_return_t r;
	int keepGoing;
	
	msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
	r = timer_quanta_req(timerPort, timerReplyPort, 0, FALSE);
	if (r != KERN_SUCCESS)
	{
		free((char *)msg);
		return r;
	}

	keepGoing = TRUE;
	while (keepGoing)
	{
		msg->msg_size = MSG_SIZE_MAX;
		msg->msg_local_port = portSet;
		r = msg_receive(msg, MSG_OPTION_NONE, 0);
		if (r != KERN_SUCCESS)
		{
			free((char *)msg);
			return r; 
		}
		else keepGoing = FALSE;
	}		
	if (msg->msg_local_port == timerReplyPort)
	{
		r = midi_timer_reply_handler(msg, &midiTimerReply);
		if (r != KERN_SUCCESS)
		{
			free((char *)msg);
			return r;
		}
	}
	else
	{
		free((char *)msg);
		return r;
	}
	free((char *)msg);
	databuf[0]=(int)quantaTime;
	databuf[1]=(int)quantaSize;
	return KERN_SUCCESS;
}


int midiwritemessage(int msg, int qtime)
{
	midi_cooked_data_t cookedData;
	kern_return_t r;
	cookedData.quanta = qtime;
	cookedData.ndata = (char)((msg & 0x03000000) >> 24);
	cookedData.data[0]=(char)((msg & 0x00ff0000) >> 16);

	if (cookedData.ndata > 1)
		cookedData.data[1]=(char)((msg & 0x0000ff00) >> 8);
	if (cookedData.ndata > 2)
		cookedData.data[2]=(char)(msg & 0x000000ff);
	r = midi_send_cooked_data(xmitPort, &cookedData, 1, TRUE); 
	if (r == MIDI_WILL_BLOCK)
	{
		return r;
	}
	else if (r != KERN_SUCCESS)
	{
		midi_error("midi_send_cooked_data", r);
		return r;
	}
	return KERN_SUCCESS;
}

int midiflushrecv()
{
	return (int)midi_clear_queue(recvPort);
}

int midiflushxmit()
{
	return (int)midi_clear_queue(xmitPort);
}

int midiallnotesoff(int time)
{
	int chan, note;
	midi_cooked_data_t off;
	kern_return_t r;
	for (chan = 0; chan < 16; chan++)
	{
		for (note = 0; note < 128; note++)
		{	
	                off.quanta = time;
			off.ndata = 3;
			off.data[0]=(char)(0x80 | chan);
			off.data[1]=(char)note;
			off.data[2]=127;
			midi_send_cooked_data(xmitPort, &off, 1, TRUE);
		}
	}			
	return KERN_SUCCESS;
}

int midihush ()
{
    midiallnotesoff(0);
}

int midireadmessages() 
{
	msg_header_t *msg;
	kern_return_t r = KERN_SUCCESS;
	int keepGoing = TRUE;
	/*
	* Receive midi events in a loop until no more events
	* are available.  This loop should not be necessary,
	* but this driver does not return all the current events
	* at once, ie it takes several calls to midi_get_data to
	* receive all the current messages from the driver.
	*/
	msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
	while (keepGoing)
	{
		r = midi_get_data(recvPort, recvReplyPort);
		if (r != KERN_SUCCESS)
		{
			midi_timer_error("midi_get_data", r);
			break;
		}	 
		msg->msg_size = MSG_SIZE_MAX;
		msg->msg_local_port = portSet;
		r = msg_receive(msg, (RCV_TIMEOUT | RCV_INTERRUPT), 1);
		switch (r)
		{
			case RCV_SUCCESS:
				if (msg->msg_local_port == recvReplyPort)
				r = midi_reply_handler(msg, &midiReply);
				break;
			case RCV_TIMED_OUT:
				r = KERN_SUCCESS;
				keepGoing=FALSE;
				break;
			default:
				r = KERN_FAILURE;
				keepGoing=FALSE;
				break;
		}
	}
	free((char *)msg);
	return r;
}


/*
 *                             Handlers                 
 */

kern_return_t myTimerReplyHandler (
	void *arg, timeval_t timeval,
	u_int quanta, 
	u_int usecPerQuantum,
	u_int realUsecPerQuantum,
	boolean_t timerExpired,
	boolean_t timerStopped,
	boolean_t timerForward)
{	
	quantaTime = quanta;
	quantaSize = usecPerQuantum;
	return KERN_SUCCESS;
}
kern_return_t myRecvRawDataHandler(void * arg, midi_raw_t rawData,
                                   u_int rawDataCnt)
{
}
		
#ifdef EXCL
#define MIDI_INPUT_HOOK 0
#endif

kern_return_t myRecvCookedDataHandler(void * arg,
				      midi_cooked_t cookedData,
				      u_int cookedDataCnt)
{
#ifdef EXCL
	long lisp_call(int index, unsigned tim, unsigned msg);
#endif
#ifdef AKCL
	void MIDI_INPUT_HOOK(int msg, int tim);
#endif
	unsigned message, quanta;
	
	while (cookedDataCnt--)
	{
		quanta=(unsigned)cookedData->quanta;
		/* message type */
		if ((cookedData->data[0] & 0xf0) == 0xf0)
			message = (1 << 27) & 0xc000000;
		else message = (1 << 26) & 0xc000000;
		/* message size */
		message = message | ((cookedData->ndata << 24) & 0x03000000);
		/* message data */
		message = message | ((cookedData->data[0] << 16) & 0xff0000);
		message = message | ((cookedData->data[1] <<  8) & 0xff00);
		message = message |  (cookedData->data[2] & 0xff);
#ifdef EXCL
		lisp_call(MIDI_INPUT_HOOK, message, quanta);
#endif
#ifdef AKCL
		MIDI_INPUT_HOOK((int)message,(int)quanta);
#endif
		cookedData++; 	
	}
}

kern_return_t myRecvPackedDataHandler(void * arg, u_int quanta,
				      midi_packed_t packedData,
				      u_int packedDataCnt)
{
}

kern_return_t myQueueNotifyHandler(void * arg, u_int queueSize)
{
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.