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. ...@@ -10,45 +10,6 @@ UART I/O and MIDI parsing.
#include "notes.h" #include "notes.h"
#include <avr/io.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 void
midi_init() midi_init()
{ {
...@@ -61,76 +22,96 @@ midi_init() ...@@ -61,76 +22,96 @@ midi_init()
PORTD |= _BV(PORTD0); PORTD |= _BV(PORTD0);
} }
static uint8_t midi_note_on_byte; static uint8_t midi_channel;
void 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)
{ {
midi_note_on_byte = (0b1001 << 4) | (midi_channel & 0xf); // Some channel messages have only 1 data byte, but we don't support any of those yet.
return 2;
} }
// 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 uint8_t
midi_parse(uint8_t state, uint8_t midi_byte) midi_status(void)
{ {
static uint8_t key; return status;
}
uint16_t midi_data(void)
{
return data;
}
uint8_t
midi_available(void)
{
return (status < MIDI_NO_STATUS) && (data_len(status) == parsed_len);
}
void
midi_parse(uint8_t midi_byte)
{
if ((midi_byte & 0xf8) == 0xf8) { if ((midi_byte & 0xf8) == 0xf8) {
// Ignore MIDI real time messages // Ignore MIDI real time messages
return state; return;
} }
switch (state) { for (uint8_t i = 0; i < MIDI_NO_STATUS; i++) {
case MIDI_START : if (midi_byte == ((statuses[i] << 4) | midi_channel)) {
if (midi_byte == midi_note_on_byte) { status = i;
return MIDI_NOTE; return;
} }
return MIDI_START; }
break; if (status == MIDI_NO_STATUS) {
case MIDI_NOTE : return;
if (midi_byte & _BV(7)) { }
return MIDI_START;
}
key = midi_byte;
return MIDI_KEY;
break; if (midi_byte & 0x80) {
case MIDI_KEY : status = MIDI_NO_STATUS;
if (midi_byte & _BV(7)) { data = 0;
return MIDI_START; return;
} }
handle_note_on(key, midi_byte);
return MIDI_VELOCITY;
break; if (parsed_len >= 2) {
case MIDI_VELOCITY : data = 0;
if (midi_byte == midi_note_on_byte) { parsed_len = 0;
return MIDI_NOTE; }
}
if (midi_byte & _BV(7)) {
return MIDI_START;
}
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; break;
} }
return MIDI_START;
} }
void uint8_t
midi_read() midi_read(void)
{ {
static uint8_t midi_state = MIDI_START;
uint8_t uart_status = UCSR0A; uint8_t uart_status = UCSR0A;
if (!(uart_status & _BV(RXC0))) { if (!(uart_status & _BV(RXC0))) {
// No UART data available // No UART data available
return; return 0;
} }
// Read data to clear all status bits // Read data to clear all status bits
...@@ -138,9 +119,9 @@ midi_read() ...@@ -138,9 +119,9 @@ midi_read()
if (uart_status & (_BV(FE0) | _BV(DOR0) | _BV(UPE0))) { if (uart_status & (_BV(FE0) | _BV(DOR0) | _BV(UPE0))) {
// There was a UART error // There was a UART error
midi_state = MIDI_START; return 0;
return;
} }
midi_state = midi_parse(midi_state, uart_data); midi_parse(uart_data);
return midi_available();
} }
...@@ -3,16 +3,16 @@ ...@@ -3,16 +3,16 @@
#include <inttypes.h> #include <inttypes.h>
// We run Timer0 at F_CPU/1024, so 15.6 kHz. This number, relative to enum _statuses {
// Timer0, is tuned (??) so that we get a pulse of just over 10ms on the trig MIDI_NOTE_ON,
// outputs. MIDI_NOTE_OFF,
#define PULSE 180 MIDI_NO_STATUS,
};
// This variable is shared between the MIDI parser and the event parser. uint8_t midi_read();
extern uint16_t midi_event;
void midi_read();
void midi_init(); void midi_init();
void midi_set_channel(uint8_t channel); void midi_set_channel(uint8_t channel);
uint8_t midi_status();
uint16_t midi_data();
#endif #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