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.