Midi in - midi out

This code read a MIDI IN (DIN 5) keyboard and send it right to the MIDI OUT ... eventually I will do some changes to the Midi velocity data. The issue I have is that the response of the code generates data error unless I add some delay(nn) ; but this create another issue of latency. How can I make the code works more effectively.

Thanks,
PRPROG

//Code

byte commandByte;
byte noteByte;
byte velocityByte;

int MIDI_MSG = 0;
int MIDIOUT = 0;

void setup() {
// put your setup code here, to run once:
Serial.begin(31250);

pinMode(13,OUTPUT);
digitalWrite(13,LOW);
}

void loop() {

if(Serial.available() > 0 ) {
digitalWrite(13,HIGH);//turn on led

MIDI_MSG = Serial.read() ;

//parse MIDI IN message
commandByte= (MIDI_MSG >> 16) & 0xFF ;
noteByte= (MIDI_MSG >> 8) & 0xFF ;
velocityByte=MIDI_MSG & 0xFF;
}

//send MIDI
MIDI_MSG = (commandByte << 16) | (noteByte << 8) | velocityByte;

Serial.write(MIDI_MSG);
digitalWrite(13,LOW);//turn led off
MIDI_MSG = 0;
delay(30);
}

Welcome, this should be a fun protect for you. I and many others cannot or will not read your code as posted. Please use code tags. They are explained in the forum guidelines.

What Arduino board are you using?

a7

Hi , @alto777 , using Arduino UNO

OK, and did you find or borrow or write this code?

Which you might apply the IDE Auto Format tool to which, and the use the IDE Copy for Forum tool and paste it in your next post to this thread.

Then looking closer.

a7

You cannot parse MIDI like this: you need to inspect the most significant bit of each byte to keep track of the start of a message, you need to have a simple state machine to count data bytes and to support “running status”, and you need to support messages of different lengths (not all of them are three bytes long, some don't even have a fixed length at all). If you look at the MIDI standard, you'll find a flow chart explaining the process. You can also find existing MIDI parsers online that you could use for inspiration, see e.g. Control-Surface/src/MIDI_Parsers/SerialMIDI_Parser.hpp at main · tttapa/Control-Surface · GitHub and Control-Surface/src/MIDI_Parsers/SerialMIDI_Parser.cpp at main · tttapa/Control-Surface · GitHub.

@alto777 , I check a couple of examples , check on the internet on how to parse the MIDI message and work it out..

byte commandByte;
byte noteByte;
byte velocityByte;

int MIDI_MSG = 0;
int MIDIOUT = 0;

void setup() {
  // put your setup code here, to run once:
Serial.begin(31250);

pinMode(13,OUTPUT);
digitalWrite(13,LOW);
}


void loop() {
 
   if(Serial.available() > 0 ) {
   digitalWrite(13,HIGH);//turn on led

   MIDI_MSG = Serial.read() ;
   

  //parse MIDI IN message
    commandByte=  (MIDI_MSG >> 16) & 0xFF ;
    noteByte= (MIDI_MSG >> 8) & 0xFF ;
    velocityByte=MIDI_MSG & 0xFF;
    }
  

  //send MIDI
  MIDI_MSG = (commandByte << 16) | (noteByte << 8) | velocityByte;
  
  Serial.write(MIDI_MSG);
  digitalWrite(13,LOW);//turn led off
  MIDI_MSG = 0;
  delay(30);
}

Thanks @PieterP for the details.
Good point on specific MIDI message... I will take note and considered how to read ONLY Midi Note ON and Note Off messages. Will check the MIDI parsers links provided. Thanks

This reads only one byte, it doesn't read the whole message. So with only one byte the code that follows is a nonsense, because it is acting like it has read the whole message and not just a byte.

You have to build up the message one byte at a time, waiting if necessary for each byte to arrive and not just assuming all the bytes of a MIDI message will arrive at once.

The loop function runs much faster than the note come in.

Hi @Grumpy_Mike , thanks a lot for the reply. Actually, the serial.read() capture the full MIDI message. My code is somehow based on this short code that works perfectly. It reads the MIDI data and pass it thru to the MIDI OUT.

What I did is to parse the MIDI message into its parts (which I now start to understand that MIDI messages are not all the same length or same parts....)

This is the original code:

int midiMsg = 0 ;

void setup() {
  // put your setup code here, to run once:
 // Initialize the serial port for MIDI
  Serial.begin(32500) ;
}

void loop() {
  // put your main code here, to run repeatedly:
 if (Serial.available() > 0) {
    midiMsg = Serial.read() ;
    Serial.write(midiMsg) ;
  }
}

As you see, that wasn't the best way forward.

I see you sending ~33 characters every second with no regard for there actually being new MIDI traffic to pass on. Just sending the same thing until a new character is arrived.

So logically it makes no sense.

Also int type on the UNO is 16 bits, so those 16 bit shifts are off to nowhere. Just nonsense.

It amounts to your latest posted example, except notice that the example sends each received character out only once.

One character comes in, you send the same one out. No characters, nothing comes out.

And those are not examined or modified. You might as well have used a wire.

If you want to get a MIDI message and modify it and send it along, that is what you'll have to do. Either take in an entire valid MIDI message, then change it and send it out, or get clever if it is something that needs as little delay in doing that as possible. You could be sending out characters forming the new MIDI message whilst still receiving the rest of the message going through.

As pointed out, the MIDI messages will need several characters to be read() and examined.

a7

@alto777 , critical points to take into consideration , thanks. On the last code I post ,it reads the FULL MIDI message , as you point out, into a 16 bit variable. I don't understand , then , how it is working so well. It reads the complete MIDI message (3 bytes of 8 bits , thats 24 bits.....) and send it to the MIDI OUT , but it work. No data is lost. ... how?

No it does not.

This

if (Serial.available() > 0) {
    midiMsg = Serial.read() ;
    Serial.write(midiMsg) ;
  }

gets one character when available, and sends that one character on to the output. Without examining it, without criticizing it, without caring what it is.

If these are any kind of messages, they are formed from multiple characters, and survive because you just pass every single one along as it arrives, one character in, one character out.

Because you are using the serial port, I cannot suggest you print that "message" midiMsg from inside the if statement - but I guarantee that it is a single character each time.

HTH

a7

No it doesn't.
Any appearance of it works is just a fluke.
Transferring an input byte to an output byte might appear like it works, but you are deluding yourself.

Still, what do I know? I have only written and got published, a book on using MIDI on the Arduino.

Arduino Audio

Thanks @gilshultz , @alto777, @PieterP and @Grumpy_Mike for your replies and comments. I will check out ALL the reference given. Thanks again!!!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.