This is next-midi-3-0-block.c in view mode; [Download] [Up]
/* interface to NeXT 3.0 midi driver. * if using Franz, compile by: cc -DEXCL next-2-0-midi.c -c -O * * This version blocks if too many bytes are written. */ #define EXCL 1 #ifndef EXCL #ifndef AKCL #error "missing compilation flag: need AKCL or EXCL !" #endif #endif #import <mach.h> #import <stdio.h> #import <stdlib.h> #import <mach_error.h> #import <signal.h> #import <servers/netname.h> #import <libc.h> #import <appkit/nextstd.h> #import <mididriver/midi_driver.h> #import <mididriver/midi_spec.h> #import <cthreads.h> static port_t driverPort; /* Port for driver on particular host. */ static port_t ownerPort; /* Port that represents ownership */ static port_t dataPort; /* Port for incoming data. */ static port_t queuePort; /* Port for output queue notification messages */ static port_t exceptionPort; /* Port for timing exceptions */ static port_t alarmPort; /* To get periodic messages. */ static int maxQueueSize; /* Maximum output queue size */ static int halfQueueSize; /* Maximum output queue size/2 */ static int unit; /* Serial port to send to */ static port_set_name_t ports; /* Port set to listen for messages from driver */ static int quantaSize=1000; static int quantaTime=0; /* Thread Globals */ int Listening = 0; int Writing = 0; mutex_t queueLock; mutex_t listeningLock; mutex_t schedulerLock; /* Handler Declarations */ static void myDataReply(port_t replyPort, short unit, MIDIRawEvent *eventbuf, unsigned int count); static void myAlarmReply(port_t replyPort, int requestedTime, int actualTime); static void myExceptionReply(port_t replyPort, int exception); static void myQueueReply(port_t replyPort, short unit); /* MIDI Messages */ typedef struct _MIDIMessage { unsigned long time; unsigned long message; struct _MIDIMessage *next; } MIDIMessage; static MIDIMessage *firstMessage = NULL; static MIDIMessage *lastMessage = NULL; static int lastTime = -1; static int Scheduling; #define SCHEDULER_ADVANCE 50 void startScheduler() { Scheduling = 1; } void stopScheduler() { mutex_lock(schedulerLock); Scheduling = 0; mutex_unlock(schedulerLock); firstMessage = NULL; lastMessage = NULL; } int midiopen(int port) /* port=0 for A, 1 for B */ { kern_return_t r; int synchUnit; /* Serial port to listen for time code */ if (port==0) unit=MIDI_PORT_A_UNIT; else if (port==1) unit=MIDI_PORT_B_UNIT; else return KERN_FAILURE; r = netname_look_up(name_server_port, "","mididriver", &driverPort); if (r != KERN_SUCCESS) return r; r = port_allocate(task_self(), &ownerPort); if (r != KERN_SUCCESS) return 0; r = MIDIBecomeOwner(driverPort,ownerPort); if (r != KERN_SUCCESS) return r; r = MIDIClaimUnit(driverPort, ownerPort,unit); if (r != KERN_SUCCESS) return r; r = MIDISetClockMode(driverPort, ownerPort, synchUnit, MIDI_CLOCK_MODE_INTERNAL); if (r != KERN_SUCCESS) return r; r = MIDISetClockQuantum(driverPort, ownerPort, quantaSize); if (r != KERN_SUCCESS) return r; r = MIDISetSystemIgnores(driverPort, ownerPort, unit, MIDI_IGNORE_REAL_TIME); if (r != KERN_SUCCESS) return r; /* create the various ports */ r = port_allocate(task_self(), &queuePort); if (r != KERN_SUCCESS) return r; r = port_allocate(task_self(), &exceptionPort); if (r != KERN_SUCCESS) return r; r = port_allocate(task_self(), &dataPort); if (r != KERN_SUCCESS) return r; r = port_allocate(task_self(), &alarmPort); if (r != KERN_SUCCESS) return r; /* create the port set and add the ports */ r = MIDIRequestExceptions(driverPort, ownerPort, exceptionPort); if (r != KERN_SUCCESS) return r; r = MIDIGetAvailableQueueSize(driverPort, ownerPort, unit, &maxQueueSize); if (r != KERN_SUCCESS) return r; halfQueueSize = maxQueueSize / 2; r = MIDISetClockTime(driverPort, ownerPort, quantaTime); if (r != KERN_SUCCESS) return r; r = MIDIStartClock(driverPort, ownerPort); if (r != KERN_SUCCESS) return r; /* DAJ: Moved this to here. Note that you only have to do it once, not * every invocation of midireadmessages(). */ r = MIDIRequestData(driverPort, ownerPort, unit, dataPort); if (r != KERN_SUCCESS) return r; listeningLock = mutex_alloc(); /* i should free these */ schedulerLock = mutex_alloc(); queueLock = mutex_alloc(); Listening = 0; /* startScheduler(); */ return KERN_SUCCESS; } int midiclose() { kern_return_t r; if (!driverPort || !ownerPort) return KERN_SUCCESS; r = MIDIReleaseOwnership(driverPort,ownerPort); if (r != KERN_SUCCESS) return r; r = port_deallocate(task_self(), exceptionPort); if (r != KERN_SUCCESS) return r; r = port_deallocate(task_self(), queuePort); if (r != KERN_SUCCESS) return r; r = port_deallocate(task_self(), dataPort); if (r != KERN_SUCCESS) return r; r = port_deallocate(task_self(), alarmPort); if (r != KERN_SUCCESS) return r; quantaTime=0; quantaSize=1000; return KERN_SUCCESS; } int midistarttimer() { return MIDIStartClock(driverPort, ownerPort); } int midistoptimer() { return MIDIStopClock(driverPort, ownerPort); } int midisetquantasize(int usec) { quantaSize=usec; return MIDISetClockQuantum(driverPort, ownerPort, usec); } int midisettime(int time) { quantaTime=time; MIDIClearQueue(driverPort, ownerPort, unit); return MIDISetClockTime(driverPort, ownerPort, time); } int midigettime(int *time) { kern_return_t r; r = MIDIGetClockTime(driverPort, ownerPort, &quantaTime); if (r != KERN_SUCCESS) return r; time[0]=quantaTime; time[1]=quantaSize; return KERN_SUCCESS; } static int waitForRoom(int size) { int r; MIDIReplyFunctions recvStruct = {0}; r = MIDIRequestQueueNotification(driverPort,ownerPort, unit,queuePort,maxQueueSize/2); if (r != KERN_SUCCESS) return r; r = MIDIAwaitReply(queuePort,&recvStruct,MIDI_NO_TIMEOUT); /* THIS BLOCKS! */ return r; } int midiwritemessage(int message, int qtime) { kern_return_t r = KERN_SUCCESS; MIDIRawEvent events[16]; int byte=16; int size=(message & 0x03000000) >> 24; int i; message=message & 0xffffff; for (i=0; i<size; i++) { events[i].time=qtime; events[i].byte=(char)((message >> byte) & 0xff); byte -= 8; } for (;;) { r = MIDISendData(driverPort, ownerPort, unit, events, size); if (r == MIDI_ERROR_QUEUE_FULL) { r = waitForRoom(size); if (r != KERN_SUCCESS) break; } else break; } return r; } int midireadmessages() { kern_return_t r; char msgBuf[MIDI_MAX_MSG_SIZE]; msg_header_t *msg = (msg_header_t *)msgBuf; MIDIReplyFunctions funcs = {0, 0, 0, 0}; int keepGoing = TRUE; funcs.dataReply = (MIDIDataReplyFunction)myDataReply; while (keepGoing) { msg->msg_local_port = dataPort; msg->msg_size = MIDI_MAX_MSG_SIZE; r = msg_receive(msg, (RCV_TIMEOUT | RCV_INTERRUPT), 0); /* Changed to 0 by daj */ switch (r) { case RCV_SUCCESS: r = MIDIHandleReply(msg, &funcs); /* Simplifed by DAJ */ break; case RCV_TIMED_OUT: r = KERN_SUCCESS; default: keepGoing = FALSE; break; } } return r; } int midiflushxmit() { return KERN_SUCCESS; } int midiflushrecv() { return KERN_SUCCESS; } int midihush() { return KERN_SUCCESS; } int midiallnotesoff() { return KERN_SUCCESS; } #ifdef EXCL #define MIDI_INPUT_HOOK 0 #endif #define DataTag 0x0 #define ChannelTag 0x4000000 #define SystemTag 0x8000000 #define MetaTag 0xc000000 static void myDataReply(port_t replyPort, short unit, MIDIRawEvent *eventbuf, unsigned int count) { static unsigned char status = 0; static int length = 0; static int datastart = 0; static int bytenum = 0; static int datalsh = 0; static unsigned typeid = 0; static unsigned message = 0; MIDIRawEvent *e; char data; #ifdef EXCL long lisp_call(int index, unsigned msg, unsigned tim); #endif #ifdef AKCL void MIDI_INPUT_HOOK(int msg, int tim); #endif for (e = eventbuf; count--; e++) { data = e->byte; if (data & MIDI_STATUSBIT) { status = data; typeid = (MIDI_TYPE_SYSTEM(status)) ? SystemTag : ChannelTag; if (MIDI_TYPE_1BYTE(status)) { length = 1; datastart = 0; } else if (MIDI_TYPE_2BYTE(status)) { length = 2; datastart = 0; } else { length = 3; datastart = 8; } datalsh = datastart; bytenum = 1; message = 0; } else { message |= ((data << datalsh) & (0xff << datalsh)); if (datalsh == 0) datalsh = datastart; else datalsh -= 8; bytenum++; } if (bytenum == length) { message |= (typeid | ((length << 24) & 0x03000000) | ((status << 16) & 0xff0000)); #ifdef EXCL lisp_call(MIDI_INPUT_HOOK, message, (unsigned)e->time); #endif #ifdef AKCL MIDI_INPUT_HOOK((int)message,(int)e->time); #endif bytenum = 1; message = 0; datalsh = datastart; } } } static void myAlarmReply(port_t replyPort, int requestedTime, int actualTime) { } static void myExceptionReply(port_t replyPort, int exception) { }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.