From 15449c78ab76f658874c346aab808c1af4d4624f Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Wed, 26 Aug 2020 08:44:09 +0200 Subject: [PATCH] Initial commit. --- OSC2Midi.cpp | 42 ++++++++++++++++ OSC2Midi.h | 9 ++++ OSC2MidiGateway.ino | 116 ++++++++++++++++++++++++++++++++++++++++++++ debug.h | 26 ++++++++++ 4 files changed, 193 insertions(+) create mode 100644 OSC2Midi.cpp create mode 100644 OSC2Midi.h create mode 100644 OSC2MidiGateway.ino create mode 100644 debug.h diff --git a/OSC2Midi.cpp b/OSC2Midi.cpp new file mode 100644 index 0000000..9263630 --- /dev/null +++ b/OSC2Midi.cpp @@ -0,0 +1,42 @@ +#include "OSC2Midi.h" +#include +#include + +/* + * TODO: this will return rather unpredictable numbers when + * given strings with numbers > 255. + */ +uint8_t getCC(const char *str, int index) +{ + const char *offset = str; + + // skip the first / + if (strncmp(str, "/", strlen("/")) == 0) + { + offset++; + } + + if (index == -1) + { + return atoi(offset); + } + + while (index > 0) + { + const char *new_offset = strstr(offset, "/"); + if (new_offset) { + offset = new_offset + 1; + } else { + return 0; + } + + index--; + } + + return atoi(offset); +} + +uint8_t getCC(const char *str) +{ + return getCC(str, -1); +} \ No newline at end of file diff --git a/OSC2Midi.h b/OSC2Midi.h new file mode 100644 index 0000000..a91b2c7 --- /dev/null +++ b/OSC2Midi.h @@ -0,0 +1,9 @@ +#ifndef OSC2MIDI_H +#define OSC2MIDI_H + +#include + +uint8_t getCC(const char *str, int index); +uint8_t getCC(const char *str); + +#endif \ No newline at end of file diff --git a/OSC2MidiGateway.ino b/OSC2MidiGateway.ino new file mode 100644 index 0000000..9f3712a --- /dev/null +++ b/OSC2MidiGateway.ino @@ -0,0 +1,116 @@ +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include +#include "OSC2Midi.h" + +void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t value); + +WiFiUDP udp; + +/** + source address of last OSC message for midi2osc messages. +*/ +IPAddress clientIP; + +/*IPAddress local_IP(192,168,4,2); + IPAddress gateway(192,168,4,1); + IPAddress subnet(255,255,255,0);*/ + +MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI); + +void setup() { + // Midi via UART0 + Serial.begin(31250); + Serial.swap(); + +#ifdef DEBUG + // Debug via UART1 TX only + Serial1.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY, 2); + Serial1.setDebugOutput(true); +#endif + + DEBUG_MSG("\nHello OSC2Midi!\n"); + + WiFi.softAP("OSC2Midi", "Midi2OSCGateway"); + + DEBUG_MSG("\nAP IP address: %s\n", WiFi.softAPIP().toString().c_str()); + + udp.begin(8000); + + MIDI.setHandleControlChange(MidiCCToOSC); +} + +void OSCToMidiCC(OSCMessage &msg, int offset) { + char address[100] = { 0 }; + uint8_t cc, value; + + msg.getAddress(address, offset, sizeof(address)); + + if (msg.size() == 1 && msg.isFloat(0)) { + // Single or multi control with sending one value + cc = getCC(address); + value = round(msg.getFloat(0)); + value = value > 127 ? 127 : value; + DEBUG_MSG("MSG: %s\tCC: %u\tValue: %u\n", address, cc, value); + MIDI.sendControlChange(cc, value, 1); + } else if (msg.size() == 2 && msg.isFloat(0) && msg.isFloat(1)) { + // XY pad, two values + cc = getCC(address, 0); + value = round(msg.getFloat(0)); + value = value > 127 ? 127 : value; + DEBUG_MSG("MSG: %s\tCC: %u\tValue: %u\n", address, cc, value); + MIDI.sendControlChange(cc, value, 1); + + cc = getCC(address, 1); + value = round(msg.getFloat(1)); + value = value > 127 ? 127 : value; + DEBUG_MSG("MSG: %s\tCC: %u\tValue: %u\n", address, cc, value); + MIDI.sendControlChange(cc, value, 1); + } else { + DEBUG_MSG("Cannot handle: %s\n", address); + } +} + +void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t value) { + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "/midi/cc/%u", number); + + OSCMessage msg = OSCMessage(buffer); + msg.add(value * 1.0); + + DEBUG_MSG("MidiCCToOsc: %s %f", buffer, value * 1.0); + + udp.beginPacket(clientIP, 8001); + msg.send(udp); + udp.endPacket(); +} + +void loop() { + OSCMessage msg; + uint8_t buffer[1024]; + + // Check if there are any OSC packets to handle + size_t size = udp.parsePacket(); + if (size > 0 && size <= 1024) { + udp.read(buffer, size); + msg.fill(buffer, size); + + if (!msg.hasError()) { + DEBUG_OSC_MESSAGE(msg); + msg.route("/midi/cc", OSCToMidiCC); + } else { + DEBUG_MSG("Error parsing OSC message: %d\n", msg.getError()); + } + + // Keep track of the client IP address for "talking back" + clientIP = udp.remoteIP(); + } + + // Check if there are any CC messages from synth itself + MIDI.read(); +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..c0c290e --- /dev/null +++ b/debug.h @@ -0,0 +1,26 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#ifdef DEBUG + +#define DEBUG_ESP_PORT Serial1 +#define DEBUG_MSG(...) Serial1.printf( __VA_ARGS__ ) + +#define DEBUG_OSC_MESSAGE(msg) \ + do { \ + char address[100]; \ + msg.getAddress(address, 0, sizeof(address)); \ + Serial1.printf("osc message: [%d] %s ", msg.size(), address); \ + for (int i = 0; i < msg.size(); i++) { \ + if (msg.isFloat(i)) { Serial1.printf("f:%f\t", msg.getFloat(i)); } \ + if (msg.isInt(i)) { Serial1.printf("i:%d\t", msg.getInt(i)); } \ + } \ + Serial1.printf("\n"); \ + } while(0); + +#else +#define DEBUG_MSG(...) +#define DEBUG_OSC_MESSAGE(...) +#endif + +#endif \ No newline at end of file