#include "midi.h"
#include <cstring>
#include <vector>
#include <alsa/asoundlib.h>
#include <libraries/Midi/Midi.h>
namespace {
Midi *self(BelaMidi *midi) { return reinterpret_cast<Midi *>(midi); }
int output_available(const char *port) {
snd_rawmidi_t *out = nullptr;
int err = snd_rawmidi_open(nullptr, &out, port, SND_RAWMIDI_NONBLOCK);
if (err) {
return err;
}
snd_rawmidi_close(out);
return 0;
}
void discard_sysex(midi_byte_t, void *) {}
}
extern "C" {
unsigned int bela_midi_list_ports(char *buf, unsigned int len) {
std::vector<Midi::Port> ports;
try {
ports = Midi::listAllPorts();
} catch (...) {
return 0;
}
unsigned int needed = 0;
bool copying = true;
for (const Midi::Port &port : ports) {
const unsigned int size = port.name.size() + 1;
if (copying && needed + size <= len) {
memcpy(buf + needed, port.name.c_str(), size);
} else {
copying = false;
}
needed += size;
}
return needed;
}
BelaMidi *bela_midi_new(void) {
Midi *midi = nullptr;
try {
midi = new Midi();
midi->enableParser(true);
midi->getParser()->setSysexCallback(discard_sysex, nullptr);
} catch (...) {
delete midi;
return nullptr;
}
return reinterpret_cast<BelaMidi *>(midi);
}
void bela_midi_delete(BelaMidi *midi) {
try {
delete self(midi);
} catch (...) {
}
}
int bela_midi_read_from(BelaMidi *midi, const char *port) {
Midi *m = self(midi);
if (m->isInputEnabled()) {
return BELA_MIDI_ALREADY_OPEN;
}
int ret;
try {
if (!Midi::exists(port)) {
return BELA_MIDI_NO_SUCH_PORT;
}
ret = m->readFrom(port);
} catch (...) {
return -1;
}
if (m->isInputEnabled()) {
return 0;
}
return ret < 0 ? ret : -1;
}
int bela_midi_write_to(BelaMidi *midi, const char *port) {
Midi *m = self(midi);
if (m->isOutputEnabled()) {
return BELA_MIDI_ALREADY_OPEN;
}
int ret;
try {
if (!Midi::exists(port)) {
return BELA_MIDI_NO_SUCH_PORT;
}
ret = output_available(port);
if (ret) {
return ret;
}
ret = m->writeTo(port);
} catch (...) {
return -1;
}
if (m->isOutputEnabled()) {
return 0;
}
return ret < 0 ? ret : -1;
}
int bela_midi_available_messages(BelaMidi *midi) {
MidiParser *parser = self(midi)->getParser();
if (!parser) {
return 0;
}
return parser->numAvailableMessages();
}
unsigned int bela_midi_get_message(BelaMidi *midi, unsigned char *buf) {
MidiParser *parser = self(midi)->getParser();
if (!parser) {
return 0;
}
MidiChannelMessage message;
do {
if (parser->numAvailableMessages() <= 0) {
return 0;
}
message = parser->getNextChannelMessage();
} while (message.getType() == kmmNone);
buf[0] = message.getStatusByte() | message.getChannel();
unsigned int size = message.getNumDataBytes();
if (size > BELA_MIDI_MESSAGE_MAX - 1) {
size = BELA_MIDI_MESSAGE_MAX - 1;
}
for (unsigned int n = 0; n < size; ++n) {
buf[n + 1] = message.getDataByte(n);
}
return size + 1;
}
int bela_midi_write_output(BelaMidi *midi, const unsigned char *bytes,
unsigned int length) {
return self(midi)->writeOutput(const_cast<midi_byte_t *>(bytes), length);
}
}