|
|
|
@ -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); |
|
|
|
|