Skip to content

Commit

Permalink
Separate MIDI parsing from USB communication
Browse files Browse the repository at this point in the history
No new code was added, the functionality of the original MIDIDeviceBase
class has been separated into two classes:
1. The new LowLevelMIDIDeviceBase class only deals with low-level MIDI
over USB communication, like reading and writing 32-bit USB-MIDI event
packets.
2. The MIDIDeviceBase class inherits from the LowLevelMIDIDeviceBase
class and parses the MIDI data, calling user-provided callbacks.
The code for reading a USB-MIDI event packet from the rx buffer and
starting the next rx data transfer that was originally part of the
MIDIDeviceBase::read() method has been moved into a separate
LowLevelMIDIDeviceBase::read_packed() method.
  • Loading branch information
tttapa committed Feb 26, 2024
1 parent b6f94f7 commit 9db3ad9
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 125 deletions.
146 changes: 78 additions & 68 deletions USBHost_t36.h
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,61 @@ class JoystickController : public USBDriver, public USBHIDInput, public BTHIDInp

//--------------------------------------------------------------------------

class MIDIDeviceBase : public USBDriver {
class LowLevelMIDIDeviceBase : public USBDriver {
public:
LowLevelMIDIDeviceBase(USBHost &host, uint32_t *rx, uint32_t *tx1, uint32_t *tx2,
uint16_t bufsize, uint32_t *rqueue, uint16_t qsize) :
txtimer(this), rx_buffer(rx), tx_buffer1(tx1), tx_buffer2(tx2),
rx_queue(rqueue), max_packet_size(bufsize), rx_queue_size(qsize) {
init();
}

void write_packed(uint32_t data);
uint32_t read_packed();
void send_now(void) __attribute__((always_inline)) {}

protected:
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
virtual void disconnect();
virtual void timer_event(USBDriverTimer *timer);
static void rx_callback(const Transfer_t *transfer);
static void tx_callback(const Transfer_t *transfer);
void rx_data(const Transfer_t *transfer);
void tx_data(const Transfer_t *transfer);
void init();
private:
Pipe_t *rxpipe;
Pipe_t *txpipe;
USBDriverTimer txtimer;
//enum { MAX_PACKET_SIZE = 64 };
//enum { RX_QUEUE_SIZE = 80 }; // must be more than MAX_PACKET_SIZE/4
//uint32_t rx_buffer[MAX_PACKET_SIZE/4];
//uint32_t tx_buffer1[MAX_PACKET_SIZE/4];
//uint32_t tx_buffer2[MAX_PACKET_SIZE/4];
uint32_t * const rx_buffer;
uint32_t * const tx_buffer1;
uint32_t * const tx_buffer2;
uint16_t rx_size;
uint16_t tx_size;
//uint32_t rx_queue[RX_QUEUE_SIZE];
uint32_t * const rx_queue;
bool rx_packet_queued;
const uint16_t max_packet_size;
const uint16_t rx_queue_size;
uint16_t rx_head;
uint16_t rx_tail;
volatile uint8_t tx1_count;
volatile uint8_t tx2_count;
uint8_t rx_ep;
uint8_t tx_ep;
uint8_t rx_ep_type;
uint8_t tx_ep_type;
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1];
};

