🚀 Primeiros Passos¶
Neste guia você terá o ESP32 recebendo e enviando MIDI em menos de 5 minutos.
Pré-requisito¶
- Biblioteca instalada (veja Instalação)
- ESP32-S3 com cabo USB-OTG ou qualquer ESP32 com Bluetooth
Passo 1 — O Sketch Mais Simples¶
Este sketch imprime todos os eventos MIDI recebidos via USB Host ou BLE no Serial Monitor:
#include <ESP32_Host_MIDI.h>
// Arduino IDE: Tools > USB Mode → "USB Host"
void setup() {
Serial.begin(115200);
midiHandler.begin(); // (1)
}
void loop() {
midiHandler.task(); // (2)
for (const auto& ev : midiHandler.getQueue()) { // (3)
char noteBuf[8];
Serial.printf("%-12s %-5s ch=%d vel=%d\n",
MIDIHandler::statusName(ev.statusCode), // "NoteOn" | "NoteOff" | "ControlChange"...
MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)), // "C4", "D#5"...
ev.channel0 + 1,
ev.velocity7);
}
}
Anotações:
begin()inicializa automaticamente USB Host (se o chip suportar) e BLE (se habilitado)task()deve ser chamado em todoloop()— ele drena os ring buffers de todos os transportesgetQueue()retorna a fila de eventos desde a última chamada detask()
Passo 2 — Acessar Campos do Evento¶
Cada evento tem os seguintes campos:
for (const auto& ev : midiHandler.getQueue()) {
// Identificação
ev.index; // Contador global de eventos (único, crescente)
ev.timestamp; // millis() no momento da chegada
ev.delay; // Δt em ms desde o evento anterior
// Tipo de mensagem
ev.statusCode; // MIDIStatus enum: MIDI_NOTE_ON, MIDI_NOTE_OFF, MIDI_CONTROL_CHANGE...
ev.channel0; // Canal MIDI: 0–15 (some +1 para exibir 1–16)
// Nota (apenas NoteOn / NoteOff)
ev.noteNumber; // Número MIDI: 0–127 (60 = C4 = Dó central)
ev.velocity7; // Velocidade 7-bit: 0–127 (também: valor CC, program, pressure)
ev.velocity16; // Velocidade 16-bit: 0–65535 (MIDI 2.0)
// Helpers estáticos (zero allocation)
// MIDIHandler::statusName(ev.statusCode) → "NoteOn", "NoteOff"...
// MIDIHandler::noteName(ev.noteNumber) → "C", "C#", "D"...
// MIDIHandler::noteWithOctave(ev.noteNumber, buf, sz) → "C4", "D#5"...
// Agrupamento de acordes
ev.chordIndex; // Notas simultâneas compartilham o mesmo chordIndex
// Pitch Bend (apenas PitchBend)
ev.pitchBend14; // 0–16383 (centro = 8192), MIDI 1.0
ev.pitchBend32; // 0–4294967295 (centro = 2147483648), MIDI 2.0
}
Exemplo — Apenas NoteOn¶
for (const auto& ev : midiHandler.getQueue()) {
if (ev.statusCode == MIDI_NOTE_ON && ev.velocity7 > 0) {
char noteBuf[8];
Serial.printf("Nota: %s Velocidade: %d Canal: %d\n",
MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)),
ev.velocity7,
ev.channel0 + 1);
}
}
Exemplo — Control Change¶
for (const auto& ev : midiHandler.getQueue()) {
if (ev.statusCode == MIDI_CONTROL_CHANGE) {
// ev.noteNumber = número do controlador (CC#)
// ev.velocity7 = valor do controlador (0–127)
Serial.printf("CC #%d = %d (canal %d)\n",
ev.noteNumber, ev.velocity7, ev.channel0 + 1);
}
}
Passo 3 — Enviar MIDI de Volta¶
Todos os métodos de envio transmitem simultaneamente para todos os transportes ativos:
// NoteOn: canal 1, nota C4 (60), velocidade 100
midiHandler.sendNoteOn(1, 60, 100);
// NoteOff: canal 1, nota C4 (60), velocidade 0
midiHandler.sendNoteOff(1, 60, 0);
// Control Change: canal 1, CC #7 (volume) = 127
midiHandler.sendControlChange(1, 7, 127);
// Program Change: canal 1, programa 0
midiHandler.sendProgramChange(1, 0);
// Pitch Bend: canal 1, valor -8192 a +8191 (0 = centro)
midiHandler.sendPitchBend(1, 4096); // +0.5 semitom
Exemplo — Echo MIDI (loopback)¶
Recebe qualquer NoteOn e reenvia para todos os transportes:
void loop() {
midiHandler.task();
for (const auto& ev : midiHandler.getQueue()) {
if (ev.statusCode == MIDI_NOTE_ON) {
// Reenvia com velocidade dobrada (limitada a 127)
uint8_t vel = min((int)(ev.velocity7 * 2), 127);
midiHandler.sendNoteOn(ev.channel0 + 1, ev.noteNumber, vel);
}
if (ev.statusCode == MIDI_NOTE_OFF) {
midiHandler.sendNoteOff(ev.channel0 + 1, ev.noteNumber, 0);
}
}
}
Passo 4 — Verificar Conexão BLE¶
void loop() {
midiHandler.task();
#if ESP32_HOST_MIDI_HAS_BLE
if (midiHandler.isBleConnected()) {
Serial.println("BLE MIDI conectado!");
}
#endif
}
Conectar via iOS
- Abra GarageBand no iPhone
- Toque em "+" → Música Mixada → Iniciar
- Menu de configurações → Conectar dispositivo MIDI via Bluetooth
- O ESP32 aparecerá como "ESP32 MIDI BLE" (ou o nome configurado)
Passo 5 — Sketch Completo com USB + BLE¶
#include <ESP32_Host_MIDI.h>
// Arduino IDE: Tools > USB Mode → "USB Host"
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("ESP32 Host MIDI — Iniciando...");
MIDIHandlerConfig cfg;
cfg.maxEvents = 20; // capacidade da fila
cfg.chordTimeWindow = 50; // ms para agrupar acordes
midiHandler.begin(cfg);
Serial.println("Pronto! Conecte um teclado USB ou use BLE.");
}
void loop() {
midiHandler.task();
for (const auto& ev : midiHandler.getQueue()) {
char noteBuf[8];
if (ev.statusCode == MIDI_NOTE_ON && ev.velocity7 > 0) {
Serial.printf("[NoteOn] %s vel=%3d ch=%d t=%lums\n",
MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)),
ev.velocity7,
ev.channel0 + 1,
ev.timestamp);
} else if (ev.statusCode == MIDI_NOTE_OFF || ev.velocity7 == 0) {
Serial.printf("[NoteOff] %s ch=%d\n",
MIDIHandler::noteWithOctave(ev.noteNumber, noteBuf, sizeof(noteBuf)),
ev.channel0 + 1);
} else if (ev.statusCode == MIDI_CONTROL_CHANGE) {
Serial.printf("[CC] #%3d = %3d ch=%d\n",
ev.noteNumber, ev.velocity7, ev.channel0 + 1);
} else if (ev.statusCode == MIDI_PITCH_BEND) {
Serial.printf("[Pitch] %d (centro=8192) ch=%d\n",
ev.pitchBend14, ev.channel0 + 1);
}
}
}
Fluxo de Inicialização¶
sequenceDiagram
participant SKETCH as Seu Sketch
participant HANDLER as MIDIHandler
participant USB as USBConnection
participant BLE as BLEConnection
SKETCH->>HANDLER: midiHandler.begin()
HANDLER->>HANDLER: Lê MIDIHandlerConfig
HANDLER->>USB: usbTransport.begin()
Note over USB: Inicia FreeRTOS task\nno Core 0
HANDLER->>BLE: bleTransport.begin(bleName)
Note over BLE: Inicia stack BLE\ne advertising
HANDLER-->>SKETCH: Pronto
loop Cada loop()
SKETCH->>HANDLER: midiHandler.task()
HANDLER->>USB: usb.task()
HANDLER->>BLE: ble.task()
USB-->>HANDLER: Eventos do ring buffer
BLE-->>HANDLER: Eventos do ring buffer
HANDLER-->>SKETCH: getQueue() com eventos
end
Próximos Passos¶
- Configuração → — ajustar
MIDIHandlerConfig, filtros e histórico - Transportes → — adicionar mais transportes (RTP-MIDI, UART, OSC...)
- Funcionalidades → — detecção de acordes, notas ativas