/*
 * sgidrv.c -- A MIDI driver that uses the SGI midi library.. 
 *
 *  Copyright 1998 - Rob Fletcher and John Stone
 *              (rpf1@york.ac.uk)     (j.stone@acm.org)
 * 
 *  $Id: sgidrv.c,v 1.7 1998/02/24 17:12:04 johns Exp $
 *
 */

#ifdef __sgi

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dmedia/midi.h> /* Include the SGI midi header files - surprise! */

#include "seq.h"      /* protos for MidiIOEvent */
#include "devices.h"  /* protos for device installation code */

#define  SGIDRV_INTERNAL
#include "sgidrv.h"  /* protos and types for this file */

static char sgidrv_drivername[] = "SGI";
static char sgidrv_version[] = "$Revision: 1.7 $";



int sgidrv_drvinst(AddMIDIDriverFunc adddriver, MidiSystem * midisystem) {
  MidiDriver drvinfo;

  drvinfo.typename  = sgidrv_drivername;
  drvinfo.version   = sgidrv_version;
  drvinfo.flags     = DEVICE_HAS_TIMER;
  drvinfo.openfunc  = sgidrv_open;
  drvinfo.writefunc = sgidrv_write;   
  drvinfo.readfunc  = sgidrv_read;
  drvinfo.closefunc = sgidrv_close;

  adddriver(midisystem, drvinfo);

  return 0;
}



int sgidrv_open(MidiDeviceSetupParms name, MidiDeviceHandle * handleptr, int *iofd) {

SGI_ports *Midiports;
int i, nports;

  nports=mdInit();
  if (nports < 0) {
    return -1; /* startmidi is not currently running */
  }

  if (nports == 0) {
    return -1; /* no ports are installed */
  }

  if ( nports > MAXIOPORTS) {
    printf("ERROR. %d is too many ports. Increase the size of MAXPORTS and re-build\n",
            nports*2);
    return -1;
  }

  Midiports = malloc(sizeof(SGI_ports));

  if (Midiports == NULL) {
     printf("Couldn't allocate space for MIDI port(s)\n");   
    return -1;
  }

  Midiports->numports = nports *2 ; /* Allow in and out for each */

/* Cycle round each port and assign in and out */
  for( i = 0; i < Midiports->numports ; i = i+2 ) {

    Midiports->port[i] = mdOpenOutPort(mdGetName(i));
    if( Midiports->port[i] == NULL ) {
       printf("Could not Open MIDI Out port %s\n",mdGetName(i));
       return -1;
    }
    mdSetStampMode(Midiports->port[i],MD_DELTASTAMP);

    Midiports->port[i+1] =  mdOpenInPort(mdGetName(i));
    if( Midiports->port[i+1] == NULL ) {
       printf("Could not Open MIDI In port %s\n",mdGetName(0));
       return -1;
    }
    mdSetStampMode(Midiports->port[i+1],MD_DELTASTAMP);
  }

/* Set the "default" input and output ports - make the code nicer to read! */
  Midiports->output = Midiports->port[0];
  Midiports->input  = Midiports->port[1];

  *iofd = -1;				/* Set the input fd */
  *handleptr = (void *)Midiports;
  *iofd = mdGetFd( Midiports->input ); /* Get the input port fd */
  return 0;
}




int sgidrv_write(MidiDeviceHandle handle, MidiIOEvent * ev) {
  MDevent MidiEvent;   /* SGI midi event structure */
  int i;
  int SendReturnCode;
  unsigned long long time ;
  SGI_ports *Midi = (SGI_ports *) handle;

  if (mdGetStampMode( (MDport) Midi->output  ) == MD_DELTASTAMP) {
    time =  (unsigned long long)ev->delay.tv_sec * 1000000000 +
            (unsigned long long)ev->delay.tv_nsec;
  }

  /* Copy event data over to the SGI structure */
  for( i=0; i< ev->msglen ; i++ )
    MidiEvent.msg[i] = ev->msg[i];

  MidiEvent.stamp  = time;
  MidiEvent.msglen = ev->msglen;

  SendReturnCode = mdSend( (MDport)Midi->output, &MidiEvent, 1);
  if (SendReturnCode <= 0) {
    if (SendReturnCode == 0) {
      printf("Error. Could not send any messages.\n");
    }
    else {
      printf("Error. %d message(s) sent in error.\n",SendReturnCode*-1);
      printf("msg len %d  time  %d\n",MidiEvent.msglen,(int) MidiEvent.stamp);
      printf("msg data:  %x   %d   %x    %x\n\n",MidiEvent.msg[0],
                 MidiEvent.msg[1],MidiEvent.msg[2],MidiEvent.msg[3]);
    }

    printf("OSERROR = %d\n",goserror());
    return -1;
  }

  return 0;
}




int sgidrv_read(MidiDeviceHandle handle, MidiIOEvent * ev) {

  SGI_ports *Midi = (SGI_ports *) handle;
  MDevent MidiEvent;   	 /* SGI midi event structure */
  int i;

   /* Get any available MIDI message. */
    mdReceive((MDport)Midi->input, &MidiEvent, 1);

    ev->msglen = MidiEvent.msglen;
    for (i=0; i<MidiEvent.msglen; i++) {
      ev->msg[i] = MidiEvent.msg[i];
    }  

    ev->delay.tv_sec = MidiEvent.stamp / 1000000000;
    ev->delay.tv_nsec = MidiEvent.stamp % 1000000000;

  return 0;
}




int sgidrv_close(MidiDeviceHandle * handleptr) {
  SGI_ports *Midi = (SGI_ports *) *handleptr;

  if (handleptr != NULL) {
    mdClosePort((MDport) Midi->output);
    mdClosePort((MDport) Midi->input);
    free(*handleptr);
    *handleptr=NULL;
   return 0;
  }

  return 0;
}

#endif



