Added multi client support and sync between clients.

master
Holger Wirtz 4 years ago
parent 3d5014aaae
commit 1e58a4cb4b
  1. 191
      OSC2MIDI.ino

@ -69,6 +69,9 @@
#define ENC_BUTTON_PIN 32
#define ENC_A_PIN 34
#define ENC_B_PIN 35
#define MAX_CLIENTS 5
#define KRATE_CHECK_CLIENTIP 2000
#define CLIENT_TIMEOUT 10000
void OSCToMidiCC(OSCMessage &msg, int offset);
void OSCMixerMuteToMidiCC(OSCMessage &msg, int offset);
@ -83,7 +86,8 @@ void ConfigAPStarted(WiFiManager* wm);
void check_mode(void);*/
WiFiUDP udp;
IPAddress clientIP;
IPAddress clientIP[MAX_CLIENTS];
uint32_t clientIP_time[MAX_CLIENTS];
LiquidCrystal_I2C lcd(LCD_I2C_ADDR, LCD_COL, LCD_ROW);
HardwareSerial midi1(2); // RX: 16, TX: 17
#ifndef D5
@ -102,7 +106,7 @@ bool last_reset_ap_check = false;
looper sched;
bool write_state = false;
uint32_t last_usage = millis();
bool broadcast_send = false;
bool broadcast_send[MAX_CLIENTS];
uint32_t midi_ignore_volume_cc = 0;
ESP32Encoder enc;
@ -124,9 +128,12 @@ void setup()
DEBUG_MSG("<SETUP>\n");
memset(midistate_cc, -1, 16 * 128);
memset(midistate_mute, -1, 16);
memset(midistate_solo, -1, 16);
memset(midistate_cc, -1, 16 * 128 * sizeof(uint8_t));
memset(midistate_mute, -1, 16 * sizeof(uint8_t));
memset(midistate_solo, -1, 16 * sizeof(uint8_t));
memset(clientIP, 0, MAX_CLIENTS * sizeof(IPAddress));
memset(clientIP_time, 0, MAX_CLIENTS * sizeof(uint8_t));
memset(broadcast_send, false, MAX_CLIENTS * sizeof(uint8_t));
Serial.setDebugOutput(true);
Serial.println(F("OSC2MIDI (c)2020 H. Wirtz <wirtz@parasitstudio.de>"));
@ -246,7 +253,9 @@ void setup()
sched.addJob(check_mode, KRATE_MODE);
sched.addJob(check_reset_ap_data, KRATE_RESET_AP_DATA);
sched.addJob(check_write_state, KRATE_CHECK_WRITE_STATE);
sched.addJob(check_clientIPs, KRATE_CHECK_CLIENTIP);
sched.addJob(enc_show, 1000);
sched.addJob(show_clientIP, 5000);
//sched.addJob(show_midi_state, KRATE_STATE);
listDir(SPIFFS, "/", 1);
@ -268,14 +277,16 @@ void loop()
{
IPAddress tmpIP = udp.remoteIP();
// Keep track of the client IP address for "talking back"
if (clientIP != tmpIP)
uint8_t slot;
if (slot = check_for_clientIP(tmpIP) < 0)
{
clientIP = tmpIP;
DEBUG_MSG("New connection from: %d.%d.%d.%d\n", clientIP[0], clientIP[1], clientIP[2], clientIP[3]);
slot = add_clientIP(tmpIP);
DEBUG_MSG("New connection from: %d.%d.%d.%d\n", tmpIP[0], tmpIP[1], tmpIP[2], tmpIP[3]);
}
// Check if there are any OSC packets to handle
udp.read(buffer, size);
msg.fill(buffer, size);
clientIP_time[slot] = millis();
if (!msg.hasError())
{
@ -286,6 +297,33 @@ void loop()
msg.route("/ping", ping);
//msg.route("/midi/sysex", OSCToMidiSYSEX);
//msg.route("/midi/note", OSCToMidiNote);
char address[100];
msg.getAddress(address, 0, sizeof(address));
if (strcmp(address, "/ping"))
{
DEBUG_MSG("Broadcasting [%s] from %d.%d.%d.%d to\n", address, tmpIP[0], tmpIP[1], tmpIP[2], tmpIP[3]);
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0 && clientIP[i])
{
if (!same_ip(tmpIP, clientIP[i]))
{
udp.beginPacket(clientIP[i], UDP_SEND_PORT);
udp.write(buffer, size);
udp.endPacket();
udp.flush();
DEBUG_MSG("\t%d.%d.%d.%d\n", clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3]);
}
}
}
}
else
{
int8_t slot = check_for_clientIP(tmpIP);
if (slot >= 0)
clientIP_time[slot] = millis();
}
}
else
{
@ -435,30 +473,26 @@ void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t val)
if (number == 7)
if (millis() - MIDI_IGNORE_VOLUME_CC < midi_ignore_volume_cc)
return;
else
DEBUG_MSG("\n!!!%d - %d!!!\n\n", millis() - MIDI_IGNORE_VOLUME_CC, midi_ignore_volume_cc);
snprintf(buffer, sizeof(buffer), "/midi/cc/%d/%d", channel, number);
DEBUG_MSG("MidiCCToOsc: %s %f\n", buffer, val);
change_midistate_cc(channel, number, val);
if (clientIP)
{
OSCMessage msg = OSCMessage(buffer);
msg.add(val);
udp.beginPacket(clientIP, UDP_SEND_PORT);
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0 && clientIP[i])
{
udp.beginPacket(clientIP[i], UDP_SEND_PORT);
msg.send(udp);
udp.endPacket();
msg.empty();
udp.flush();
DEBUG_MSG("Sending MidiCCToOsc: %s %f to %d.%d.%d.%d:%d\n", buffer, val, clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3], UDP_SEND_PORT);
}
else
{
DEBUG_MSG("No client IP.\n");
}
//msg.empty();
}
void MidiMuteToOSC(uint8_t channel, uint8_t val)
@ -471,23 +505,21 @@ void MidiMuteToOSC(uint8_t channel, uint8_t val)
snprintf(buffer, sizeof(buffer), "/midi/mixer/mute/%d", channel);
DEBUG_MSG("MidiMuteToOsc: %s %f\n", buffer, val);
if (clientIP)
{
OSCMessage msg = OSCMessage(buffer);
msg.add(val);
udp.beginPacket(clientIP, UDP_SEND_PORT);
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0 && clientIP[i])
{
udp.beginPacket(clientIP[i], UDP_SEND_PORT);
msg.send(udp);
udp.endPacket();
msg.empty();
udp.flush();
DEBUG_MSG("Sending MidiMuteToOsc: %s %f to %d.%d.%d.%d\n", buffer, val, clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3]);
}
else
{
DEBUG_MSG("No client IP.\n");
}
//msg.empty();
}
void MidiSoloToOSC(uint8_t channel, uint8_t val)
@ -501,23 +533,21 @@ void MidiSoloToOSC(uint8_t channel, uint8_t val)
snprintf(buffer, sizeof(buffer), "/midi/mixer/solo/%d", channel);
DEBUG_MSG("MidiSoloToOsc: %s %f\n", buffer, float(val));
if (clientIP)
{
OSCMessage msg = OSCMessage(buffer);
msg.add(val);
udp.beginPacket(clientIP, UDP_SEND_PORT);
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0 && clientIP[i])
{
udp.beginPacket(clientIP[i], UDP_SEND_PORT);
msg.send(udp);
udp.endPacket();
msg.empty();
udp.flush();
DEBUG_MSG("Sending MidiSoloToOsc: %s %f to %d.%d.%d.%d\n", buffer, val, clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3]);
}
else
{
DEBUG_MSG("No client IP.\n");
}
//msg.empty();
}
void change_midistate_cc(uint8_t midichannel, uint8_t cc, uint8_t value)
@ -1014,7 +1044,7 @@ void broadcast_midistate(void)
{
uint8_t m, c;
DEBUG_MSG("Broadcast MIDI CC state : \n");
DEBUG_MSG("Broadcast MIDI CC state:\n");
for (m = 0; m < 16; m++)
{
@ -1063,11 +1093,14 @@ void check_reset_ap_data(void)
void ping(OSCMessage & msg, int offset)
{
if (clientIP && broadcast_send == false)
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
broadcast_send = true;
if (clientIP[i] && broadcast_send[i] == false)
{
broadcast_send[i] = true;
broadcast_midistate();
}
}
}
void ConfigAPWeb(void)
@ -1125,6 +1158,78 @@ void enc_show(void)
DEBUG_MSG(" button[%d] = %d\n", ENC_BUTTON_PIN, (uint8_t)digitalRead(ENC_BUTTON_PIN));
}
void check_clientIPs(void)
{
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0)
{
if (millis() - clientIP_time[i] > CLIENT_TIMEOUT)
{
DEBUG_MSG("Removing client slot %d: %d.%d.%d.%d\n", i, clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3]);
clientIP[i] = {0, 0, 0, 0};
clientIP_time[i] = 0;
broadcast_send[i] = false;
}
}
}
}
int8_t check_for_clientIP(IPAddress ip)
{
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (same_ip(clientIP[i], ip))
return (i);
}
return (-1);
}
uint8_t add_clientIP(IPAddress ip)
{
uint8_t oldest = 0;
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP_time[i] > 0)
{
for (uint8_t n = 0; n < MAX_CLIENTS; n++)
{
if (clientIP_time[i] < clientIP_time[n])
oldest = i;
}
}
else
{
oldest = i;
break;
}
}
clientIP[oldest] = ip;
clientIP_time[oldest] = millis();
DEBUG_MSG("Adding client slot %d: %d.%d.%d.%d\n", oldest, clientIP[oldest][0], clientIP[oldest][1], clientIP[oldest][2], clientIP[oldest][3]);
return (oldest);
}
void show_clientIP(void)
{
DEBUG_MSG("Connected clients:\n");
for (uint8_t i = 0; i < MAX_CLIENTS; i++)
{
if (clientIP[i])
DEBUG_MSG("Slot %d: %d.%d.%d.%d - %ld\n", i, clientIP[i][0], clientIP[i][1], clientIP[i][2], clientIP[i][3], clientIP_time[i]);
}
}
bool same_ip(IPAddress ip1, IPAddress ip2)
{
if (ip1[0] == ip2[0] && ip1[1] == ip2[1] && ip1[2] == ip2[2] && ip1[3] == ip2[3])
return (true);
else
return (false);
}
void listDir(fs::FS & fs, const char * dirname, uint8_t levels)
{
DEBUG_MSG("Listing directory : %s\n", dirname);

Loading…
Cancel
Save