class MIDIDeviceBase : protected LowLevelMIDIDeviceBase {
public:
enum { SYSEX_MAX_LEN = 290 };

Expand All @@ -1192,12 +1246,7 @@ class MIDIDeviceBase : public USBDriver {
ActiveSensing = 0xFE, // System Real Time - Active Sensing
SystemReset = 0xFF, // System Real Time - System Reset
};
MIDIDeviceBase(USBHost &host, uint32_t *rx, uint32_t *tx1, uint32_t *tx2,
uint16_t bufsize, uint32_t *rqueue, uint16_t qsize) :
txtimer(this), rx_buffer(rx), tx_buffer1(tx1), tx_buffer2(tx2),
rx_queue(rqueue), max_packet_size(bufsize), rx_queue_size(qsize) {
init();
}
using LowLevelMIDIDeviceBase::LowLevelMIDIDeviceBase;
void sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t cable = 0) {
send(0x80, note, velocity, channel, cable);
}
Expand Down Expand Up @@ -1316,8 +1365,7 @@ class MIDIDeviceBase : public USBDriver {
| ((data1 & 0x7F) << 16) | ((data2 & 0x7F) << 24));
}
}
void send_now(void) __attribute__((always_inline)) {
}
using LowLevelMIDIDeviceBase::send_now;
bool read(uint8_t channel = 0);
uint8_t getType(void) {
return msg_type;
Expand Down Expand Up @@ -1433,75 +1481,37 @@ class MIDIDeviceBase : public USBDriver {
handleRealTimeSystem = fptr;
}
protected:
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
virtual void disconnect();
virtual void timer_event(USBDriverTimer *timer);
static void rx_callback(const Transfer_t *transfer);
static void tx_callback(const Transfer_t *transfer);
void rx_data(const Transfer_t *transfer);
void tx_data(const Transfer_t *transfer);
void init();
void write_packed(uint32_t data);
void send_sysex_buffer_has_term(const uint8_t *data, uint32_t length, uint8_t cable);
void send_sysex_add_term_bytes(const uint8_t *data, uint32_t length, uint8_t cable);
void sysex_byte(uint8_t b);
private:
Pipe_t *rxpipe;
Pipe_t *txpipe;
USBDriverTimer txtimer;
//enum { MAX_PACKET_SIZE = 64 };
//enum { RX_QUEUE_SIZE = 80 }; // must be more than MAX_PACKET_SIZE/4
//uint32_t rx_buffer[MAX_PACKET_SIZE/4];
//uint32_t tx_buffer1[MAX_PACKET_SIZE/4];
//uint32_t tx_buffer2[MAX_PACKET_SIZE/4];
uint32_t * const rx_buffer;
uint32_t * const tx_buffer1;
uint32_t * const tx_buffer2;
uint16_t rx_size;
uint16_t tx_size;
//uint32_t rx_queue[RX_QUEUE_SIZE];
uint32_t * const rx_queue;
volatile bool rx_packet_queued;
const uint16_t max_packet_size;
const uint16_t rx_queue_size;
uint16_t rx_head;
uint16_t rx_tail;
volatile uint8_t tx1_count;
volatile uint8_t tx2_count;
uint8_t rx_ep;
uint8_t tx_ep;
uint8_t rx_ep_type;
uint8_t tx_ep_type;
uint8_t msg_cable;
uint8_t msg_channel;
uint8_t msg_type;
uint8_t msg_data1;
uint8_t msg_data2;
uint8_t msg_sysex[SYSEX_MAX_LEN];
uint16_t msg_sysex_len;
void (*handleNoteOff)(uint8_t ch, uint8_t note, uint8_t vel);
void (*handleNoteOn)(uint8_t ch, uint8_t note, uint8_t vel);
void (*handleVelocityChange)(uint8_t ch, uint8_t note, uint8_t vel);
void (*handleControlChange)(uint8_t ch, uint8_t control, uint8_t value);
void (*handleProgramChange)(uint8_t ch, uint8_t program);
void (*handleAfterTouch)(uint8_t ch, uint8_t pressure);
void (*handlePitchChange)(uint8_t ch, int pitch);
void (*handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete);
void (*handleSysExComplete)(uint8_t *data, unsigned int size);
void (*handleTimeCodeQuarterFrame)(uint8_t data);
void (*handleSongPosition)(uint16_t beats);
void (*handleSongSelect)(uint8_t songnumber);
void (*handleTuneRequest)(void);
void (*handleClock)(void);
void (*handleStart)(void);
void (*handleContinue)(void);
void (*handleStop)(void);
void (*handleActiveSensing)(void);
void (*handleSystemReset)(void);
void (*handleRealTimeSystem)(uint8_t rtb);
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1];
uint16_t msg_sysex_len = 0;
void (*handleNoteOff)(uint8_t ch, uint8_t note, uint8_t vel) = nullptr;
void (*handleNoteOn)(uint8_t ch, uint8_t note, uint8_t vel) = nullptr;
void (*handleVelocityChange)(uint8_t ch, uint8_t note, uint8_t vel) = nullptr;
void (*handleControlChange)(uint8_t ch, uint8_t control, uint8_t value) = nullptr;
void (*handleProgramChange)(uint8_t ch, uint8_t program) = nullptr;
void (*handleAfterTouch)(uint8_t ch, uint8_t pressure) = nullptr;
void (*handlePitchChange)(uint8_t ch, int pitch) = nullptr;
void (*handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete) = nullptr;
void (*handleSysExComplete)(uint8_t *data, unsigned int size) = nullptr;
void (*handleTimeCodeQuarterFrame)(uint8_t data) = nullptr;
void (*handleSongPosition)(uint16_t beats) = nullptr;
void (*handleSongSelect)(uint8_t songnumber) = nullptr;
void (*handleTuneRequest)(void) = nullptr;
void (*handleClock)(void) = nullptr;
void (*handleStart)(void) = nullptr;
void (*handleContinue)(void) = nullptr;
void (*handleStop)(void) = nullptr;
void (*handleActiveSensing)(void) = nullptr;
void (*handleSystemReset)(void) = nullptr;
void (*handleRealTimeSystem)(uint8_t rtb) = nullptr;
};

