The universal MIDI hub for ESP32 β 9 transports, one API.
ESP32_Host_MIDI turns your ESP32 into a full-featured, multi-protocol MIDI hub. Connect a USB keyboard, receive notes from an iPhone via Bluetooth, bridge your DAW over WiFi with RTP-MIDI (Apple MIDI), control Max/MSP via OSC, reach 40-year-old synths through a DIN-5 serial cable, and link multiple ESP32 boards wirelessly with ESP-NOW β all simultaneously, all through the same clean event API.
#include <ESP32_Host_MIDI.h>
void setup() { midiHandler.begin(); }
void loop() {
midiHandler.task();
for (const auto& ev : midiHandler.getQueue()) {
char noteBuf[8];
Serial.printf("%-12s %-4s ch=%d vel=%d\n",
MIDIHandler::statusName(ev.statusCode),
MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)),
ev.channel0 + 1, ev.velocity7);
}
}A partial list. Every combination of transports opens a new instrument, tool, or installation.
Wireless MIDI interfaces
- USB keyboard β ESP32 β WiFi β macOS (Logic Pro / GarageBand) β no drivers, no cables to the Mac
- iPhone / iPad BLE app β ESP32 β USB MIDI Device β DAW port β iOS apps become studio controllers
- ESP32 presents itself as a USB MIDI Class Compliant interface β plug into any computer, it just works
Custom hardware instruments
- Effects pedal board β ESP32 sends Program Change / CC messages to a Daisy Seed or hardware multi-effects unit; display shows preset name and bank
- MIDI drum pad β piezo sensors on ADC inputs β velocity-sensitive MIDI notes β USB or BLE
- Custom synthesizer β ESP32 receives MIDI and controls an external DAC + VCO/VCA analog circuit, or triggers a Daisy Seed running a synth engine
- MIDI controller β encoders, faders, buttons, touchpads β USB MIDI Device β any DAW
- MIDI to CV converter β ESP32 + external DAC (MCP4728, MCP4921) β 0β5 V CV / gate for Eurorack and analog synths
- Wireless expression pedal β foot controller with ESP-NOW β central ESP32 hub β CC messages
- Smart metronome / clock β generates MIDI Clock at precise BPM, sent simultaneously over USB, BLE, DIN-5, and WiFi
- Theremin with MIDI output β ultrasonic sensors or capacitive touch β pitch + volume β MIDI notes
- MIDI accordion or wind controller β pressure sensors + buttons β ESP32 β BLE β iPad instrument
Bridges and routers
- DIN-5 vintage synth β ESP32 β USB Device β modern DAW β zero-driver adapter
- Wireless stage rig: ESP-NOW mesh of performers β single USB output to FOH computer Creative software integration
- Max/MSP / Pure Data / SuperCollider β ESP32 over OSC β bidirectional, address-mapped
- TouchOSC tablet β ESP32 β DIN-5 hardware synth β touchscreen for vintage gear
- Algorithmic composition in Max β OSC β ESP32 β BLE β iOS instrument app
Monitoring and education
- Live piano roll: keys lit as you play, scrollable view on a 1.9" display
- Real-time chord detection: plays a chord, see its name instantly ("Cmaj7", "Dm7β5")
- MIDI event logger with timestamps, channel, velocity, and chord grouping
| Transport | Protocol | Physical | Latency | Requires |
|---|---|---|---|---|
| USB Host | USB MIDI 1.0 | USB-OTG cable | < 1 ms | ESP32-S3 / S2 / P4 |
| USB Host MIDI 2.0 | USB MIDI 2.0 (UMP) | USB-OTG cable | < 1 ms | ESP32-S3 / S2 / P4 |
| BLE MIDI | BLE MIDI 1.0 | Bluetooth LE | 3β15 ms | Any ESP32 with BT |
| USB Device | USB MIDI 1.0 | USB-OTG cable | < 1 ms | ESP32-S3 / S2 / P4 |
| ESP-NOW MIDI | ESP-NOW | 2.4 GHz radio | 1β5 ms | Any ESP32 |
| RTP-MIDI (WiFi) | AppleMIDI / RFC 6295 | WiFi UDP | 5β20 ms | Any ESP32 with WiFi |
| Ethernet MIDI | AppleMIDI / RFC 6295 | Wired (W5x00 / native) | 2β10 ms | W5500 SPI or ESP32-P4 |
| OSC | Open Sound Control | WiFi UDP | 5β15 ms | Any ESP32 with WiFi |
| UART / DIN-5 | Serial MIDI 1.0 | DIN-5 connector | < 1 ms | Any ESP32 |
All transports share a single MIDIHandler event queue and the same send API. Mix and match at will.
#include <ESP32_Host_MIDI.h>
// Arduino IDE: Tools > USB Mode β "USB Host"
void setup() {
Serial.begin(115200);
midiHandler.begin();
}
void loop() {
midiHandler.task();
for (const auto& ev : midiHandler.getQueue()) {
char noteBuf[8];
Serial.println(MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)));
}
}Access individual fields:
for (const auto& ev : midiHandler.getQueue()) {
ev.statusCode; // MIDI_NOTE_ON | MIDI_NOTE_OFF | MIDI_CONTROL_CHANGE | ...
ev.channel0; // 0β15 (MIDI spec)
ev.noteNumber; // MIDI note number (0β127)
ev.velocity7; // 0β127 (MIDI 1.0)
ev.velocity16; // 0β65535 (MIDI 2.0, scaled)
ev.pitchBend14; // 0β16383 (center = 8192)
ev.pitchBend32; // 0β0xFFFFFFFF (MIDI 2.0, center = 0x80000000)
ev.chordIndex; // groups simultaneous notes
ev.timestamp; // millis() at arrival
// Static helpers (zero allocation):
MIDIHandler::noteName(ev.noteNumber); // "C", "C#", "D" ...
MIDIHandler::noteOctave(ev.noteNumber); // -1 to 9
MIDIHandler::statusName(ev.statusCode); // "NoteOn", "ControlChange" ...
}RTP-MIDI / Apple MIDI connecting to macOS Β· 25-key scrolling piano roll
25-key scrolling piano roll Β· Real-time chord name (Gingoduino) Β· Event queue debug
BLE Receiver (iPhone β ESP32) Β· BLE Sender Β· Piano debug view
Videos β each example folder contains an
.mp4demo insideexamples/<name>/images/.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INPUTS MIDIHandler OUTPUTS β
β β
β USB keyboard ββ[USBConnection]βββββΊ ββββββββββββββββ β
β USB MIDI 2.0 ββ[USBMIDI2Conn]βββββΊ β β β
β iPhone BLE ββ[BLEConnection]βββββΊ β β β
β macOS WiFi ββ[RTPMIDIConn.]ββββββΊ β Event Queue ββββΊ getQueue()β
β DAW USB out ββ[USBDeviceConn]βββββΊ β (ring buf, β β
β Max/MSP OSC ββ[OSCConnection]βββββΊ β thread-safe)ββββΊ Active β
β W5500 LAN ββ[EthernetMIDI]ββββββΊ β β notes β
β DIN-5 serial ββ[UARTConnection]ββββΊ β Chord β β
β ESP32 radio ββ[ESPNowConn.]βββββββΊ ββββββββ¬βββββββββββΊ Chord β
β β names β
β β β
β βΌ β
β sendMidiMessage() β
β (broadcasts to ALL transports) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Core 0 β USB Host task, BLE stack, radio / network drivers (FreeRTOS tasks)
Core 1 β midiHandler.task() + your loop() code
Thread safety β ring buffers + portMUX spinlocks on every transport
Every transport implements the same MIDITransport abstract interface. Adding a new transport is one line: midiHandler.addTransport(&myTransport).
Connects any class-compliant USB MIDI device β keyboards, pads, interfaces, drum machines, controllers β directly to the ESP32's USB-OTG port. No hub, no driver, no OS configuration.
Boards: ESP32-S3, ESP32-S2, ESP32-P4 Β· Arduino IDE: Tools > USB Mode β "USB Host"
#include <ESP32_Host_MIDI.h>
void setup() { midiHandler.begin(); }Examples: T-Display-S3, T-Display-S3-Queue, T-Display-S3-Piano, T-Display-S3-Gingoduino
MIDI 2.0: Use
USBMIDI2Connectionfor native USB MIDI 2.0 with UMP. See the MIDI 2.0 section below.
The ESP32 advertises as a BLE MIDI 1.0 peripheral. macOS (Audio MIDI Setup β Bluetooth), iOS (GarageBand, AUM, Loopy, Moog), and Android connect without any pairing ritual. Also supports Central (scanner) mode to connect to another BLE MIDI device.
Boards: Any ESP32 with Bluetooth Β· Range: ~30 m Β· Latency: 3β15 ms
#include <ESP32_Host_MIDI.h>
void setup() { midiHandler.begin(); } // BLE advertises automaticallyExamples: T-Display-S3-BLE-Sender, T-Display-S3-BLE-Receiver
The ESP32-S3 presents itself as a class-compliant USB MIDI interface to the host computer. macOS, Windows, and Linux recognise it instantly β no driver. Acts as a transparent bridge: any MIDI from BLE, WiFi, UART, or ESP-NOW is forwarded to the DAW via USB, and vice versa.
Boards: ESP32-S3, ESP32-S2, ESP32-P4 Β· Arduino IDE: Tools > USB Mode β "USB-OTG (TinyUSB)"
Cannot coexist with USB Host β both use the OTG port.
#include "src/USBDeviceConnection.h"
USBDeviceConnection usbMIDI("ESP32 MIDI"); // name shown in DAW MIDI port list
void setup() {
midiHandler.addTransport(&usbMIDI);
usbMIDI.begin();
midiHandler.begin();
}Examples: USB-Device-MIDI, T-Display-S3-USB-Device
Ultra-low-latency (~1β5 ms) wireless MIDI between ESP32 boards via Espressif's proprietary peer-to-peer radio. No WiFi router, no handshake, no pairing. Broadcast mode (all boards receive everyone's notes) or unicast.
Boards: Any ESP32 Β· Range: ~200 m open air Β· Infrastructure: none
#include "src/ESPNowConnection.h"
ESPNowConnection espNow;
void setup() {
espNow.begin();
midiHandler.addTransport(&espNow);
midiHandler.begin();
}Examples: ESP-NOW-MIDI, T-Display-S3-ESP-NOW-Jam
Implements Apple MIDI (RTP-MIDI, RFC 6295) over WiFi UDP. macOS and iOS discover the ESP32 automatically via mDNS Bonjour β it appears in Audio MIDI Setup β Network with no manual configuration. Compatible with Logic Pro, GarageBand, Ableton, and any CoreMIDI app.
Requires: lathoub/Arduino-AppleMIDI-Library v3.x
#include <WiFi.h>
#include "src/RTPMIDIConnection.h"
RTPMIDIConnection rtpMIDI;
void setup() {
WiFi.begin("YourSSID", "YourPassword");
while (WiFi.status() != WL_CONNECTED) delay(500);
midiHandler.addTransport(&rtpMIDI);
rtpMIDI.begin();
midiHandler.begin();
}Examples: RTP-MIDI-WiFi
Same RTP-MIDI / AppleMIDI protocol over a wired W5x00 SPI Ethernet module or ESP32-P4 native Ethernet MAC. Lower and more consistent latency than WiFi. Ideal for studio racks and live venues with managed networks.
Requires: lathoub/Arduino-AppleMIDI-Library v3.x + Arduino Ethernet library
#include <SPI.h>
#include "src/EthernetMIDIConnection.h"
EthernetMIDIConnection ethMIDI;
static const uint8_t MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
void setup() {
midiHandler.addTransport(ðMIDI);
ethMIDI.begin(MAC); // DHCP β pass a static IPAddress as second arg for fixed IP
midiHandler.begin();
}Examples: Ethernet-MIDI
Bidirectional OSC β MIDI bridge over WiFi UDP. Receives OSC messages from Max/MSP, Pure Data, SuperCollider, and TouchOSC and converts them to MIDI events β and sends every MIDI event out as an OSC message.
Address map: /midi/noteon, /midi/noteoff, /midi/cc, /midi/pc, /midi/pitchbend, /midi/aftertouch
Requires: CNMAT/OSC library
#include <WiFi.h>
#include "src/OSCConnection.h"
OSCConnection oscMIDI;
void setup() {
WiFi.begin("YourSSID", "YourPassword");
while (WiFi.status() != WL_CONNECTED) delay(500);
midiHandler.addTransport(&oscMIDI);
oscMIDI.begin(8000, IPAddress(192, 168, 1, 100), 9000);
midiHandler.begin();
}Examples: OSC-MIDI-WiFi, T-Display-S3-OSC
Standard MIDI serial (31250 baud, 8N1) for connecting vintage hardware β synthesizers, drum machines, mixers, sequencers, anything with a DIN-5 connector. Supports running status, real-time messages (Clock, Start, Stop), and multiple simultaneous UART ports (ESP32-P4 has five hardware UARTs).
Hardware: TX β DIN-5 pin 5 via 220 Ξ©; PC-900V / 6N138 optocoupler on RX β DIN-5 pin 4
#include "src/UARTConnection.h"
UARTConnection uartMIDI;
void setup() {
uartMIDI.begin(Serial1, /*RX=*/16, /*TX=*/17);
midiHandler.addTransport(&uartMIDI);
midiHandler.begin();
}Examples: UART-MIDI-Basic, P4-Dual-UART-MIDI
Native USB MIDI 2.0/UMP support with automatic protocol negotiation. USBMIDI2Connection extends USBConnection β scans the device's configuration descriptor for both Alt 0 (MIDI 1.0) and Alt 1 (MIDI 2.0), preferring MIDI 2.0 when available. Falls back to MIDI 1.0 transparently.
After selecting MIDI 2.0, performs the mandatory UMP Endpoint Discovery and Protocol Negotiation sequence. Raw UMP words (32-bit) are delivered via callback β no conversion to MIDI 1.0.
#include "src/USBMIDI2Connection.h"
USBMIDI2Connection usb;
void onUMP(void*, const uint32_t* words, uint8_t count) {
// Raw UMP words β MIDI 2.0 native resolution
}
void setup() {
usb.setUMPCallback(onUMP, nullptr);
usb.setMidiCallback(onMidi, nullptr); // MIDI 1.0 fallback
midiHandler.addTransport(&usb);
midiHandler.begin();
}Query device capabilities after negotiation:
if (usb.isMIDI2() && usb.isNegotiated()) {
auto& ep = usb.getEndpointInfo();
Serial.printf("UMP v%d.%d, %d function blocks\n",
ep.umpVersionMajor, ep.umpVersionMinor, ep.numFunctionBlocks);
}Boards: ESP32-S3, ESP32-S2, ESP32-P4 Β· Examples: T-Display-S3-AMoled-MIDI2-UMP
Any MIDI arriving on any transport is automatically forwarded to all others β no extra code.
| Bridge | Diagram |
|---|---|
| Wireless keyboard β DAW | iPhone BLE β ESP32 β USB Device β Logic Pro |
| USB keyboard β WiFi | USB keyboard β ESP32 β RTP-MIDI β macOS |
| Legacy to modern | DIN-5 synth β ESP32 β USB Device β any DAW |
| Modern to legacy | macOS β RTP-MIDI β ESP32 β DIN-5 β 1980s drum machine |
| Wireless stage mesh | ESP-NOW nodes β ESP32 hub β USB β FOH computer |
| Creative software | Max/MSP OSC β ESP32 β BLE β iPad instrument app |
Full hub β receive everything, send everywhere:
USB keyboard ββ
iPhone BLE ββ€
macOS RTP βββΌβββΊ MIDIHandler βββΊ USB Device (DAW)
DIN-5 synth ββ€ βββΊ BLE (iOS app)
TouchOSC ββ€ βββΊ DIN-5 (drum machine)
ESP-NOW ββ βββΊ ESP-NOW (stage nodes)
ESP32_Host_MIDI acts as the MIDI brain and protocol hub. It connects and communicates with a broad ecosystem of boards and devices.
| Board | Connection | Use case |
|---|---|---|
| Daisy Seed (Electro-Smith) | UART / DIN-5 or USB | DSP audio synthesis engine; ESP32 sends MIDI, Daisy plays notes |
| Teensy 4.x (PJRC) | UART serial or USB Host | Complex MIDI routing or synthesis; excellent USB MIDI native support |
| Arduino UNO / MEGA / Nano | UART serial (DIN-5) | Classic MIDI projects; ESP32 is the wireless gateway |
| Raspberry Pi | RTP-MIDI, OSC, or USB | DAW host, audio processing, generative composition |
| Eurorack / modular synths | MIDI DIN-5 β CV/gate interface | Pitch CV, gate, velocity β analogue voltage via converter module |
| Hardware synthesizers | DIN-5 | Any keyboard, rack synth, or effects unit with MIDI In/Out/Thru |
| iPad / iPhone | BLE MIDI | GarageBand, AUM, Moog apps, NLog, Animoog β all CoreMIDI-compatible |
| Computer DAW | USB Device or RTP-MIDI | Logic Pro, Ableton, Bitwig, FL Studio, Reaper, Pro Tools |
Daisy Seed + ESP32 is a particularly powerful combination: the ESP32 handles all MIDI connectivity (USB, BLE, WiFi, DIN-5) and the Daisy Seed processes audio in real time at 48 kHz / 24-bit with its ARM Cortex-M7 DSP. They talk over a single UART/DIN-5 cable.
Teensy 4.1 can run complex MIDI logic, arpeggiators, chord voicers, or sequencers, while ESP32 handles wireless transport β each board doing what it does best.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PROJECT β COMPONENTS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Wireless MIDI pedal β ESP32 + buttons + enclosure β ESP-NOW β
β board β β central hub β DIN-5 / USB to amp rack β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β MIDI drum pad β ESP32 + piezo sensors + ADC β velocity- β
β β sensitive MIDI notes over USB or BLE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Synthesizer β ESP32 + Daisy Seed: ESP32 bridges all β
β β MIDI protocols, Daisy generates audio β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β MIDI to CV converter β ESP32 + MCP4728 DAC β 0β5 V pitch CV + β
β β gate for Eurorack / analogue synths β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Custom MIDI β ESP32-S3 + encoders + faders + OLED β β
β controller β USB MIDI Device recognized by any DAW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Piano learning aid β ESP32 + RGB LEDs on piano keys + display β
β β β lights the correct key for each note β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Wireless expression β ESP32 + FSR / potentiometer in foot β
β pedal β enclosure β CC messages via ESP-NOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β MIDI arpeggiator / β ESP32 receives chords, generates β
β sequencer β arpeggiated patterns, sends to DIN-5 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Theremin / air synth β Ultrasonic sensors β pitch + volume β β
β β MIDI notes via BLE or USB β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Interactive art β Motion / proximity / touch sensors β β
β installation β MIDI β generative music / light control β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The LilyGO T-Display-S3 has a 1.9" 170Γ320 ST7789 display + ESP32-S3. These examples show a live MIDI dashboard in landscape mode (320Γ170 after setRotation(2)).
| Example | Transport | What the display shows |
|---|---|---|
T-Display-S3 |
USB Host | Active notes + event log |
T-Display-S3-Queue |
USB Host | Full event queue debug view |
T-Display-S3-Piano |
USB Host | 25-key scrollable piano roll |
T-Display-S3-Piano-Debug |
USB Host | Piano roll + extended debug info |
T-Display-S3-Gingoduino |
USB Host + BLE | Chord names (music theory engine) |
T-Display-S3-BLE-Sender |
BLE | Send mode status + event log |
T-Display-S3-BLE-Receiver |
BLE | Receive mode + note log |
T-Display-S3-ESP-NOW-Jam |
ESP-NOW | Peer status + jam events |
T-Display-S3-OSC |
OSC + WiFi | WiFi status + OSC bridge log |
T-Display-S3-USB-Device |
BLE + USB Device | Dual status + bridge log |
Gingoduino is a music theory library for embedded systems β the same engine that powers the T-Display-S3-Gingoduino example. When integrated via GingoAdapter.h, it listens to the same MIDI event stream and continuously analyses the active notes to produce:
- Chord name β "Cmaj7", "Dm7β5", "G7", "Am" with extensions and alterations
- Root note β identified root pitch of the chord
- Active note set β structured list of currently pressed notes
- Interval analysis β intervals between notes (M3, m7, P5, etc.)
- Scale matching β identifies likely scale (major, minor, modes)
Everything runs on-device at interrupt speed β no cloud, no network, no latency.
#include "src/GingoAdapter.h" // requires Gingoduino β₯ v0.2.2
void loop() {
midiHandler.task();
// Chord name updates automatically as notes arrive and are released:
std::string chord = gingoAdapter.getChordName(); // "Cmaj7", "Dm", "G7sus4" β¦
std::string root = gingoAdapter.getRootNote(); // "C", "D", "G" β¦
display.setChord(chord.c_str());
}T-Display-S3-Gingoduino: chord name, root note, and active keys updated in real time
β github.com/sauloverissimo/gingoduino
Gingo is the desktop and Python counterpart of Gingoduino β the same music theory concepts ported to Python for use in scripts, DAW integrations, MIDI processors, composition tools, and web apps.
Use it to:
- Analyse MIDI files and extract chord progressions
- Build Python MIDI processors that recognise chords on the fly
- Create web applications with real-time music theory annotation
- Prototype music theory algorithms before porting them to Gingoduino
- Generate chord charts, lead sheets, and educational exercises
from gingo import Gingo
g = Gingo()
chord = g.identify([60, 64, 67, 71]) # C E G B
print(chord.name) # "Cmaj7"
print(chord.root) # "C"β github.com/sauloverissimo/gingo β sauloverissimo.github.io/gingo
ESP32 + Gingo workflow: prototype music theory algorithms in Python with Gingo β port the logic to Gingoduino on ESP32 β display chord names live on T-Display-S3.
| Chip | USB Host | BLE | USB Device | WiFi | Ethernet (native) | UART | ESP-NOW |
|---|---|---|---|---|---|---|---|
| ESP32-S3 | β | β | β | β | β (W5500 SPI) | β | β |
| ESP32-S2 | β | β | β | β | β (W5500 SPI) | β | β |
| ESP32-P4 | β | β | β | β | β | β Γ5 | β |
| ESP32 (classic) | β | β | β | β | β (W5500 SPI) | β | β |
| ESP32-C3 / C6 / H2 | β | β | β | β | β | β | β |
W5500 SPI Ethernet works on any ESP32 via
EthernetMIDIConnection.
| Use case | Board |
|---|---|
| Best all-round (USB Host + BLE + WiFi + display) | LilyGO T-Display-S3 |
| Full USB Host + USB Device + BLE | Any ESP32-S3 DevKit |
| Ultra-low-latency wireless stage mesh | ESP32 DevKit (ESP-NOW) |
| Wired studio rack | ESP32-P4 native Ethernet or any ESP32 + W5500 |
| DIN-5 MIDI gateway | Any ESP32 + UART optocoupler |
Arduino IDE: Sketch β Include Library β Manage Libraries β search ESP32_Host_MIDI
PlatformIO:
[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
lib_deps =
sauloverissimo/ESP32_Host_MIDI
# lathoub/Arduino-AppleMIDI-Library ; RTP-MIDI + Ethernet MIDI
# arduino-libraries/Ethernet ; Ethernet MIDI
# CNMAT/OSC ; OSC
# sauloverissimo/gingoduino ; Chord namesBoard package: Tools > Boards Manager β "esp32" by Espressif β β₯ 3.0.0
USB Host and USB Device require arduino-esp32 β₯ 3.0 (TinyUSB MIDI).
| Transport | Required library |
|---|---|
| RTP-MIDI / Ethernet MIDI | lathoub/Arduino-AppleMIDI-Library |
| Ethernet MIDI | arduino-libraries/Ethernet |
| OSC | CNMAT/OSC |
| Chord names | sauloverissimo/gingoduino |
| USB Host / Device / BLE / ESP-NOW | Built into arduino-esp32 |
// Setup
midiHandler.begin(); // start built-in transports (USB, BLE, ESP-NOW)
midiHandler.begin(cfg); // with custom config
midiHandler.addTransport(&t); // register external transport
// Receive
const auto& q = midiHandler.getQueue(); // event ring buffer
std::vector<std::string> n = midiHandler.getActiveNotesVector(); // ["C4","E4","G4"]
std::string chord = midiHandler.getChordName(); // "Cmaj7"
// Send (broadcasts to ALL transports simultaneously)
midiHandler.sendNoteOn(ch, note, vel);
midiHandler.sendNoteOff(ch, note, vel);
midiHandler.sendControlChange(ch, ctrl, val);
midiHandler.sendProgramChange(ch, prog);
midiHandler.sendPitchBend(ch, val); // 0β16383, center = 8192MIDIHandlerConfig:
MIDIHandlerConfig cfg;
cfg.maxEvents = 20; // queue capacity
cfg.enableHistory = true; // keep full history
cfg.chordDetection = true; // group simultaneous notesCustom transport interface:
class MyTransport : public MIDITransport {
public:
void task() override;
bool isConnected() const override;
bool sendMidiMessage(const uint8_t* data, size_t len) override;
protected:
void dispatchMidiData(const uint8_t* data, size_t len); // inject received MIDI
void dispatchConnected();
void dispatchDisconnected();
};
midiHandler.addTransport(&myTransport);ESP32_Host_MIDI/
βββ src/
β βββ ESP32_Host_MIDI.h β main include (USB + BLE + ESP-NOW built-in)
β βββ MIDIHandler.h / .cpp β event queue, chord detection, active notes
β βββ MIDITransport.h β abstract transport interface
β βββ MIDIHandlerConfig.h β config struct
β βββ USBConnection.h / .cpp β USB Host OTG
β βββ USBMIDI2Connection.h / .cpp β USB Host MIDI 2.0 (UMP negotiation)
β βββ MIDI2Support.h β UMP types, scaler, builder, parser
β βββ BLEConnection.h / .cpp β BLE MIDI
β βββ ESPNowConnection.h / .cpp β ESP-NOW MIDI
β βββ UARTConnection.h / .cpp β UART / DIN-5
β βββ USBDeviceConnection.h β USB MIDI Device (header-only)
β βββ RTPMIDIConnection.h / .cpp β RTP-MIDI over WiFi (header-only)
β βββ EthernetMIDIConnection.h β AppleMIDI over Ethernet (header-only)
β βββ OSCConnection.h β OSC β MIDI bridge (header-only)
β βββ GingoAdapter.h β Gingoduino chord integration
βββ extras/
β βββ tests/
β βββ test_native.cpp β MIDI2Support + MIDITransport tests (32)
β βββ test_handler.cpp β MIDIHandler tests (99)
β βββ test_midi2_scan.cpp β USB MIDI 2.0 descriptor tests (120)
βββ examples/
βββ T-Display-S3/ T-Display-S3-Queue/
βββ T-Display-S3-Piano/ T-Display-S3-Piano-Debug/
βββ T-Display-S3-Gingoduino/ T-Display-S3-BLE-Sender/
βββ T-Display-S3-BLE-Receiver/ T-Display-S3-ESP-NOW-Jam/
βββ T-Display-S3-OSC/ T-Display-S3-USB-Device/
βββ ESP-NOW-MIDI/ UART-MIDI-Basic/
βββ P4-Dual-UART-MIDI/ RTP-MIDI-WiFi/
βββ Ethernet-MIDI/ OSC-MIDI-WiFi/
βββ USB-Device-MIDI/
MIT β see LICENSE
Built with β€οΈ for musicians, makers, and researchers.
Issues and contributions welcome:
github.com/sauloverissimo/ESP32_Host_MIDI







