Skip to content

Commit

Permalink
Midi: add more information on port, retrievabble
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliomoro committed Feb 8, 2024
1 parent cdda35b commit c954b74
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 25 deletions.
115 changes: 92 additions & 23 deletions libraries/Midi/Midi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,47 @@ void Midi::doWriteOutput(const void* data, int size) {

#include <RtWrappers.h>

static Midi::Port getPort(snd_rawmidi_info_t* info)
{
#if 0
printf("==========\n");
printf("device: %d\n", snd_rawmidi_info_get_device(info));
printf("subdevice: %d\n", snd_rawmidi_info_get_subdevice(info));
printf("stream: %d\n", snd_rawmidi_info_get_stream(info));
printf("card: %d\n", snd_rawmidi_info_get_card(info));
printf("flags: %d\n", snd_rawmidi_info_get_flags(info));
printf("id: %s\n", snd_rawmidi_info_get_id(info));
printf("name: %s\n", snd_rawmidi_info_get_name(info));
printf("subdevice_name: %s\n", snd_rawmidi_info_get_subdevice_name(info));
printf("subdevices_count: %d\n", snd_rawmidi_info_get_subdevices_count(info));
printf("subdevices_avail: %d\n", snd_rawmidi_info_get_subdevices_avail(info));
#endif
int card = snd_rawmidi_info_get_card(info);
int sub = snd_rawmidi_info_get_subdevice(info);
int device = snd_rawmidi_info_get_device(info);
std::string name = "hw:" + std::to_string(card) + "," + std::to_string(device) + "," + std::to_string(sub);
std::string desc = std::string(snd_rawmidi_info_get_id(info)) + " " + snd_rawmidi_info_get_name(info) + " [ " + snd_rawmidi_info_get_subdevice_name(info) + " ]";
return {
.name = name,
.desc = desc,
.card = card,
.device = device,
.sub = (int)sub,
.hasInput = false, // TODO: fill these in, see is_input()/is_output()
.hasOutput = false,
};
}

static int getPort(snd_rawmidi_t* rmidi, Midi::Port& port) {
snd_rawmidi_info_t *info;
snd_rawmidi_info_alloca(&info);
int ret = snd_rawmidi_info(rmidi, info);
if(ret)
return ret;
port = getPort(info);
return 0;
}

int Midi::readFrom(const char* port){
if(port == NULL){
port = defaultPort.c_str();
Expand All @@ -274,7 +315,13 @@ int Midi::readFrom(const char* port){
if (err) {
return err;
}
int ret = create_and_start_thread(&midiInputThread, inId.c_str(), 50, 0, NULL, Midi::readInputLoopStatic, (void*)this);
int ret = getPort(alsaIn, inPortFull);
inPortFull.hasInput = true;
if(ret) {
fprintf(stderr, "Unable to retrieve input port information for %s\n", port);
return 0;
}
ret = create_and_start_thread(&midiInputThread, inId.c_str(), 50, 0, NULL, Midi::readInputLoopStatic, (void*)this);
if(ret)
return 0;
inputEnabled = true;
Expand All @@ -292,6 +339,12 @@ int Midi::writeTo(const char* port){
if (err) {
return err;
}
int ret = getPort(alsaOut, outPortFull);
inPortFull.hasOutput = true;
if(ret) {
fprintf(stderr, "Unable to retrieve output port information for %s\n", port);
return 0;
}
midiOutputTask = new AuxTaskNonRT();
midiOutputTask->create(outId, [this](void* buf, int size) {
this->doWriteOutput(buf, size);
Expand All @@ -300,7 +353,8 @@ int Midi::writeTo(const char* port){
return 1;
}

void Midi::createAllPorts(std::vector<Midi*>& ports, bool useParser){
std::vector<Midi::Port> Midi::listAllPorts(){
std::vector<Port> ports;
int card = -1;
int status;
while((status = snd_card_next(&card)) == 0){
Expand All @@ -314,7 +368,7 @@ void Midi::createAllPorts(std::vector<Midi*>& ports, bool useParser){
sprintf(name, "hw:%d", card);
if ((status = snd_ctl_open(&ctl, name, 0)) < 0) {
error("cannot open control for card %d: %s\n", card, snd_strerror(status));
return;
return ports;
}
do {
status = snd_ctl_rawmidi_next_device(ctl, &device);
Expand Down Expand Up @@ -342,7 +396,7 @@ void Midi::createAllPorts(std::vector<Midi*>& ports, bool useParser){
if ((status = is_output(ctl, card, device, sub)) < 0) {
error("cannot get rawmidi information %d:%d: %s",
card, device, snd_strerror(status));
return;
return ports;
} else if (status){
out = true;
// writeTo
Expand All @@ -352,35 +406,51 @@ void Midi::createAllPorts(std::vector<Midi*>& ports, bool useParser){
if ((status = is_input(ctl, card, device, sub)) < 0) {
error("cannot get rawmidi information %d:%d: %s",
card, device, snd_strerror(status));
return;
return ports;
}
} else if (status) {
in = true;
// readfrom
}

if(in || out){
ports.resize(ports.size() + 1);
unsigned int index = ports.size() - 1;
ports[index] = new Midi();
const char* myName = snd_rawmidi_info_get_name(info);
const char* mySubName = snd_rawmidi_info_get_subdevice_name(info);
sprintf(name, "hw:%d,%d,%d", card, device, sub);
if(in){
printf("Port %d, Reading from: %s, %s %s\n", index, name, myName, mySubName);
ports[index]->readFrom(name);
ports[index]->enableParser(useParser);
}
if(out){
printf("Port %d, Writing to: %s %s %s\n", index, name, myName, mySubName);
ports[index]->writeTo(name);
}
Port port = getPort(info);
port.hasInput = in;
port.hasOutput = out;
ports.push_back(port);
}
}
}
} while (device >= 0);
snd_ctl_close(ctl);
}
return ports;
}

void Midi::createAllPorts(std::vector<Midi*>& ports, bool useParser){
auto list = listAllPorts();
ports.reserve(list.size());
for(size_t n = 0; n < list.size(); ++n) {
auto& l = list[n];
if(!(l.hasInput || l.hasOutput))
continue;
Midi* m = new Midi();
if(l.hasInput) {
std::string str = "reading from " + l.name + ": " + l.desc;
if(1 == m->readFrom(l.name.c_str()))
printf("Port %d, %s\n", n, str.c_str());
else
fprintf(stderr, "Port %d, ERROR %s\n", n, str.c_str());
}
if(l.hasOutput) {
std::string str = "writing to " + l.name + ": " + l.desc;
if(1 == m->writeTo(l.name.c_str()))
printf("Port %d, %s\n", n, str.c_str());
else
fprintf(stderr, "Port %d, ERROR %s\n", n, str.c_str());
}
ports.push_back(m);
}
}

int Midi::_getInput(){
Expand Down Expand Up @@ -437,12 +507,12 @@ int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
return 1;
}

bool Midi::isInputEnabled()
bool Midi::isInputEnabled() const
{
return inputEnabled;
}

bool Midi::isOutputEnabled()
bool Midi::isOutputEnabled() const
{
return outputEnabled;
}
Expand Down Expand Up @@ -761,7 +831,6 @@ static int is_input(snd_ctl_t *ctl, int card, int device, int sub) {
}



//////////////////////////////
//
// is_output -- returns true if specified card/device/sub can output MIDI data.
Expand Down
28 changes: 26 additions & 2 deletions libraries/Midi/Midi.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <vector>
#include <string>
#include <AuxTaskNonRT.h>
#include <tuple>

typedef unsigned char midi_byte_t;

Expand Down Expand Up @@ -370,10 +371,31 @@ class Midi {
MidiParser* getMidiParser();
virtual ~Midi();

bool isInputEnabled();
bool isInputEnabled() const;

bool isOutputEnabled();
bool isOutputEnabled() const;

struct Port {
std::string name;
std::string desc;
int card;
int device;
int sub;
bool hasInput;
bool hasOutput;
bool operator== (const Port& o) const {
return name == o.name &&
desc == o.desc &&
card == o.card &&
device == o.device &&
sub == o.sub &&
hasInput == o.hasInput &&
hasOutput == o.hasOutput;
}
};
const Port& getInputPort() const { return inPortFull; }
const Port& getOutputPort() const { return outPortFull; }
static std::vector<Port> listAllPorts();
/**
* Opens all the existing MIDI ports, in the same order returned by the filesystem or Alsa.
* Ports open with this method should be closed with destroyPorts()
Expand All @@ -387,6 +409,8 @@ class Midi {
private:
std::string inPort;
std::string outPort;
Port inPortFull;
Port outPortFull;
int _getInput();
int attemptRecoveryRead();
static void* readInputLoopStatic(void* obj);
Expand Down

0 comments on commit c954b74

Please sign in to comment.