85 lines
2.2 KiB
C++
85 lines
2.2 KiB
C++
// intellectual property is bullshit bgdc
|
|
|
|
#ifndef MIDIX_HPP
|
|
#define MIDIX_HPP
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <inttypes.h>
|
|
#include <assert.h>
|
|
|
|
#include <etl/queue_spsc_locked.h>
|
|
#include <avrstuff/serial.hpp>
|
|
#include <avrstuff/ringbuf.hpp>
|
|
#include "midi.hpp"
|
|
|
|
#define MIDIX_SYSEX_LEN 64
|
|
#define MIDIX_SYSEX_OVERHEAD 2
|
|
// Must at least equal LEN + OVERHEAD, should be a power of 2
|
|
#define MIDIX_SYSEX_OUT_LEN 128
|
|
|
|
typedef iringbuf<struct midi_message> midi_iqueue;
|
|
|
|
// MIDI transceiver. MIDI messages are received from the RXC ISR and placed
|
|
// into a queue. Outgoing MIDI messages are transmitted from an internal
|
|
// queue.
|
|
class midix {
|
|
public:
|
|
midix(serial & serport, midi_iqueue & mq)
|
|
: m_serport(serport)
|
|
, m_sysex_buf_avail(true)
|
|
, m_message_pos(0)
|
|
, m_receiving_sysex(false)
|
|
, m_queue(mq)
|
|
{
|
|
m_message.source = this;
|
|
m_message.command = MIDI_ICMD_NOP;
|
|
}
|
|
|
|
// Receive Complete interrupt. Call within the serial port's RXC ISR.
|
|
void rxc();
|
|
|
|
// Data Register Empty interrupt. Call within the port's DRE ISR.
|
|
void dre();
|
|
|
|
// Transmit a raw message. Message is NUL terminated.
|
|
void send(uint8_t const * msg);
|
|
|
|
// Transmit a sysex message, adding the correct guard bytes. Message
|
|
// is NUL terminated.
|
|
void send_sysex(uint8_t const * msg);
|
|
|
|
// Release the sysex buffer. When a message is enqueued containing
|
|
// sysex content, it contains a reference to this midix's internal
|
|
// sysex buffer. This can only be used once, so it must be released
|
|
// when no longer needed. If another sysex is received while the buffer
|
|
// is held, it is rejected and becomes a MIDI_ICMD_SYSEX_OVERFLOW.
|
|
//
|
|
// buf: buffer to release. Must be the original buffer given in
|
|
// midi_message.content
|
|
void sysex_release_buffer(uint8_t * buf);
|
|
|
|
private:
|
|
// Send the current message and initialize it for the next one
|
|
void send()
|
|
{
|
|
m_queue.push(m_message);
|
|
m_message_pos = 0;
|
|
m_message.command = MIDI_ICMD_NOP;
|
|
m_receiving_sysex = false;
|
|
}
|
|
|
|
serial & m_serport;
|
|
uint8_t m_sysex_buf[MIDIX_SYSEX_LEN];
|
|
bool m_sysex_buf_avail;
|
|
|
|
struct midi_message m_message;
|
|
size_t m_message_pos;
|
|
bool m_receiving_sysex;
|
|
midi_iqueue & m_queue;
|
|
|
|
ringbuf<uint8_t, 128> m_outbuf;
|
|
};
|
|
|
|
#endif // !defined(MIDIX_HPP)
|