aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2017-06-21 21:15:04 +0200
committercbdev <cb@cbcdn.com>2017-06-21 21:15:04 +0200
commit66c59fd7ec79338a47c68077674350ee2c74f326 (patch)
tree8f911aba1d7f8ed041c5ce22cb755396b3c5e6b3
parent45c2a69122b9141f84d3f8064f41d5f6160d9ca2 (diff)
downloadmidimonster-66c59fd7ec79338a47c68077674350ee2c74f326.tar.gz
midimonster-66c59fd7ec79338a47c68077674350ee2c74f326.tar.bz2
midimonster-66c59fd7ec79338a47c68077674350ee2c74f326.zip
Implement loopback backend
-rw-r--r--README.md27
-rw-r--r--loopback.c120
-rw-r--r--loopback.h16
-rw-r--r--monster.cfg37
4 files changed, 175 insertions, 25 deletions
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 <string.h>
+#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