File midi.h¶
File List > external-docs > libDaisy > src > hid > midi.h
Go to the documentation of this file
Source Code¶
#pragma once
#ifndef DSY_MIDI_H
#define DSY_MIDI_H
#include <stdint.h>
#include <stdlib.h>
#include <algorithm>
#include "per/uart.h"
#include "util/ringbuffer.h"
#include "util/FIFO.h"
#include "hid/midi_parser.h"
#include "hid/usb_midi.h"
#include "sys/dma.h"
#include "sys/system.h"
namespace daisy
{
class MidiUartTransport
{
public:
typedef void (*MidiRxParseCallback)(uint8_t* data,
size_t size,
void* context);
MidiUartTransport() {}
~MidiUartTransport() {}
struct Config
{
UartHandler::Config::Peripheral periph;
Pin rx;
Pin tx;
uint8_t* rx_buffer;
size_t rx_buffer_size;
Config();
};
inline void Init(Config config)
{
UartHandler::Config uart_config;
//defaults
uart_config.baudrate = 31250;
uart_config.stopbits = UartHandler::Config::StopBits::BITS_1;
uart_config.parity = UartHandler::Config::Parity::NONE;
uart_config.mode = UartHandler::Config::Mode::TX_RX;
uart_config.wordlength = UartHandler::Config::WordLength::BITS_8;
//user settings
uart_config.periph = config.periph;
uart_config.pin_config.rx = config.rx;
uart_config.pin_config.tx = config.tx;
rx_buffer = config.rx_buffer;
rx_buffer_size = config.rx_buffer_size;
std::fill(rx_buffer, rx_buffer + rx_buffer_size, 0);
uart_.Init(uart_config);
}
inline void StartRx(MidiRxParseCallback parse_callback, void* context)
{
parse_context_ = context;
parse_callback_ = parse_callback;
dsy_dma_clear_cache_for_buffer((uint8_t*)this,
sizeof(MidiUartTransport));
uart_.DmaListenStart(
rx_buffer, rx_buffer_size, MidiUartTransport::rxCallback, this);
}
inline bool RxActive() { return uart_.IsListening(); }
inline void FlushRx() {}
inline void Tx(uint8_t* buff, size_t size) { uart_.PollTx(buff, size); }
private:
UartHandler uart_;
uint8_t* rx_buffer;
size_t rx_buffer_size;
void* parse_context_;
MidiRxParseCallback parse_callback_;
static void rxCallback(uint8_t* data,
size_t size,
void* context,
UartHandler::Result res)
{
MidiUartTransport* transport
= reinterpret_cast<MidiUartTransport*>(context);
if(res == UartHandler::Result::OK)
{
if(transport->parse_callback_)
{
transport->parse_callback_(
data, size, transport->parse_context_);
}
}
}
};
template <typename Transport>
class MidiHandler
{
public:
MidiHandler() {}
~MidiHandler() {}
struct Config
{
typename Transport::Config transport_config;
};
void Init(Config config)
{
config_ = config;
transport_.Init(config_.transport_config);
parser_.Init();
}
void StartReceive()
{
transport_.StartRx(MidiHandler::ParseCallback, this);
}
void Listen()
{
// In case of UART Error, (particularly
// overrun error), UART disables itself.
// Flush the buff, and restart.
if(!transport_.RxActive())
{
parser_.Reset();
transport_.FlushRx();
StartReceive();
}
}
bool HasEvents() const { return event_q_.GetNumElements() > 0; }
bool RxActive() { return transport_.RxActive(); }
MidiEvent PopEvent() { return event_q_.PopFront(); }
void SendMessage(uint8_t* bytes, size_t size)
{
transport_.Tx(bytes, size);
}
void Parse(uint8_t byte)
{
MidiEvent event;
if(parser_.Parse(byte, &event))
{
event_q_.PushBack(event);
}
}
private:
Config config_;
Transport transport_;
MidiParser parser_;
FIFO<MidiEvent, 256> event_q_;
static void ParseCallback(uint8_t* data, size_t size, void* context)
{
MidiHandler* handler = reinterpret_cast<MidiHandler*>(context);
for(size_t i = 0; i < size; i++)
{
handler->Parse(data[i]);
}
}
};
using MidiUartHandler = MidiHandler<MidiUartTransport>;
using MidiUsbHandler = MidiHandler<MidiUsbTransport>;
} // namespace daisy
#endif