From ebb683ae0f538e7842403d4ce28f4d8188f64373 Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 6 Jun 2017 02:22:37 +0200 Subject: Working MIDI translation --- TODO | 1 + artnet.c | 2 +- artnet.h | 2 +- backend.c | 31 ++++++++++++++++++++++++++--- backend.h | 2 +- midi.c | 64 +++++++++++++++++++++++++++++++++++++++-------------------- midi.h | 2 +- midimonster.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- midimonster.h | 2 +- monster.cfg | 10 +++++++--- 10 files changed, 141 insertions(+), 35 deletions(-) diff --git a/TODO b/TODO index c83eb34..e654306 100644 --- a/TODO +++ b/TODO @@ -1 +1,2 @@ Wide channels (DMX/MIDI) +Note source in channel value struct diff --git a/artnet.c b/artnet.c index f2a2fa5..2147dd9 100644 --- a/artnet.c +++ b/artnet.c @@ -107,7 +107,7 @@ static channel* artnet_channel(instance* instance, char* spec){ return mm_channel(instance, channel, 1); } -static int artnet_set(instance* inst, size_t num, channel* c, channel_value* v){ +static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v){ //TODO return 1; } diff --git a/artnet.h b/artnet.h index 00a75a7..806d125 100644 --- a/artnet.h +++ b/artnet.h @@ -5,7 +5,7 @@ static int artnet_configure(char* option, char* value); static int artnet_configure_instance(instance* instance, char* option, char* value); static instance* artnet_instance(); static channel* artnet_channel(instance* instance, char* spec); -static int artnet_set(instance* inst, size_t num, channel* c, channel_value* v); +static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v); static int artnet_handle(size_t num, managed_fd* fds); static int artnet_start(); static int artnet_shutdown(); diff --git a/backend.c b/backend.c index 1b297d4..eeb789d 100644 --- a/backend.c +++ b/backend.c @@ -31,9 +31,34 @@ int backends_handle(size_t nfds, managed_fd* fds){ return rv; } -int backends_notify(size_t nev, channel* c, channel_value* v){ - //TODO - return 1; +int backends_notify(size_t nev, channel** c, channel_value* v){ + size_t u, p, n; + int rv = 0; + channel_value xval; + channel* xchnl; + + //TODO eliminate duplicates + for(u = 0; u < ninstances && !rv; u++){ + n = 0; + + for(p = 0; p < nev; p++){ + if(c[p]->instance == instances[u]){ + xval = v[n]; + xchnl = c[n]; + + v[n] = v[p]; + c[n] = c[p]; + + v[p] = xval; + c[p] = xchnl; + n++; + } + } + + rv |= instances[u]->backend->handle(instances[u], n, c, v); + } + + return 0; } channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ diff --git a/backend.h b/backend.h index e2eaac5..daf96bc 100644 --- a/backend.h +++ b/backend.h @@ -1,7 +1,7 @@ #include int backends_handle(size_t nfds, managed_fd* fds); -int backends_notify(size_t nev, channel* c, channel_value* v); +int backends_notify(size_t nev, channel** c, channel_value* v); backend* backend_match(char* name); instance* instance_match(char* name); diff --git a/midi.c b/midi.c index 857460f..da71a32 100644 --- a/midi.c +++ b/midi.c @@ -4,10 +4,20 @@ #define BACKEND_NAME "midi" static snd_seq_t* sequencer = NULL; +typedef union { + struct { + uint8_t pad[5]; + uint8_t type; + uint8_t channel; + uint8_t control; + } fields; + uint64_t label; +} midi_channel_ident; /* * TODO * Optionally send note-off messages + * Optionally send updates as after-touch */ enum /*_midi_channel_type*/ { @@ -104,15 +114,7 @@ static int midi_configure_instance(instance* instance, char* option, char* value } static channel* midi_channel(instance* instance, char* spec){ - union { - struct { - uint8_t pad[5]; - uint8_t type; - uint8_t channel; - uint8_t control; - } fields; - uint64_t label; - } ident = { + midi_channel_ident ident = { .label = 0 }; @@ -158,15 +160,39 @@ static channel* midi_channel(instance* instance, char* spec){ return NULL; } -static int midi_set(instance* inst, size_t num, channel* c, channel_value* v){ +static int midi_set(instance* inst, size_t num, channel** c, channel_value* v){ size_t u; + snd_seq_event_t ev; midi_instance_data* data; + midi_channel_ident ident = { + .label = 0 + }; for(u = 0; u < num; u++){ - data = (midi_instance_data*) c[u].instance->impl; - //TODO write out event + data = (midi_instance_data*) c[u]->instance->impl; + ident.label = c[u]->ident; + + snd_seq_ev_clear(&ev); + snd_seq_ev_set_source(&ev, data->port); + snd_seq_ev_set_subs(&ev); + snd_seq_ev_set_direct(&ev); + + switch(ident.fields.type){ + case note: + snd_seq_ev_set_noteon(&ev, ident.fields.channel, ident.fields.control, v[u].normalised * 127.0); + break; + case cc: + snd_seq_ev_set_controller(&ev, ident.fields.channel, ident.fields.control, v[u].normalised * 127.0); + break; + case nrpn: + //FIXME set to nrpn output + break; + } + + snd_seq_event_output(sequencer, &ev); } + snd_seq_drain_output(sequencer); return 0; } @@ -175,18 +201,14 @@ static int midi_handle(size_t num, managed_fd* fds){ instance* inst = NULL; channel* changed = NULL; channel_value val; - union { - struct { - uint8_t pad[5]; - uint8_t type; - uint8_t channel; - uint8_t control; - } fields; - uint64_t label; - } ident = { + midi_channel_ident ident = { .label = 0 }; + if(!num){ + return 0; + } + while(snd_seq_event_input(sequencer, &ev) > 0){ ident.label = 0; switch(ev->type){ diff --git a/midi.h b/midi.h index dc997bc..185176b 100644 --- a/midi.h +++ b/midi.h @@ -5,7 +5,7 @@ static int midi_configure(char* option, char* value); static int midi_configure_instance(instance* instance, char* option, char* value); static instance* midi_instance(); static channel* midi_channel(instance* instance, char* spec); -static int midi_set(instance* inst, size_t num, channel* c, channel_value* v); +static int midi_set(instance* inst, size_t num, channel** c, channel_value* v); static int midi_handle(size_t num, managed_fd* fds); static int midi_start(); static int midi_shutdown(); diff --git a/midimonster.c b/midimonster.c index 33858fd..b1c14e2 100644 --- a/midimonster.c +++ b/midimonster.c @@ -16,6 +16,10 @@ static size_t mappings = 0; static channel_mapping* map = NULL; static size_t fds = 0; static managed_fd* fd = NULL; +static size_t ev_alloc = 0; +static size_t evs = 0; +static channel** ev_channel = NULL; +static channel_value* ev_value = NULL; volatile static sig_atomic_t shutdown_requested = 0; void signal_handler(int signum){ @@ -40,6 +44,7 @@ int mm_map_channel(channel* from, channel* to){ } memset(map + mappings, 0, sizeof(channel_mapping)); mappings++; + map[u].from = from; } //check whether the target is already mapped @@ -134,11 +139,52 @@ void fds_free(){ } int mm_channel_event(channel* c, channel_value v){ - //TODO - fprintf(stderr, "Stub implementation: Channel on %s at value %f\n", c->instance->name, v.normalised); + size_t u, p; + + //find mapped channels + for(u = 0; u < mappings; u++){ + if(map[u].from == c){ + break; + } + } + + if(u == mappings){ + //target-only channel + return 0; + } + + //resize event structures to fit additional events + if(evs + map[u].destinations >= ev_alloc){ + ev_channel = realloc(ev_channel, (ev_alloc + map[u].destinations) * sizeof(channel*)); + ev_value = realloc(ev_value, (ev_alloc + map[u].destinations) * sizeof(channel_value)); + + if(!ev_channel || !ev_value){ + fprintf(stderr, "Failed to allocate memory\n"); + ev_alloc = 0; + evs = 0; + return 1; + } + + ev_alloc += map[u].destinations; + } + + //enqueue channel events + //FIXME this might lead to one channel being mentioned multiple times in an apply call + for(p = 0; p < map[u].destinations; p++){ + ev_channel[evs + p] = map[u].to[p]; + ev_value[evs + p] = v; + } + + evs += map[u].destinations; return 0; } +void event_free(){ + free(ev_channel); + free(ev_value); + ev_alloc = 0; +} + int usage(char* fn){ fprintf(stderr, "MIDIMonster v0.1\n"); fprintf(stderr, "Usage:\n"); @@ -225,7 +271,14 @@ int main(int argc, char** argv){ goto bail; } - //TODO push collected events to target backends + //push collected events to target backends + if(evs && backends_notify(evs, ev_channel, ev_value)){ + fprintf(stderr, "Backends failed to handle output\n"); + goto bail; + } + + //reset the event count + evs = 0; } rv = EXIT_SUCCESS; @@ -237,6 +290,7 @@ bail: instances_free(); map_free(); fds_free(); + event_free(); return rv; } diff --git a/midimonster.h b/midimonster.h index bd42d8f..27dcae4 100644 --- a/midimonster.h +++ b/midimonster.h @@ -12,7 +12,7 @@ struct _backend_channel; struct _backend_instance; struct _managed_fd; -typedef int (*mmbackend_handle_event)(struct _backend_instance* inst, size_t channels, struct _backend_channel* c, struct _channel_value* v); +typedef int (*mmbackend_handle_event)(struct _backend_instance* inst, size_t channels, struct _backend_channel** c, struct _channel_value* v); typedef struct _backend_instance* (*mmbackend_create_instance)(); typedef struct _backend_channel* (*mmbackend_parse_channel)(struct _backend_instance* instance, char* spec); typedef void (*mmbackend_free_channel)(struct _backend_channel* c); diff --git a/monster.cfg b/monster.cfg index 3ff2e3f..1da33c6 100644 --- a/monster.cfg +++ b/monster.cfg @@ -9,9 +9,11 @@ net = 0 [midi bcf] read = BCF +write = BCF [midi lc1] read = Launch Control +write = Launch Control [midi xlate] @@ -24,9 +26,11 @@ output = true net = 0 [map] -net1.255 = lc1.cc0.1 -net1.256 = lc1.note0.9 -net1.257 = bcf.cc0.81 +bcf.cc0.81 = lc1.cc0.1 +lc1.cc0.1 = bcf.cc0.81 +bcf.cc0.82 = lc1.note0.9 +;net1.256 = lc1.note0.9 +;net1.257 = bcf.cc0.81 ;net1.231 = foo.1 ;net1.255 = lc1.cc0.1 ;net1.231 = osc.f/channel5/ toggle=127 -- cgit v1.2.3