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.