diff --git a/midi2osc/Makefile b/midi2osc/Makefile new file mode 100644 index 0000000..f731555 --- /dev/null +++ b/midi2osc/Makefile @@ -0,0 +1,9 @@ +CFLAGS = -Wall -g +LDFLAGS = -lasound -llo + +.PHONY: clean + +midi2osc: midi2osc.c + +clean: + rm -f midi2osc diff --git a/midi2osc/README b/midi2osc/README new file mode 100644 index 0000000..bf73390 --- /dev/null +++ b/midi2osc/README @@ -0,0 +1,12 @@ +midi2osc register itself as a writeable MIDI device. It then forwards +the MIDI messages it receives to the specified OSC destination. + +To use it with the Milkymist One, + +- enable Ethernet on the M1 +- ./midi2osc IP-address-or-host-name +- launch qjackctl +- click on the Connect button in qjackctl +- in the "Connections" window, drag a connection from each MIDI device + you want to connect to midi2osc +- MIDI events will now show up in the MIDI settings dialog, etc. diff --git a/midi2osc/midi2osc.c b/midi2osc/midi2osc.c new file mode 100644 index 0000000..393d278 --- /dev/null +++ b/midi2osc/midi2osc.c @@ -0,0 +1,102 @@ +/* + * midi2osc.c - MIDI to OSC forwarder + * + * Written 2011 by Werner Almesberger + * Copyright 2011 Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include +#include +#include +#include "lo/lo.h" + + +#define NAME "midi2osc" + + +static void forward(snd_seq_t *midi, lo_address osc) +{ + snd_seq_event_t *ev; + uint8_t msg[4] = { 0, }; + + while (snd_seq_event_input(midi, &ev)) { + switch (ev->type) { + case SND_SEQ_EVENT_NOTEON: + msg[1] = 0x90 | ev->data.control.channel; + msg[2] = ev->data.note.note; + msg[3] = ev->data.note.velocity; + break; + case SND_SEQ_EVENT_CONTROLLER: + msg[1] = 0xb0 | ev->data.control.channel; + msg[2] = ev->data.control.param; + msg[3] = ev->data.control.value; + break; + case SND_SEQ_EVENT_PITCHBEND: + msg[1] = 0xe0 | ev->data.control.channel; + msg[2] = ev->data.control.value; + msg[3] = 0; + break; + default: + /* Flickernoise currently doesn't support any others */ + snd_seq_free_event(ev); + continue; + } + if (lo_send(osc, "/midi", "m", msg) < 0) + fprintf(stderr, "%s\n", lo_address_errstr(osc)); + snd_seq_free_event(ev); + } +} + + +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s hostname [port]\n", name); + exit(1); +} + + +int main(int argc, char **argv) +{ + const char *port = "4444"; /* Milkymist One OSC port */ + lo_address osc; + snd_seq_t *midi; + + switch (argc) { + case 2: + break; + case 3: + port = argv[2]; + break; + default: + usage(*argv); + } + + osc = lo_address_new(argv[1], port); + if (!osc) { + fprintf(stderr, "invalid address %s %s\n", argv[1], port); + exit(1); + } + + if (snd_seq_open(&midi, "hw", SND_SEQ_OPEN_INPUT,0) < 0) { + fprintf(stderr, "can't open ALSA sequencer\n"); + exit(1); + } + snd_seq_set_client_name(midi, NAME); + if (snd_seq_create_simple_port(midi, NAME, + SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, + SND_SEQ_PORT_TYPE_APPLICATION) < 0) { + fprintf(stderr, "can't create sequencer port\n"); + exit(1); + } + + forward(midi, osc); + + return 0; +}