aboutsummaryrefslogtreecommitdiff
path: root/midi_matrix_channel_filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'midi_matrix_channel_filter.c')
-rw-r--r--midi_matrix_channel_filter.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/midi_matrix_channel_filter.c b/midi_matrix_channel_filter.c
new file mode 100644
index 0000000..b5141fc
--- /dev/null
+++ b/midi_matrix_channel_filter.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <midi_matrix.h>
+
+typedef struct _Handle Handle;
+
+struct _Handle {
+ LV2_URID_Map *map;
+ struct {
+ LV2_URID midi_MidiEvent;
+ } uris;
+
+ const LV2_Atom_Sequence *midi_in;
+ LV2_Atom_Sequence *midi_out;
+ float *control [0x10];
+ uint16_t mask [0x10];
+
+ LV2_Atom_Forge forge;
+ LV2_Atom_Forge_Frame frame;
+};
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor, double rate, const char *bundle_path, const LV2_Feature *const *features)
+{
+ int i;
+ Handle *handle = (Handle *)calloc(1, sizeof(Handle));
+ if(!handle)
+ return NULL;
+
+ for(i=0; features[i]; i++)
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->map = (LV2_URID_Map *)features[i]->data;
+
+ if(!handle->map)
+ {
+ fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+
+ handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
+ lv2_atom_forge_init(&handle->forge, handle->map);
+
+ return handle;
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void *data)
+{
+ Handle *handle = (Handle *)instance;
+ switch(port)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ handle->control[port] = (float *)data;
+ break;
+ case 0x10:
+ handle->midi_in = (const LV2_Atom_Sequence *)data;
+ break;
+ case 0x11:
+ handle->midi_out = (LV2_Atom_Sequence *)data;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+activate(LV2_Handle instance)
+{
+ Handle *handle = (Handle *)instance;
+ //nothing
+}
+
+static void
+run(LV2_Handle instance, uint32_t sample_count)
+{
+ Handle *handle = (Handle *)instance;
+
+ if(!handle->midi_in || !handle->midi_out)
+ return;
+
+ // fill channel mask array
+ int i;
+ for(i=0x0; i<0x10; i++)
+ handle->mask[i] = (uint16_t)*handle->control[i];
+
+ // prepare midi atom forge
+ const uint32_t capacity = handle->midi_out->atom.size;
+ LV2_Atom_Forge *forge = &handle->forge;
+ lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->midi_out, capacity);
+ lv2_atom_forge_sequence_head(forge, &handle->frame, 0);
+
+ // process incoming events
+ LV2_ATOM_SEQUENCE_FOREACH(handle->midi_in, ev)
+ {
+ if(ev->body.type == handle->uris.midi_MidiEvent)
+ {
+ int64_t frames = ev->time.frames;
+ const uint32_t len = ev->body.size;
+ const uint8_t *buf = LV2_ATOM_BODY_CONST(&ev->body);
+
+ const uint8_t cmd = buf[0] & 0xf0;
+ if(cmd == 0xf0)
+ continue; // ignore system messages
+
+ const uint8_t src = buf[0] & 0x0f; // source channel
+ if(handle->mask[src]) // are there any active output channels at all for this input channel?
+ {
+ uint8_t dst;
+ uint16_t mask;
+ for(dst=0x0, mask=0x1; dst<0x10; dst++, mask=mask<<1)
+ {
+ if(handle->mask[src] & mask) // is this output channel active?
+ {
+ LV2_Atom midiatom;
+ midiatom.type = handle->uris.midi_MidiEvent;
+ midiatom.size = len;
+ const uint8_t m = (buf[0] & 0xf0) | dst; // rewrite channel number
+
+ lv2_atom_forge_frame_time(forge, frames);
+ lv2_atom_forge_raw(forge, &midiatom, sizeof(LV2_Atom));
+ lv2_atom_forge_raw(forge, &m, 1);
+ lv2_atom_forge_raw(forge, &buf[1], len-1);
+ lv2_atom_forge_pad(forge, sizeof(LV2_Atom) + len);
+ }
+ }
+ }
+ }
+ }
+
+ lv2_atom_forge_pop(forge, &handle->frame);
+}
+
+static void
+deactivate(LV2_Handle instance)
+{
+ Handle *handle = (Handle *)instance;
+ //nothing
+}
+
+static void
+cleanup(LV2_Handle instance)
+{
+ Handle *handle = (Handle *)instance;
+
+ free(handle);
+}
+
+static const void*
+extension_data(const char* uri)
+{
+ //nothing
+ return NULL;
+}
+
+const LV2_Descriptor channel_filter = {
+ .URI = MIDI_MATRIX_CHANNEL_FILTER_URI,
+ .instantiate = instantiate,
+ .connect_port = connect_port,
+ .activate = activate,
+ .run = run,
+ .deactivate = deactivate,
+ .cleanup = cleanup,
+ .extension_data = extension_data
+};