Commit f7a78c3a authored by Jacob Vosmaer's avatar Jacob Vosmaer

Rewrite midi parser

parent 3b3ebc1a
......@@ -10,45 +10,6 @@ UART I/O and MIDI parsing.
#include "notes.h"
#include <avr/io.h>
// MIDI parser state machine states
enum _midi_state {
MIDI_START,
MIDI_NOTE,
MIDI_KEY,
MIDI_VELOCITY
};
uint16_t midi_event = 0;
void midi_set_event(uint8_t note, uint8_t velocity) {
midi_event = note | (velocity << 8);
}
void
handle_note_on(uint8_t pitch, uint8_t velocity)
{
if (velocity == 0) {
return;
}
switch(pitch) {
case 35:
case 36:
midi_set_event(NOTE_BD, velocity);
break;
case 38:
case 40:
midi_set_event(NOTE_SD, velocity);
break;
case 34:
midi_set_event(NOTE_RM, velocity);
break;
case 42:
midi_set_event(NOTE_CH, velocity);
break;
}
}
void
midi_init()
{
......@@ -61,76 +22,96 @@ midi_init()
PORTD |= _BV(PORTD0);
}
static uint8_t midi_note_on_byte;
static uint8_t midi_channel;
void
midi_set_channel(uint8_t midi_channel)
midi_set_channel(uint8_t channel)
{
midi_channel = channel & 0xf;
}
uint8_t status = MIDI_NO_STATUS;
uint16_t data = 0;
static uint8_t parsed_len = 0;
const uint8_t statuses[MIDI_NO_STATUS] = {
0b1001, // note on
0b1000, // note off
};
uint8_t
data_len(uint8_t st)
{
// Some channel messages have only 1 data byte, but we don't support any of those yet.
return 2;
}
uint8_t
midi_status(void)
{
midi_note_on_byte = (0b1001 << 4) | (midi_channel & 0xf);
return status;
}
uint16_t midi_data(void)
{
return data;
}
// midi_parse is a state machine that recognizes MIDI note-on messages
// on a fixed channel. Once it has parsed a relevant note-on it will call
// handle_note_on as a side effect.
uint8_t
midi_parse(uint8_t state, uint8_t midi_byte)
midi_available(void)
{
static uint8_t key;
return (status < MIDI_NO_STATUS) && (data_len(status) == parsed_len);
}
void
midi_parse(uint8_t midi_byte)
{
if ((midi_byte & 0xf8) == 0xf8) {
// Ignore MIDI real time messages
return state;
return;
}
switch (state) {
case MIDI_START :
if (midi_byte == midi_note_on_byte) {
return MIDI_NOTE;
for (uint8_t i = 0; i < MIDI_NO_STATUS; i++) {
if (midi_byte == ((statuses[i] << 4) | midi_channel)) {
status = i;
return;
}
return MIDI_START;
break;
case MIDI_NOTE :
if (midi_byte & _BV(7)) {
return MIDI_START;
}
key = midi_byte;
return MIDI_KEY;
break;
case MIDI_KEY :
if (midi_byte & _BV(7)) {
return MIDI_START;
if (status == MIDI_NO_STATUS) {
return;
}
handle_note_on(key, midi_byte);
return MIDI_VELOCITY;
break;
case MIDI_VELOCITY :
if (midi_byte == midi_note_on_byte) {
return MIDI_NOTE;
if (midi_byte & 0x80) {
status = MIDI_NO_STATUS;
data = 0;
return;
}
if (midi_byte & _BV(7)) {
return MIDI_START;
if (parsed_len >= 2) {
data = 0;
parsed_len = 0;
}
key = midi_byte;
return MIDI_KEY;
switch (parsed_len ) {
case 0:
data = midi_byte << 8;
parsed_len++;
break;
case 1:
data |= midi_byte;
parsed_len++;
break;
}
return MIDI_START;
}
void
midi_read()
uint8_t
midi_read(void)
{
static uint8_t midi_state = MIDI_START;
uint8_t uart_status = UCSR0A;
if (!(uart_status & _BV(RXC0))) {
// No UART data available
return;
return 0;
}
// Read data to clear all status bits
......@@ -138,9 +119,9 @@ midi_read()
if (uart_status & (_BV(FE0) | _BV(DOR0) | _BV(UPE0))) {
// There was a UART error
midi_state = MIDI_START;
return;
return 0;
}
midi_state = midi_parse(midi_state, uart_data);
midi_parse(uart_data);
return midi_available();
}
......@@ -3,16 +3,16 @@
#include <inttypes.h>
// We run Timer0 at F_CPU/1024, so 15.6 kHz. This number, relative to
// Timer0, is tuned (??) so that we get a pulse of just over 10ms on the trig
// outputs.
#define PULSE 180
enum _statuses {
MIDI_NOTE_ON,
MIDI_NOTE_OFF,
MIDI_NO_STATUS,
};
// This variable is shared between the MIDI parser and the event parser.
extern uint16_t midi_event;
void midi_read();
uint8_t midi_read();
void midi_init();
void midi_set_channel(uint8_t channel);
uint8_t midi_status();
uint16_t midi_data();
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment