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

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.