From 66c59fd7ec79338a47c68077674350ee2c74f326 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 21 Jun 2017 21:15:04 +0200 Subject: Implement loopback backend --- README.md | 27 ++++++++++++++ loopback.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ loopback.h | 16 ++++++++ monster.cfg | 37 ++++++------------- 4 files changed, 175 insertions(+), 25 deletions(-) create mode 100644 loopback.c create mode 100644 loopback.h diff --git a/README.md b/README.md index 7c62452..8a79d1f 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,33 @@ NRPNs are not yet fully implemented, though rudimentary support is in the codeba The channel specification syntax is currently a bit clunky. +### The `loopback` backend + +This backend allows the user to create logical mapping channels, for example to exchange triggering +channels easier later. All events that are input are immediately output again on the same channel. + +#### Global configuration + +All global configuration is ignored. + +#### Instance configuration + +All instance configuration is ignored + +#### Channel specification + +A channel may have any string for a name. + +Example mapping: +``` +loop.foo = loop.bar123 +``` + +#### Known bugs / problems + +It is possible to configure loops using this backend. Triggering a loop +will create a deadlock, preventing any other backends from generating events. + ### The `osc` backend TBD diff --git a/loopback.c b/loopback.c new file mode 100644 index 0000000..56e8759 --- /dev/null +++ b/loopback.c @@ -0,0 +1,120 @@ +#include +#include "loopback.h" + +#define BACKEND_NAME "loopback" + +int init(){ + backend loopback = { + .name = BACKEND_NAME, + .conf = backend_configure, + .create = backend_instance, + .conf_instance = backend_configure_instance, + .channel = backend_channel, + .handle = backend_set, + .process = backend_handle, + .start = backend_start, + .shutdown = backend_shutdown + }; + + //register backend + if(mm_backend_register(loopback)){ + fprintf(stderr, "Failed to register loopback backend\n"); + return 1; + } + return 0; +} + +static int backend_configure(char* option, char* value){ + //intentionally ignored + return 0; +} + +static int backend_configure_instance(instance* instance, char* option, char* value){ + //intentionally ignored + return 0; +} + +static instance* backend_instance(){ + instance* i = mm_instance(); + if(!i){ + return NULL; + } + + i->impl = calloc(1, sizeof(loopback_instance)); + if(!i->impl){ + fprintf(stderr, "Failed to allocate memory\n"); + return NULL; + } + + return i; +} + +static channel* backend_channel(instance* inst, char* spec){ + size_t u; + loopback_instance* data = (loopback_instance*) inst->impl; + + //find matching channel + for(u = 0; u < data->n; u++){ + if(!strcmp(spec, data->name[u])){ + break; + } + } + + //allocate new channel + if(u == data->n){ + data->name = realloc(data->name, (u + 1) * sizeof(char*)); + if(!data->name){ + fprintf(stderr, "Failed to allocate memory\n"); + return NULL; + } + + data->name[u] = strdup(spec); + if(!data->name[u]){ + fprintf(stderr, "Failed to allocate memory\n"); + return NULL; + } + data->n++; + } + + return mm_channel(inst, u, 1); +} + +static int backend_set(instance* inst, size_t num, channel** c, channel_value* v){ + size_t n; + for(n = 0; n < num; n++){ + mm_channel_event(c[n], v[n]); + } + return 0; +} + +static int backend_handle(size_t num, managed_fd* fds){ + //no events generated here + return 0; +} + +static int backend_start(){ + return 0; +} + +static int backend_shutdown(){ + size_t n, u, p; + instance** inst = NULL; + loopback_instance* data = NULL; + + if(mm_backend_instances(BACKEND_NAME, &n, &inst)){ + fprintf(stderr, "Failed to fetch instance list\n"); + return 1; + } + + for(u = 0; u < n; u++){ + data = (loopback_instance*) inst[u]->impl; + for(p = 0; p < data->n; p++){ + free(data->name[p]); + } + free(data->name); + free(inst[u]->impl); + } + + free(inst); + return 0; +} diff --git a/loopback.h b/loopback.h new file mode 100644 index 0000000..fe44e91 --- /dev/null +++ b/loopback.h @@ -0,0 +1,16 @@ +#include "midimonster.h" + +int init(); +static int backend_configure(char* option, char* value); +static int backend_configure_instance(instance* instance, char* option, char* value); +static instance* backend_instance(); +static channel* backend_channel(instance* instance, char* spec); +static int backend_set(instance* inst, size_t num, channel** c, channel_value* v); +static int backend_handle(size_t num, managed_fd* fds); +static int backend_start(); +static int backend_shutdown(); + +typedef struct /*_loopback_instance_data*/ { + size_t n; + char** name; +} loopback_instance; diff --git a/monster.cfg b/monster.cfg index 194b115..f1caf87 100644 --- a/monster.cfg +++ b/monster.cfg @@ -5,31 +5,18 @@ name = MIDIMonster bind = * 6454 net = 0 -;[backend osc] +[midi pad] +read = Launchpad +write = Launchpad -[midi bcf] -read = BCF -write = BCF - -[midi lc1] -read = Launch Control -write = Launch Control - -[midi xlate] - -[artnet net1] -net = 0 -uni = 1 -output = true +[loopback loop] [map] -bcf.cc0.81 = lc1.cc0.1 -bcf.cc0.82 = lc1.note0.1 -bcf.cc0.83 = lc1.cc0.9 -net1.15 = lc1.cc0.1 -bcf.cc0.1 = net1.1 -bcf.cc0.2 = net1.3 -;net1.257 = bcf.cc0.81 -;net1.231 = foo.1 -;net1.255 = lc1.cc0.1 -;net1.231 = osc.f/channel5/ toggle=127 +loop.test = pad.note0.0 + +pad.note0.1 = loop.test +pad.note0.2 = loop.test +pad.note0.3 = loop.test +pad.note0.4 = loop.test +pad.note0.5 = loop.test +pad.note0.6 = loop.test -- cgit v1.2.3