What limitations did you encounter ? Can you post the UNO code ?
On a leonardo, the Serial port has native USB, so you can actually turn it into a USB midi device. For receiving Midi from your digital piano, you can connect to the hwSerial 1 (Serial1) on pins 0 & 1 instead of any swSerial you are using on the UNO.
This is of course the limitation that you may run into on an UNO, but before that causes issues you will need to play an insane amount of notes at the default 115200 baudrate that is supported by hairless, don;t use 9600.
But anyway, if you switch to the Leonardo, you should use "MIDIUSB.h" and you can use this as a guide on how the functions are implemented. (again you don't need hairless anymore)
#include "MIDIUSB.h"
#define LED 3 // that pin is PWM capable and has no extra function
#define POT A2
#define CHANNEL (7 - 1) // midi channel 6 equals 5 in this system.
// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, (uint8_t) (0x90 | channel), pitch, velocity};
MidiUSB.sendMIDI(noteOn);
MidiUSB.flush();
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, (uint8_t) (0x80B | channel), pitch, velocity};
MidiUSB.sendMIDI(noteOff);
MidiUSB.flush();
}
void setup() {
pinMode(LED, OUTPUT);
analogWrite(LED, 120);
delay(1000);
analogWrite(LED, 0);
}
// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, (uint8_t) (0xB0 | channel), control, value};
MidiUSB.sendMIDI(event);
MidiUSB.flush();
}
void loop() {
static uint32_t moment = millis();
//static bool noteon = true;
static uint8_t volume = 0;
uint8_t analog = analogRead(POT) >> 3;
if ((volume != analog) && (millis() - moment > 20)) {
moment = millis();
volume = analog;
controlChange(CHANNEL, 7, volume);
}
/*if (millis() - moment > 2000) {
moment = millis();
if (noteon) noteOn(0, 48, 100); // pin C2
else noteOff(0, 48, 64);
noteon = !noteon;
}*/
midiEventPacket_t rx = MidiUSB.read();
while (rx.header != 0) {
uint8_t type = rx.byte1 >> 4;
uint8_t channel = rx.byte1 & 0xF;
uint8_t value1 = rx.byte2;
uint8_t value2 = rx.byte3;
if (type == 0x9) analogWrite(LED, value2 * 2);
if (type == 0x8) analogWrite(LED, 0);
rx = MidiUSB.read();
}
//controlChange(0, 10, 65); // Set the value of controller 10 on channel 0 to 65
}
For the incoming signals on Serial1 you can create a midi instance like this
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midi);
and then all you need to do is combine them
I agree that swSerial is not the best for receiving and transmitting Midi, but it should not be an issue when you are playing notes on a piano, more so when receiving and forwarding CC messages and midi sync.