Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple ports per MIDI device #886

Merged
merged 9 commits into from Oct 13, 2019
@@ -867,14 +867,18 @@ m.enc[pDEVICES] = function(n,delta)
end

m.redraw[pDEVICES] = function()
y_offset = 0
if(4<m.devices.pos) then
y_offset = 10*(4-m.devices.pos)
end
screen.clear()
if m.devices.mode == "list" then
screen.move(0,10)
screen.move(0,10+y_offset)
screen.level(4)
screen.text(string.upper(m.devices.section))
end
for i=1,m.devices.len do
screen.move(0,10*i+20)
screen.move(0,10*i+20+y_offset)
if(i==m.devices.pos) then
screen.level(15)
else
@@ -884,7 +888,7 @@ m.redraw[pDEVICES] = function()
screen.text(string.upper(m.devices.list[i]) .. " >")
elseif m.devices.mode == "list" then
screen.text(i..".")
screen.move(8,10*i+20)
screen.move(8,10*i+20+y_offset)
if m.devices.section == "midi" then
screen.text(midi.vports[i].name)
elseif m.devices.section == "grid" then
@@ -12,7 +12,13 @@
// start the rx thread for a device
static int dev_start(union dev *d);

union dev *dev_new(device_t type, const char *path, const char *name) {
union dev *dev_new(
device_t type,
const char *path,
const char *name,
bool multiport_device,
unsigned int midi_port_index
) {
union dev *d = calloc(1, sizeof(union dev));

if (d == NULL) {
@@ -38,7 +44,7 @@ union dev *dev_new(device_t type, const char *path, const char *name) {
}
break;
case DEV_TYPE_MIDI:
if (dev_midi_init(d) < 0) {
if (dev_midi_init(d, midi_port_index, multiport_device) < 0) {
goto err_init;
}
break;
@@ -21,7 +21,13 @@ union dev {
// initialize device registry
extern void devices_init(void);
// create a device from a file path
extern union dev *dev_new(device_t type, const char *path, const char *name);
extern union dev *dev_new(
device_t type,
const char *path,
const char *name,
bool multiport_device,
unsigned int midi_port_index
);
// destroy given device
extern void dev_delete(union dev *d);

@@ -1,5 +1,7 @@
#pragma once

#include <stdint.h>

typedef enum {
// libmonome devices
DEV_TYPE_MONOME = 0,
@@ -2,7 +2,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "device_midi.h"
#include "events.h"
#include "device.h"
#include "device_list.h"
@@ -23,15 +25,21 @@ struct dev_q {

struct dev_q dq;

static struct dev_node *dev_lookup_path(const char *path) {
struct dev_node *n = dq.head;
static struct dev_node *dev_lookup_path(
const char *path,
struct dev_node *node_head
) {
const char *npath;
while (n != NULL) {
npath = n->d->base.path;
if (node_head == NULL) {
node_head = dq.head;
}

while (node_head != NULL) {
npath = node_head->d->base.path;
if (strcmp(path, npath) == 0) {
return n;
return node_head;
}
n = n->next;
node_head = node_head->next;
}
return NULL;
}
@@ -42,23 +50,18 @@ void dev_list_init(void) {
dq.tail = NULL;
}

void dev_list_add(device_t type, const char *path, const char *name) {
if (type < 0) {
return;
union event_data *post_add_event(union dev *d, event_t event_type) {
if (d == NULL) {
fprintf(stderr, "dev_list_add: error allocating device data\n");
return NULL;
}

struct dev_node *dn = calloc(1, sizeof(struct dev_node));

if (dn == NULL) {
fprintf(stderr, "dev_list_add: error allocating device queue node\n");
return;
}

union dev *d = dev_new(type, path, name);

if (d == NULL) {
fprintf(stderr, "dev_list_add: error allocating device data\n");
return;
free(d);
return NULL;
}

d->base.id = id++;
@@ -72,35 +75,86 @@ void dev_list_add(device_t type, const char *path, const char *name) {
dq.size++;

union event_data *ev;
ev = event_data_new(event_type);
return ev;
}

void dev_list_add(device_t type, const char *path, const char *name) {
if (type < 0) {
return;
}

union event_data *ev;
union dev *d;
unsigned int midi_port_count = 0;

switch (type) {
case DEV_TYPE_MIDI:
midi_port_count = dev_port_count(path);
for (unsigned int pidx = 0; pidx < midi_port_count; pidx++) {
d = dev_new(type, path, name, midi_port_count > 1, pidx);
ev = post_add_event(d, EVENT_MIDI_ADD);
if (ev != NULL) {
ev->midi_add.dev = d;
event_post(ev);
}
}
return;
case DEV_TYPE_MONOME:
ev = event_data_new(EVENT_MONOME_ADD);
ev->monome_add.dev = d;
d = dev_new(type, path, name, true, 0);
ev = post_add_event(d, EVENT_MONOME_ADD);
break;
case DEV_TYPE_HID:
ev = event_data_new(EVENT_HID_ADD);
ev->hid_add.dev = d;
break;
case DEV_TYPE_MIDI:
ev = event_data_new(EVENT_MIDI_ADD);
ev->midi_add.dev = d;
d = dev_new(type, path, name, true, 0);
ev = post_add_event(d, EVENT_HID_ADD);
break;
case DEV_TYPE_CROW:
ev = event_data_new(EVENT_CROW_ADD);
ev->crow_add.dev = d;
d = dev_new(type, path, name, true, 0);
ev = post_add_event(d, EVENT_CROW_ADD);
break;
default:
fprintf(stderr, "dev_list_add(): error posting event (unknown type)\n");
return;
}
event_post(ev);
if (ev != NULL) {
ev->monome_add.dev = d;

This comment has been minimized.

@tehn

tehn Oct 18, 2019
Member

seems this is using the monome_add structure for HID and CROW

This comment has been minimized.

@okyeron

okyeron Oct 19, 2019
Contributor

not sure it's relevant, but want to mention this comment from when HID was getting fixed up:
#662 (comment)
Although... I can't remember specifics of the debug I did at that point.

event_post(ev);
}
}

struct dev_node *dev_remove_node(
struct dev_node *dn,
union event_data *event_remove,
const char *node
) {
struct dev_node *next_node;
event_post(event_remove);

if(dq.head == dn) { dq.head = dn->next; }
if(dq.tail == dn) { dq.tail = dn->prev; }
remque(dn);
dq.size--;

This comment has been minimized.

@tehn

tehn Oct 18, 2019
Member

fairly sure the problem is something with these three lines 138-140...

dev_delete(dn->d);
next_node = dev_lookup_path(node, dn);
free(dn);

return next_node;
}

void dev_list_remove(device_t type, const char *node) {
struct dev_node *dn = dev_lookup_path(node);
struct dev_node *dn = dev_lookup_path(node, NULL);
if(dn == NULL) { return; }
union event_data *ev;

switch(type) {
case DEV_TYPE_MIDI:
while (dn != NULL) {
ev = event_data_new(EVENT_MIDI_REMOVE);
ev->midi_remove.id = dn->d->base.id;
dn = dev_remove_node(dn, ev, node);
}
return;
case DEV_TYPE_MONOME:
ev = event_data_new(EVENT_MONOME_REMOVE);
ev->monome_remove.id = dn->d->base.id;
@@ -109,10 +163,6 @@ void dev_list_remove(device_t type, const char *node) {
ev = event_data_new(EVENT_HID_REMOVE);
ev->hid_remove.id = dn->d->base.id;
break;
case DEV_TYPE_MIDI:
ev = event_data_new(EVENT_MIDI_REMOVE);
ev->midi_remove.id = dn->d->base.id;
break;
case DEV_TYPE_CROW:
ev = event_data_new(EVENT_CROW_REMOVE);
ev->crow_remove.id = dn->d->base.id;
@@ -121,13 +171,5 @@ void dev_list_remove(device_t type, const char *node) {
fprintf(stderr, "dev_list_remove(): error posting event (unknown type)\n");
return;
}
event_post(ev);

if(dq.head == dn) { dq.head = dn->next; }
if(dq.tail == dn) { dq.tail = dn->prev; }
remque(dn);
dq.size--;

dev_delete(dn->d);
free(dn);
}
dev_remove_node(dn, ev, node);
}
@@ -8,7 +8,49 @@
#include "device_midi.h"
#include "../clocks/clock_midi.h"

int dev_midi_init(void *self) {
unsigned int dev_port_count(const char *path) {
int card;
int alsa_dev;

if (sscanf(path, "/dev/snd/midiC%dD%d", &card, &alsa_dev) < 0) {
// TODO: Insert error message here
return 0;
}

// mostly from amidi.c
snd_ctl_t *ctl;
char name[32];

snd_rawmidi_info_t *info;
int subs = 0;
int subs_in = 0;
int subs_out = 0;

sprintf(name, "hw:%d", card);
if (snd_ctl_open(&ctl, name, 0) < 0) {
// TODO: Insert error message here
return 0;
}

snd_rawmidi_info_alloca(&info);
snd_rawmidi_info_set_device(info, alsa_dev);

snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
if (snd_ctl_rawmidi_info(ctl, info) >= 0) {
subs_in = snd_rawmidi_info_get_subdevices_count(info);
}

snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
if (snd_ctl_rawmidi_info(ctl, info) >= 0) {
subs_out = snd_rawmidi_info_get_subdevices_count(info);
}
snd_ctl_close(ctl);

subs = subs_in > subs_out ? subs_in : subs_out;
return subs;
}

int dev_midi_init(void *self, unsigned int port_index, bool multiport_device) {
struct dev_midi *midi = (struct dev_midi *) self;
struct dev_common *base = (struct dev_common *) self;

@@ -18,7 +60,7 @@ int dev_midi_init(void *self) {

sscanf(base->path, "/dev/snd/midiC%uD%u", &alsa_card, &alsa_dev);

if (asprintf(&alsa_name, "hw:%u,%u", alsa_card, alsa_dev) < 0) {
if (asprintf(&alsa_name, "hw:%u,%u,%u", alsa_card, alsa_dev, port_index) < 0) {
fprintf(stderr, "failed to create alsa device name for card %d,%d\n", alsa_card, alsa_dev);
return -1;
}
@@ -28,6 +70,21 @@ int dev_midi_init(void *self) {
return -1;
}

char *name_with_port_index;
if (multiport_device) {
if (asprintf(&name_with_port_index, "%s %u", base->name, port_index + 1) < 0) {
fprintf(
stderr,
"failed to create human-readable device name for card %d,%d,%d\n",
alsa_card,
alsa_dev,
port_index
);
return -1;
}
base->name = name_with_port_index;
}

base->start = &dev_midi_start;
base->deinit = &dev_midi_deinit;

@@ -40,7 +97,7 @@ void dev_midi_deinit(void *self) {
snd_rawmidi_close(midi->handle_out);
}

void* dev_midi_start(void *self) {
void *dev_midi_start(void *self) {
struct dev_midi *midi = (struct dev_midi *) self;
union event_data *ev;

@@ -10,7 +10,8 @@ struct dev_midi {
snd_rawmidi_t *handle_out;
};

extern int dev_midi_init(void *self);
extern unsigned int dev_port_count(const char *path);
extern int dev_midi_init(void *self, unsigned int port_index, bool multiport_device);
extern void dev_midi_deinit(void *self);
extern void* dev_midi_start(void *self);
extern ssize_t dev_midi_send(void *self, uint8_t *data, size_t n);
ProTip! Use n and p to navigate between commits in a pull request.