This is sgi-midi-1.0.c in view mode; [Download] [Up]
#include "sgi-midi.h"
#include <sys/wait.h>
#include <task.h>
#include "taskblocks.h"
#include <errno.h>
/*
* If waitpid's 1st argument is -1, it waits for any child.
*/
#define ANYKID -1
ushort array[7] = {0, 0, 0, 0, 0, 0, 0};
/*
static struct semop semops[0] = {0, 0, 0};
#define wait_request(type) wait_request_1(type,semops)
#define lock(object) lock_1(object,semops)
#define request(type) request_1(type,semops)
#define unlock(object) unlock_1(object,semops)
*/
void suicide(int errnr) {
killpg (procgroup, SIGHUP);
exit(errnr);
}
pid_t main_midi_pid;
int n_midi_queues = 0;
MIPortedQueue **midi_queue;
void set_SMPTE_nibble(int *smpte, int snibble, int svalue)
{
smpte[snibble / 2] &= 0xF0 >> ((snibble % 2) * 4);
smpte[snibble / 2] |= svalue << ((snibble % 2) * 4);
}
MIevent_queue *midi_in_queue,*midi_out_queue;
static char *midi_type_strings[] = {
"NOTE OFF ",
"NOTE ON ",
"POLY PRESS",
"CONTROL ",
"PROGRAM ",
"CHAN PRESS",
"PITCH BEND",
"SYSTEM "
};
int myMIDIPrintEvent(FILE *s, MIevent *event)
{
int i, snibble, svalue;
int type, index, status, channel, bend;
static int smpte[4] = { 0, 0, 0, 0 };
static BOOL smpteok[8] = { 0 };
static BOOL smptesend = NO;
MImessage *msg;
long statm;
switch (event->t) {
case MIMESSAGE:
msg = &CHANNEL_MESSAGE(*event);
status = MIstatus(*msg);
channel = MIchannel(*msg);
fprintf(s,"Status: %d\n", status);
index = ((status >> 4) & 0x7);
fprintf(s, "MItime: %ld %ld\n", event->dt.opaque1, event->dt.opaque2);
fprintf(s, "%ld %s ", (MItimegettotalsecs(&(event->dt)) * 1000000) + MItimegetmicros(&(event->dt)), midi_type_strings[index]);
switch (status) {
case MIDI_NoteOff: /*and CHANNEL VOICE */
case MIDI_NoteOn :
case MIDI_PolyKeyPressure :
case MIDI_ControlChange: /* and MIDI_ChannelModeSelect */
fprintf(s, "%3d %3d %3d ", channel, MIbyte1(*msg), MIbyte2(*msg));
break;
case MIDI_ProgramChange:
case MIDI_ChannelPressure:
fprintf(s, "%3d %3d ", channel, MIbyte1(*msg));
break;
case MIDI_PitchBendChange: /* pitch bend */
/*This converts the rather strange format of the pitch bend data bytes
to a 9 bit positive integer. The 7 most significant bits are stored
in the second byte. The two least significant bits are stored in the
second and third (from left to right) bits of the first byte. In
addition, one more maximum value is encoded in the last four bits of
the first byte, which are set only when the bender is at maximum value.
adding this into the value yields 513 position values. -rt */
bend = MIbend(*msg);
fprintf(s, "%3d %4d ", channel, bend - 0x100);
break;
default:
fprintf(s, "UNKNOWN");
break;
}
break;
default:
msg = &CHANNEL_MESSAGE(*event);
switch(MIstatus(*msg)) {
case MIDI_TimeCodeQuarterFrame: /*and MIDI_SystemCommon*/
snibble = SMPTEnibble(*msg);
svalue = SMPTEvalue(*msg);
set_SMPTE_nibble(smpte,snibble,svalue);
smpteok[snibble] = YES;
if (snibble == 0x7) {
smptesend = YES;
for (i=0; i<8 && smptesend; i++)
smptesend = smpteok[i];
if (smptesend) {
SMPTEfprintf(s,smpte);
for (i=0; i<8; i++)
smpteok[i] = NO;
}
}
break;
default:
channel = MIchannel(*msg);
fprintf(s, " ");
fprintf(s, "SYSTEM MESSAGE? %2X %2X %2X ", channel, MIbyte1(*msg), MIbyte2(*msg));
fprintf(s, "SYSTEM MESSAGE? %2X %2X %2X ", channel, MIbyte1(*msg), MIbyte2(*msg));
break;
}
}
fprintf(s, "\n");
fflush(s);
return 1;
}
MIMultiPort *the_output_port, *the_input_port;
MIPortedQueue *input_ported_queue, *output_ported_queue;
int midiclose(MIPortedQueue *q)
{
if (q) {
MIQlock(q->queue);
MIQclose(q->queue);
MIQunlock(q->queue);
} else {
MIQlock(output_ported_queue->queue);
MIQclose(output_ported_queue->queue);
MIQunlock(output_ported_queue->queue);
}
request(SEND_MIDI);
return KERN_SUCCESS;
}
int handle_sighup(int sig)
{
register i;
if (getpid() == main_midi_pid) {
for(i=0; i< n_midi_queues; i++)
midiclose(midi_queue[i]);
/* Destroy the processes and semaphores! */
/*killpg (procgroup, 2);*/
if (semctl (semid, 0, IPC_RMID, (struct semid_ds *) NULL) == -1) {
perror ("semctl IPC_RMID");
exit (1);
}
}
/* shut down the read from midi would be nice here */
/* MIDIFileEndWritingTrack(aStream);
MIDIFileEndWriting(aStream); */
}
HANDLER_RETURN_TYPE
main_sighup_handler(int sig)
{
handle_sighup(sig);
next_handler(sig);
}
HANDLER_RETURN_TYPE
sigint_handler(int sig)
{
register i;
kill(getpid(),SIGHUP);
}
HANDLER_RETURN_TYPE
sigchld_handler(int sig)
{
pid_t pid;
int status;
pid = waitpid(ANYKID, &status, WNOHANG);
while (pid > 0) {
kids--;
#ifdef DEBUG
fprintf(stderr,"Child %d exited\n", pid);
#endif
pid = waitpid(ANYKID, &status, WNOHANG);
}
fprintf(stderr,"Child exited.\n");
}
static BOOL midi_initialized = NO;
void
init_midi ()
{
struct sigaction act;
midi_initialized = YES;
main_midi_pid = get_pid();
init_threads();
std_sigaction(SIGCHLD,sigchld_handler,&act);
std_sigaction(SIGHUP,sighup_handler,&act);
push_handler(SIGCHLD,main_sighup_handler);
std_sigaction(SIGINT,sigint_handler,&act);
#ifdef SYSV
procgroup = setpgrp ();
#else
procgroup = getpid();
setpgrp (0, procgroup);
#endif
semid = semget (IPC_PRIVATE, 7, (SEM_A | SEM_R));
if (semid == -1) {
perror ("semget");
suicide (1);
}
if (semctl (semid, 0, SETALL, (ushort *) array) == -1) {
perror ("semctl SETVAL");
suicide (1);
}
#ifdef DEBUG0
fprintf(stderr,"Semid: %d\n",semid);
#endif
unlock(PRINTMIDI);
}
int midiopen(MIevent_queue *port) /* port=0 for A, 1 for B */
{
MIconfig *midi_config = MInewconfig();
MIMultiPort *the_port = MIMPortNew(0);
u_int parambuf[2];
u_int stamping = MIRELSTAMP;
int i;
kern_return_t r = KERN_SUCCESS;
if (midi_initialized == NO)
init_midi();
parambuf[0] = MI_STAMPING;
parambuf[1] = stamping;
MIsetparams(&midi_config,parambuf,2);
if (MImulti_open(the_port,"rw",&midi_config) < 0) {
perror("Cannot open MIDI port\n");
suicide(-2);
}
MImulti_open(the_port,"rw",&midi_config);
input_ported_queue = MIPortedQNew(0);
MIPQset_name(input_ported_queue,"MIDI IN");
add_port(input_ported_queue,the_port);
output_ported_queue = MIPortedQNew(0);
MIPQset_name(output_ported_queue,"MIDI OUT");
add_port(output_ported_queue,the_port);
the_output_port = the_port;
the_input_port = the_port;
midi_in_queue = input_ported_queue->queue;
midi_out_queue = output_ported_queue->queue;
midi_queue = realloc(midi_queue,sizeof(MIPortedQueue *) * (n_midi_queues + 2));
midi_queue[n_midi_queues++] = input_ported_queue;
midi_queue[n_midi_queues++] = output_ported_queue;
switch(stamping) {
case MIRELSTAMP:
MIsetstart(the_port->port, (struct timeval *) 0);
break;
default:
break;
}
if (ntasks == maxtasks) {
maxtasks += 3;
taskblocks = (void **) realloc(taskblocks, maxtasks * sizeof(void *));
}
if (create_task("MIDIsender",midi_sender,MTB_new(output_ported_queue),0) == -1)
return -1;
if (create_task("MIDIreceiver",midi_receiver, MTB_new(input_ported_queue),0) == -1)
return -1;
return r;
}
int midi_quantasize = 1;
int midistarttimer()
{
return KERN_SUCCESS;
}
int midistoptimer()
{
return KERN_SUCCESS;
}
int midisetquantasize(int usec)
{
fprintf(stderr,"Trying to setup MIDI quanta size on SGI!\n");
return KERN_SUCCESS;
}
int midisettime(int time)
{
struct timeval tv;
tv.tv_sec = time/(1000000/midi_quantasize);
tv.tv_usec = (time*midi_quantasize) % 1000000;
MIsetstart(the_output_port,&tv);
MIsetstart(the_input_port,&tv);
return KERN_SUCCESS;
}
int midigettime(int *time)
{
MItime* tim = MIstart(the_input_port);
time[0]= (MItimegettotalsecs(tim) * 1000000 + MItimegetmicros(tim)) / midi_quantasize;
time[1]= midi_quantasize;
return KERN_SUCCESS;
}
int midiflushrecv()
{
return KERN_SUCCESS;
}
int midiflushxmit()
{
return KERN_SUCCESS;
}
void send_midi_message(int message, int time)
{
MIevent *the_event;
MIQlock(midi_out_queue);
the_event = MIQreserve(midi_out_queue);
MIQunlock(midi_out_queue);
CHANNEL_MESSAGE(*the_event) = message;
#ifdef DEBUG0
fprintf(stderr,"send_midi_message Sending MIDI data:\n");
#endif
#ifdef SENDER_PRINT
lock(PRINTMIDI);
myMIDIPrintEvent(stderr, the_event);
unlock(PRINTMIDI);
#endif
/* if (the_event->dt != (MItime *) NULL)
free(the_event->dt);
the_event->dt = MItimecreatemicros(time);*/
send_midi(midi_out_queue,the_event);
}
int midiwritemessage(int message, int qtime)
{
kern_return_t r = KERN_SUCCESS;
send_midi_message( message & 0xffffff, qtime);
return r;
}
int midiallnotesoff(int time)
{
int c,k,m;
MIevent *the_event;
u_int channel;
u_int opcode;
char data1, data2;
for (c=0;c<16;c++)
for (k=0;k<128;k++)
/* cobble up note off message */
send_midi_message(0x7800040 | ((c<<16) & 0xf0000) | ((k<<8) & 0xff00),
time);
return KERN_SUCCESS;
}
int midihush ()
{
midiallnotesoff(0);
midiclose(output_ported_queue);
}
#ifdef EXCL
#define MIDI_INPUT_HOOK 0
#endif
int midireadmessages()
{
MIevent *event;
long message;
long time;
long device;
struct sembuf semops;
#ifdef EXCL
long lisp_call(int index, unsigned msg, unsigned tim);
#endif
#ifdef AKCL
void MIDI_INPUT_HOOK(int msg, int tim);
#endif
#ifdef LISPWORKS
void MIDI_INPUT_HOOK(int msg, int tim);
#endif
for(MIQlock(midi_in_queue);
/*MIQlock(midi_in_queue),*/
midi_in_queue->length > 0
/*,MIQunlock(midi_in_queue)*/
;) {
/*wait_request(RECEIVE_MIDI); WRONG!!*/
semdec(semid,RECEIVE_MIDI,"midireadmessages RECEIVE_MIDI request check",&semops);
/* MIQlock(midi_in_queue); */
event = MIQpop(midi_in_queue);
MIQunlock(midi_in_queue);
switch (event->t) {
case MIMESSAGE:
message = (long) (CHANNEL_MESSAGE(*event));
device = MIdevice(message);
message = (message & 0xffffff) |
((MIlength(message) << 24) & 0x03000000); /* message size */
/* message type */
if ((message & 0xf00000) == 0xf00000)
message = ((1 << 27) & 0xc000000) | message;
else
message = ((1 << 26) & 0xc000000) | message;
#ifdef DEBUG
fprintf(stderr,"Read MIMESSAGE: %ld\n", message);
lock(PRINTMIDI);
myMIDIPrintEvent(stderr, event);
unlock(PRINTMIDI);
#endif
break;
default:
message = (long) SYSEX_MESSAGE(*event);
#ifdef DEBUG
fprintf(stderr,"Read SYSEX: %ld\n", message);
#endif
SYSEX_MESSAGE(*event) = (u_char *) NULL;
}
time = MItimegettotalsecs(&(event->dt)) * 1000000 + MItimegetmicros(&(event->dt));
#ifdef EXCL
lisp_call(MIDI_INPUT_HOOK, message, (unsigned)time);
#endif
#ifdef AKCL
MIDI_INPUT_HOOK((int)message,(int) time);
#endif
#ifdef LISPWORKS
MIDI_INPUT_HOOK((int)message,(int) time);
#endif
MIQlock(midi_in_queue);
MIQrecycle(midi_in_queue,event);
/*MIQunlock(midi_in_queue);*/
}
MIQunlock(midi_in_queue);
return KERN_SUCCESS;
}
void
midi_receive_callback(midi_daemon_block *my)
{
struct sembuf semops;
seminc(semid,RECEIVE_MIDI,"midi_receive_callback RECEIVE_MIDI request",&semops);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.