MIDI-Monitor-OLED
This example shows all incoming and outgoing MIDI messages on an SSD1306 OLED display. This can be handy for debugging purposes when you don't have access to the Serial Monitor.
- Boards: 🛈
- AVR, Nano Every, Due, Nano 33 IoT, Nano 33 BLE, UNO R4, Teensy 3.x, ESP32, ESP8266
Connections
- 5: Push button (to ground)
- MOSI: OLED Data/D1 (SPI)
- SCK: OLED Clock/D0 (SPI)
- 8: OLED Reset
- 9: OLED Data/Command
- 10: OLED Cable Select
Behavior
- When sending MIDI messages to the Arduino using the USB interface, these messages are printed on the OLED display, prefixed by a right arrow (→).
- If any MIDI messages are sent by Control Surface (e.g. by pressing the push button), these messages are printed on the OLED display, prefixed by a left arrow (←).
Explanation
The code below defines the OLEDDebugMIDI_Output class, which implements the MIDI_Sink and MIDI_Sender interfaces. This means that it can accept MIDI messages coming from MIDI_Pipes, and it provides all of the usual functions for sending MIDI messages.
The MIDI over USB interface (midi) will be used as the primary MIDI interface (as in the other Control Surface examples).
Two instances of our OLEDDebugMIDI_Output class are created: one for printing messages that are received by the primary MIDI interface, and one for printing messages that are sent by Control Surface.
The MIDI interfaces and Control Surface itself are connected appropriately using some pipes.

- See also
- MIDI_Pipes-Routing.ino
-
Debug-MIDI-Interface.ino
-
MIDI Tutorial: Routing MIDI messages
-
MIDI-Monitor.ino
Written by PieterP, 2024-01-05
https://github.com/tttapa/Control-Surface
#include <Adafruit_SSD1306.h>
};
if (!disp.begin())
disp.setTextSize(1);
disp.cp437();
disp.clearDisplay();
disp.display();
}
auto buf = disp.getBuffer();
}
"Note Off", "Note On", "Key Pres", "Ctrl Ch",
"Prog Ch", "Ch Pres", "Pitch Bend"};
public:
private:
return;
if (prefix != nullptr)
disp << prefix << ' ';
disp <<
msg.getCable().getOneBased() <<
':';
disp <<
msg.getChannel().getOneBased() <<
' ';
if (
msg.getMessageType() ==
msg.PitchBend)
disp <<
' ' << hex <<
msg.getData14bit() <<
'h' <<
dec;
else if (
msg.hasTwoDataBytes())
disp <<
' ' << hex <<
msg.getData1() <<
'h' <<
' ' <<
msg.getData2()
else
<<
msg.getData1() <<
'h' <<
dec;
disp.display();
}
if (prefix != nullptr)
disp << prefix << ' ';
disp <<
msg.getCable().getOneBased() <<
' ';
disp <<
msg.getMessageType() <<
hex;
if (
msg.getNumberOfDataBytes() >= 1)
disp <<
' ' <<
msg.getData1() <<
'h';
if (
msg.getNumberOfDataBytes() >= 2)
disp <<
' ' <<
msg.getData2() <<
'h';
disp.display();
}
if (prefix != nullptr)
disp << prefix << ' ';
disp <<
msg.getCable().getOneBased() <<
' ';
disp <<
F(
"Sys Ex [") <<
msg.length << (
msg.isLastChunk() ?
"]" :
"+]");
disp.println();
}
disp.display();
}
if (prefix != nullptr)
disp << prefix << ' ';
disp <<
msg.getCable().getOneBased() <<
' ';
disp <<
msg.getMessageType();
disp.display();
}
void sendNowImpl() {}
const char *prefix;
};
}
void loop() {
}
The main header file that includes all Control-Surface header files.
Control_Surface_ & Control_Surface
A predefined instance of the Control Surface to use in the Arduino sketches.
void begin()
Initialize the Control_Surface.
void loop()
Update all MIDI elements, send MIDI events and read MIDI input.
void setAsDefault()
Set this MIDI interface as the default interface.
Statically polymorphic template for classes that send MIDI messages.
void send(ChannelMessage message)
Send a MIDI Channel Voice message.
Receives MIDI messages from a MIDI pipe.
virtual void sinkMIDIfromPipe(ChannelMessage)=0
Accept an incoming MIDI Channel message.
A class for MIDI interfaces sending MIDI messages over a USB MIDI connection.
Array< T, N > copyAs(const Array< U, N > &src)
Copy an Array to an Array of a different type.
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Print & hex(Print &printer)
Print & uppercase(Print &printer)
Print & dec(Print &printer)
static constexpr Frequency SPI_MAX_SPEED
Class that produces multiple MIDI_Pipes.