#include <M5Unified.h>
#include "M5_SAM2695.h"
M5_SAM2695 midi;
static const uint8_t MELODY_CHANNEL = 0;
static const uint8_t DRUM_CHANNEL = 9;
void showStatus(const char* stage, const char* detail = nullptr) {
M5.Display.fillScreen(TFT_BLACK);
M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);
M5.Display.setTextSize(2);
M5.Display.setCursor(8, 8);
M5.Display.println("Unit MIDI Test");
M5.Display.drawFastHLine(8, 32, M5.Display.width() - 16, TFT_DARKGREY);
M5.Display.setCursor(8, 48);
M5.Display.setTextColor(TFT_CYAN, TFT_BLACK);
M5.Display.println(stage);
if (detail != nullptr) {
M5.Display.setCursor(8, 82);
M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);
M5.Display.println(detail);
}
}
void playNote(uint8_t channel, uint8_t pitch, uint8_t velocity,
uint16_t durationMs) {
if (pitch == REST) {
delay(durationMs);
return;
}
midi.setNoteOn(channel, pitch, velocity);
delay(durationMs);
midi.setNoteOff(channel, pitch, 0);
}
void playScale() {
const uint8_t scale[] = {NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4,
NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5};
for (uint8_t i = 0; i < sizeof(scale); ++i) {
playNote(MELODY_CHANNEL, scale[i], 100, 180);
}
}
void playChord() {
midi.setNoteOn(MELODY_CHANNEL, NOTE_C4, 90);
midi.setNoteOn(MELODY_CHANNEL, NOTE_E4, 90);
midi.setNoteOn(MELODY_CHANNEL, NOTE_G4, 90);
delay(600);
midi.setNoteOff(MELODY_CHANNEL, NOTE_C4, 0);
midi.setNoteOff(MELODY_CHANNEL, NOTE_E4, 0);
midi.setNoteOff(MELODY_CHANNEL, NOTE_G4, 0);
}
void playDrumPattern() {
midi.setInstrument(0, DRUM_CHANNEL, SynthDrum);
for (uint8_t beat = 0; beat < 8; ++beat) {
midi.setNoteOn(DRUM_CHANNEL, 36, 120);
midi.setNoteOn(DRUM_CHANNEL, 42, 90);
if ((beat & 0x03) == 2) {
midi.setNoteOn(DRUM_CHANNEL, 38, 110);
}
delay(180);
}
midi.setAllNotesOff(DRUM_CHANNEL);
}
void configureVoice() {
midi.setInstrument(0, MELODY_CHANNEL, ElGrdPiano_3);
midi.setVolume(MELODY_CHANNEL, 105);
midi.setPan(MELODY_CHANNEL, 64);
midi.setReverb(MELODY_CHANNEL, 1, 55, 20);
midi.setChorus(MELODY_CHANNEL, 1, 35, 18, 12);
midi.setEqualizer(MELODY_CHANNEL,
64,
60,
68,
64,
45,
55,
70,
80);
midi.setTuning(MELODY_CHANNEL, 64, 64);
midi.setVibrate(MELODY_CHANNEL, 45, 30, 10);
midi.setTvf(MELODY_CHANNEL, 90, 35);
midi.setEnvelope(MELODY_CHANNEL, 20, 75, 45);
midi.setPitchBendRange(MELODY_CHANNEL, 2);
midi.setMasterVolume(110);
}
void demonstrateVoiceShape() {
midi.setInstrument(0, MELODY_CHANNEL, Lead2Sawtooth);
midi.setVolume(MELODY_CHANNEL, 110);
midi.setPan(MELODY_CHANNEL, 64);
midi.setTvf(MELODY_CHANNEL, 48, 100);
midi.setEnvelope(MELODY_CHANNEL, 70, 45, 90);
midi.setVibrate(MELODY_CHANNEL, 80, 85, 8);
playNote(MELODY_CHANNEL, NOTE_C4, 105, 850);
playNote(MELODY_CHANNEL, NOTE_G4, 105, 850);
midi.setTvf(MELODY_CHANNEL, 115, 35);
midi.setEnvelope(MELODY_CHANNEL, 10, 85, 35);
playNote(MELODY_CHANNEL, NOTE_C5, 105, 850);
}
void demonstrateEffects() {
midi.setInstrument(0, MELODY_CHANNEL, StringEnsemble1);
midi.setVolume(MELODY_CHANNEL, 115);
midi.setReverb(MELODY_CHANNEL, 1, 110, 70);
midi.setChorus(MELODY_CHANNEL, 1, 100, 70, 50);
midi.setEqualizer(MELODY_CHANNEL, 95, 45, 75, 90, 35, 55, 80, 100);
midi.setNoteOn(MELODY_CHANNEL, NOTE_C4, 95);
midi.setNoteOn(MELODY_CHANNEL, NOTE_E4, 95);
midi.setNoteOn(MELODY_CHANNEL, NOTE_G4, 95);
delay(900);
midi.setNoteOff(MELODY_CHANNEL, NOTE_C4, 0);
midi.setNoteOff(MELODY_CHANNEL, NOTE_E4, 0);
midi.setNoteOff(MELODY_CHANNEL, NOTE_G4, 0);
delay(1200);
midi.setTuning(MELODY_CHANNEL, 64, 72);
playNote(MELODY_CHANNEL, NOTE_A4, 105, 650);
midi.setTuning(MELODY_CHANNEL, 64, 64);
}
void demonstratePitchBend() {
midi.setNoteOn(MELODY_CHANNEL, NOTE_C4, 110);
midi.setPitchBend(MELODY_CHANNEL, 0);
delay(250);
midi.setPitchBend(MELODY_CHANNEL, 512);
delay(250);
midi.setPitchBend(MELODY_CHANNEL, 1023);
delay(250);
midi.setPitchBend(MELODY_CHANNEL, 512);
midi.setNoteOff(MELODY_CHANNEL, NOTE_C4, 0);
}
void demonstrateModWheel() {
midi.setModWheel(MELODY_CHANNEL,
20,
30,
40,
50,
25,
35,
45);
}
void setup() {
M5.begin();
M5.Display.setTextWrap(true);
showStatus("Starting", "MIDI 31250 baud");
Serial.begin(115200);
Serial.println("Unit MIDI comprehensive example");
midi.begin(&Serial2, MIDI_BAUD, 18, 17);
}
void loop() {
Serial.printf("\n--- Unit MIDI demo cycle ---\n");
showStatus("Reset", "Reapply voice settings");
midi.reset();
delay(100);
configureVoice();
demonstrateModWheel();
showStatus("Scale + chord", "Channel 1");
Serial.println("Scale and chord");
playScale();
playChord();
showStatus("Pitch bend", "C4: low -> high");
Serial.println("Pitch bend");
demonstratePitchBend();
showStatus("Voice shaping", "Filter/envelope/vibrato");
Serial.println("Filter, envelope and vibrato");
demonstrateVoiceShape();
showStatus("Effects", "Reverb/chorus/EQ");
Serial.println("Reverb, chorus, equalizer and tuning");
demonstrateEffects();
showStatus("Drums", "Channel 10");
Serial.println("Drums");
midi.setAllInstrumentDrums();
playDrumPattern();
midi.setAllNotesOff(MELODY_CHANNEL);
midi.setAllNotesOff(DRUM_CHANNEL);
showStatus("Complete", "Next cycle in 1.5 s");
delay(1500);
}