midi.c 1.57 KB
Newer Older
Jacob Vosmaer's avatar
Jacob Vosmaer committed
1 2 3 4 5 6 7 8 9 10
/*

  midi.c

UART I/O and MIDI parsing.

*/

#include "midi.h"

11
uint8_t midi_channel;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
12 13

void
Jacob Vosmaer's avatar
Jacob Vosmaer committed
14 15 16 17 18
midi_set_channel(uint8_t channel)
{
	midi_channel = channel & 0xf;
}

19 20
uint8_t status;
uint16_t data;
21
uint8_t parsed_len;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
22

23
const uint8_t statuses[MIDI_NUM_STATUSES] = {
Jacob Vosmaer's avatar
Jacob Vosmaer committed
24 25 26 27 28 29
	0b1001, // note on
	0b1000, // note off
};

uint8_t
data_len(uint8_t st)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
30
{
Jacob Vosmaer's avatar
Jacob Vosmaer committed
31 32
	// Some channel messages have only 1 data byte, but we don't support any of those yet.
	return 2;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
33 34 35
}

uint8_t
Jacob Vosmaer's avatar
Jacob Vosmaer committed
36
midi_status(void)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
37
{
Jacob Vosmaer's avatar
Jacob Vosmaer committed
38 39 40 41 42 43 44
	return status;
}

uint16_t midi_data(void)
{
	return data;
}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
45

Jacob Vosmaer's avatar
Jacob Vosmaer committed
46 47 48
uint8_t
midi_available(void)
{
49
	return (status < MIDI_NUM_STATUSES) && (data_len(status) == parsed_len);
Jacob Vosmaer's avatar
Jacob Vosmaer committed
50 51
}

52 53 54 55 56 57 58 59 60 61 62 63 64
void
clear_data()
{
	parsed_len = 0;
	data = 0;
}

void
reset_status()
{
	status = MIDI_NUM_STATUSES;
}

Jacob Vosmaer's avatar
Jacob Vosmaer committed
65 66 67
void
midi_parse(uint8_t midi_byte)
{
Jacob Vosmaer's avatar
Jacob Vosmaer committed
68 69
	if ((midi_byte & 0xf8) == 0xf8) {
		// Ignore MIDI real time messages
Jacob Vosmaer's avatar
Jacob Vosmaer committed
70
		return;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
71 72
	}

73
	for (uint8_t i = 0; i < MIDI_NUM_STATUSES; i++) {
Jacob Vosmaer's avatar
Jacob Vosmaer committed
74 75 76
		if (midi_byte == ((statuses[i] << 4) | midi_channel)) {
			status = i;
			return;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
77
		}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
78
	}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
79

80
	if (status == MIDI_NUM_STATUSES) {
Jacob Vosmaer's avatar
Jacob Vosmaer committed
81 82
		return;
	}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
83

Jacob Vosmaer's avatar
Jacob Vosmaer committed
84
	if (midi_byte & 0x80) {
85 86
		reset_status();
		clear_data();
Jacob Vosmaer's avatar
Jacob Vosmaer committed
87 88
		return;
	}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
89

Jacob Vosmaer's avatar
Jacob Vosmaer committed
90
	if (parsed_len >= 2) {
91
		clear_data();
Jacob Vosmaer's avatar
Jacob Vosmaer committed
92
	}
Jacob Vosmaer's avatar
Jacob Vosmaer committed
93

Jacob Vosmaer's avatar
Jacob Vosmaer committed
94 95 96 97 98 99 100 101
	switch (parsed_len ) {
	case 0:
		data = midi_byte << 8;
		parsed_len++;
		break;
	case 1:
		data |= midi_byte;
		parsed_len++;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
102 103 104 105
		break;
	}
}

106
void
107
status_init(void)
108 109 110 111 112
{
	clear_data();
	reset_status();
}

113 114 115 116 117 118 119
void
midi_init()
{
	uart_init();
	status_init();
}

Jacob Vosmaer's avatar
Jacob Vosmaer committed
120 121
uint8_t
midi_read(void)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
122
{
123 124 125
	uint16_t uart_data = uart_read();
	if (uart_data >> 8) {
		// uart error
Jacob Vosmaer's avatar
Jacob Vosmaer committed
126
		return 0;
Jacob Vosmaer's avatar
Jacob Vosmaer committed
127 128
	}

129
	midi_parse(uart_data & 0xff);
Jacob Vosmaer's avatar
Jacob Vosmaer committed
130
	return midi_available();
Jacob Vosmaer's avatar
Jacob Vosmaer committed
131
}