/*
 * midimsg.c -- Midi event parsing code
 *
 * $Id: midievents.c,v 1.3 1998/02/09 01:49:56 johns Exp $
 *
 */

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

#include "synth.h"      /* synth control function protos */
#include "midievents.h" /* MIDI event masks etc */
#include "midisim.h"

static performance * synthptr;

midiHandle * MidiInit(void) {
  midiHandle * handle;

  handle = (midiHandle *) malloc(sizeof(midiHandle));
  memset(handle, 0, sizeof(midiHandle)); 
 
  return handle;
} 

void MidiClose(midiHandle * handle) {
  free(handle);
} 

static int MidiChannel(midiHandle * handle) {
  return (handle->buf[0] & MIDI_CHAN_MASK) + 1;
}

static int MidiNote(midiHandle * handle) {
  return (handle->buf[1] & MIDI_DATA_MASK);
}

static int MidiVelocity(midiHandle * handle) {
  return (handle->buf[2] & MIDI_DATA_MASK);
}

static int MidiController(midiHandle * handle) {
  return (handle->buf[1] & MIDI_DATA_MASK);
}

static int MidiValue(midiHandle * handle) {
  return (handle->buf[2] & MIDI_DATA_MASK);
}

static int MidiProgram(midiHandle * handle) {
  return (handle->buf[1] & MIDI_DATA_MASK);
}

static int MidiChanPressure(midiHandle * handle) {
  return (handle->buf[1] & MIDI_DATA_MASK);
}

static int MidiPitchbend(midiHandle * handle) {
  unsigned int tmp;

  tmp = handle->buf[1];
  tmp |= (handle->buf[2] << 7);
  
  return tmp;
}

void MidiDefaultHandler(midiHandle * handle) {
  int velocity;

  switch (handle->buf[0] & MIDI_STATUS_TYPE_MASK) {
    case MIDI_NOTE_OFF:
      printf("Note off: ");
      printf("channel %d ", MidiChannel(handle));
      printf("note %d ", MidiNote(handle));
      printf("velocity %d ", MidiVelocity(handle));
      printf("\n");

perf_note_off(synthptr, MidiChannel(handle), MidiNote(handle));

      break;

    case MIDI_NOTE_ON:
      if ((velocity = MidiVelocity(handle)) != 0) {
        printf("Note on: ");
        printf("channel %d ", MidiChannel(handle));
        printf("note %d ", MidiNote(handle));
        printf("velocity %d ", velocity);
        printf("\n");
perf_note_on(synthptr, MidiChannel(handle), MidiNote(handle), velocity);
      }
      else {
        printf("Note off: ");
        printf("channel %d ", MidiChannel(handle));
        printf("note %d ", MidiNote(handle));
        printf("velocity %d ", velocity);
        printf("\n");
perf_note_off(synthptr, MidiChannel(handle), MidiNote(handle));
      }
      break;

    case MIDI_KEY_TOUCH:
      printf("Key Pressure: ");
      printf("channel %d ", MidiChannel(handle));
      printf("note %d ", MidiNote(handle));
      printf("pressure %d ", MidiVelocity(handle));
      printf("\n");
      break;

    case MIDI_CONTROL:
      printf("Control Change: ");
      printf("channel %d ", MidiChannel(handle));
      printf("controller %d ", MidiController(handle));
      printf("value %d ", MidiValue(handle));
      printf("\n");
      if (MidiController(handle) == 123) {
perf_allnotesoff(synthptr, MidiChannel(handle));        
      }
      break;

    case MIDI_PITCHBEND:
      printf("Pitch Bend: ");
      printf("channel %d ", MidiChannel(handle));
      printf("value %d ", MidiPitchbend(handle)); 
      printf("\n");
      break;

    /* Messages with 1 data byte */
    case MIDI_PROG_CHNG:
      printf("Program Change: ");
      printf("channel %d ", MidiChannel(handle));
      printf("program %d ", MidiProgram(handle));
      printf("\n");
      break;

    case MIDI_CHAN_TOUCH:
      printf("Channel Pressure: ");
      printf("channel %d ", MidiChannel(handle));
      printf("pressure %d ", MidiChanPressure(handle));
      printf("\n");
      break;

    /* Special MIDI messages, can be varying length */
    case MIDI_SYSCOMMON: /* should dispatch handlers for this stuff */
      printf("System Exclusive\n");
      break;

    default:
      printf("Unknown MIDI Status\n");
      break;
  }
}



void MidiAddByte(midiHandle * handle, unsigned char b, void * synth) {
  synthptr = synth;
  if (b & MIDI_STATUS_MASK) {

    switch (b & MIDI_STATUS_TYPE_MASK) {
      case MIDI_NOTE_OFF:
      case MIDI_NOTE_ON:
      case MIDI_KEY_TOUCH:
      case MIDI_CONTROL:
      case MIDI_PITCHBEND:
        handle->buf[0] = b;
        handle->bufpos=1;
        handle->buflen=3; 
        break;

      /* Messages with 1 data byte */
      case MIDI_PROG_CHNG:
      case MIDI_CHAN_TOUCH:
        handle->buf[0] = b;
        handle->bufpos=1;
        handle->buflen=2; 
        break;

      /* Special MIDI messages, can be varying length */
      case MIDI_SYSCOMMON: /* should dispatch handlers for this stuff */
if (b != 0xf8)
  printf("System Message: %2x\n", b); 
        handle->buf[0]=0;
        handle->bufpos=0;
        handle->buflen=0;
        break;
        
      /* Out of sync, got data without matching status */
      default: 
printf("Unknown MIDI Status Message\n");
        handle->buf[0]=0;
        handle->bufpos=0;
        handle->buflen=0;
        break;
    }

    return;
  } 

  /* got a MIDI data byte, but didn't get the status byte that went with it */
  if (handle->buf[0] == 0) 
    return; 

  if (handle->bufpos < handle->buflen) {
    handle->buf[handle->bufpos] = b; /* add data byte to buffer */
    handle->bufpos++;
  }

  if (handle->bufpos >= handle->buflen) {
    MidiDefaultHandler(handle); /* do something with the MIDI event */
    handle->bufpos=1;
  }
}