class MIDIDevice : public MIDIDeviceBase {
Expand Down
94 changes: 37 additions & 57 deletions midi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,11 @@
#define print USBHost::print_
#define println USBHost::println_

void MIDIDeviceBase::init()
void LowLevelMIDIDeviceBase::init()
{
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
handleNoteOff = NULL;
handleNoteOn = NULL;
handleVelocityChange = NULL;
handleControlChange = NULL;
handleProgramChange = NULL;
handleAfterTouch = NULL;
handlePitchChange = NULL;
handleSysExPartial = NULL;
handleSysExComplete = NULL;
handleTimeCodeQuarterFrame = NULL;
handleSongPosition = NULL;
handleSongSelect = NULL;
handleTuneRequest = NULL;
handleClock = NULL;
handleStart = NULL;
handleContinue = NULL;
handleStop = NULL;
handleActiveSensing = NULL;
handleSystemReset = NULL;
handleRealTimeSystem = NULL;
rx_head = 0;
rx_tail = 0;
rxpipe = NULL;
Expand Down Expand Up @@ -83,7 +63,7 @@ void MIDIDeviceBase::init()
// EP_CONTROL_UNDEFINED 0x00
// ASSOCIATION_CONTROL 0x01

bool MIDIDeviceBase::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
bool LowLevelMIDIDeviceBase::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
// only claim at interface level
if (type != 1) return false;
Expand Down Expand Up @@ -210,30 +190,25 @@ bool MIDIDeviceBase::claim(Device_t *dev, int type, const uint8_t *descriptors,
}
rx_head = 0;
rx_tail = 0;
msg_channel = 0;
msg_type = 0;
msg_data1 = 0;
msg_data2 = 0;
msg_sysex_len = 0;
// claim if either pipe created
return (rxpipe || txpipe);
}

void MIDIDeviceBase::rx_callback(const Transfer_t *transfer)
void LowLevelMIDIDeviceBase::rx_callback(const Transfer_t *transfer)
{
if (transfer->driver) {
((MIDIDevice *)(transfer->driver))->rx_data(transfer);
((LowLevelMIDIDeviceBase *)(transfer->driver))->rx_data(transfer);
}
}

void MIDIDeviceBase::tx_callback(const Transfer_t *transfer)
void LowLevelMIDIDeviceBase::tx_callback(const Transfer_t *transfer)
{
if (transfer->driver) {
((MIDIDevice *)(transfer->driver))->tx_data(transfer);
((LowLevelMIDIDeviceBase *)(transfer->driver))->tx_data(transfer);
}
}

void MIDIDeviceBase::rx_data(const Transfer_t *transfer)
void LowLevelMIDIDeviceBase::rx_data(const Transfer_t *transfer)
{
println("MIDIDevice Receive");
print(" MIDI Data: ");
Expand Down Expand Up @@ -266,7 +241,7 @@ void MIDIDeviceBase::rx_data(const Transfer_t *transfer)
}
}

