/* midi.c */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <sys/midiio.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "vm.h"

#define PORT "/dev/music"

int midi_fd;
int midi_bytes;
seq_event_rec midi_buf;
int midi_initialised = 0;

int midi_init(void)
{
	midi_fd = open(PORT, O_NONBLOCK | O_RDONLY, 0);
	if (midi_fd == -1) {
		err(1, "failed to open MIDI port");
	}
	midi_bytes = 0;
	midi_initialised = 1;
	vm_register_signal_fd(midi_fd, VM_MIDIQ);
	return 1;
}

void midi_close(void)
{
	printf("Closing MIDI\n");
	ioctl(midi_fd, SEQUENCER_SYNC, NULL);
	ioctl(midi_fd, SEQUENCER_RESET, NULL);
	printf("...\n");
	close(midi_fd);
	printf("X.\n");
	midi_fd = 0;
	midi_initialised = 0;
}

/*
 * Returns non-zero if we're interested in the packet
 * received. Zero otherwise. 
 */
int midi_filter(void)
{
	switch (midi_buf.arr[0]) {
	case SEQ_CHN_COMMON:
		/* We don't care about the unit number - yet */
		/* We don't care about the channel - yet */
		if (midi_buf.arr[2] == 0xb0) /* cmd */
			return 1;
		return 0;
	case SEQ_TIMING:
		return 0;
	default:
		printf("Unknown MIDI message received\n");
		return 0;
	}
}

int midi_read(void)
{
	if (!midi_initialised)
		return 0;

	while (1) {
		int rv;
		int left = sizeof(midi_buf) - midi_bytes;
		rv = read(midi_fd, midi_buf.arr + midi_bytes, left);
		if (rv == -1) {
			if (errno == EAGAIN)
				return 0;
			printf("Error reading from MIDI\n");
			close(midi_fd);
			midi_initialised = 0;
		}
		if (rv == 0)
			return 0;
		midi_bytes += rv;
		if (midi_bytes == sizeof(midi_buf)) {
			midi_bytes = 0;
			if (midi_filter())
				return 1;
		}
	}
}


/*
 * Return the interesting bits of the MIDI command.
 * The contents of this function is likely to change
 * as we become interested in more types of MIDI device.
 * Pre-condition: midi_filter() has returned 1
 */
void midi_getcmd(int *button, int *value)
{
	*button = midi_buf.arr[4];
	*value = midi_buf.arr[6];
}