void MIDIDeviceBase::tx_data(const Transfer_t *transfer)
void LowLevelMIDIDeviceBase::tx_data(const Transfer_t *transfer)
{
println("MIDIDevice transmit complete");
print(" MIDI Data: ");
Expand All @@ -279,7 +254,7 @@ void MIDIDeviceBase::tx_data(const Transfer_t *transfer)
}


void MIDIDeviceBase::disconnect()
void LowLevelMIDIDeviceBase::disconnect()
{
// should rx_queue be cleared?
// as-is, the user can still read MIDI messages
Expand All @@ -289,7 +264,7 @@ void MIDIDeviceBase::disconnect()
}


void MIDIDeviceBase::write_packed(uint32_t data)
void LowLevelMIDIDeviceBase::write_packed(uint32_t data)
{
if (!txpipe) return;
uint32_t tx_max = tx_size / 4;
Expand Down Expand Up @@ -328,7 +303,7 @@ void MIDIDeviceBase::write_packed(uint32_t data)
}
}

void MIDIDeviceBase::timer_event(USBDriverTimer *timer)
void LowLevelMIDIDeviceBase::timer_event(USBDriverTimer *timer)
{
const uint32_t tx_max = tx_size / 4;
uint32_t tx1 = tx1_count;
Expand All @@ -343,6 +318,28 @@ void MIDIDeviceBase::timer_event(USBDriverTimer *timer)
}
}

uint32_t LowLevelMIDIDeviceBase::read_packed() {
uint32_t n, head, tail, avail;
__disable_irq();
bool packet_queued = rx_packet_queued;
head = rx_head;
tail = rx_tail;
__enable_irq();
if (head == tail) return 0;
if (++tail >= rx_queue_size) tail = 0;
n = rx_queue[tail];
rx_tail = tail;
if (!packet_queued && rxpipe) {
avail = (head < tail) ? tail - head - 1 : rx_queue_size - 1 - head + tail;
if (avail >= (uint32_t)(rx_size>>2)) {
rx_packet_queued = true;
queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this);
}
}
println("read: ", n, HEX);
return n;
}

void MIDIDeviceBase::send_sysex_buffer_has_term(const uint8_t *data, uint32_t length, uint8_t cable)
{
cable = (cable & 0x0F) << 4;
Expand Down Expand Up @@ -389,29 +386,12 @@ void MIDIDeviceBase::send_sysex_add_term_bytes(const uint8_t *data, uint32_t len
}
}




bool MIDIDeviceBase::read(uint8_t channel)
{
uint32_t n, head, tail, avail, ch, type1, type2, b1;
__disable_irq();
bool packet_queued = rx_packet_queued;
head = rx_head;
tail = rx_tail;
__enable_irq();
if (head == tail) return false;
if (++tail >= rx_queue_size) tail = 0;
n = rx_queue[tail];
rx_tail = tail;
if (!packet_queued && rxpipe) {
avail = (head < tail) ? tail - head - 1 : rx_queue_size - 1 - head + tail;
if (avail >= (uint32_t)(rx_size>>2)) {
rx_packet_queued = true;
queue_Data_Transfer(rxpipe, rx_buffer, rx_size, this);
}
}
println("read: ", n, HEX);
uint32_t n, ch, type1, type2, b1;

n = read_packed();
if (n == 0) return false;

type1 = n & 15;
type2 = (n >> 12) & 15;
Expand Down

0 comments on commit 9db3ad9

Please sign in to comment.