I’ve recently faced an interesting and mysterious issue:
I have to send a huge portion of MIDI data, let’s say 600 notes at a give time, with interval of 1/16 120 bpm from my audio DAW to the controller.
I have a set up when I use 5 DIN MIDI connector and I experience visual latency when I send 60 notes already. I’ve set the internal LED on my Fez Panda 2 to blink when MIDI data is read, so having a metronome beeping and light going off I see that it takes significant (audible) amount of time to read those 60 notes. This is no brainer as:
- the serial speed is 31250 bits per second
- midi note message is 24 bits
- audible latency is ~20 ms let’s say
- 60 notes * 24 bits = 1440 bits
- the serial bandwidth per 20 ms is 31250 / 50 = 625 bits
Hence we see that serial port accepting MIDI is not capable of providing a good performance with non-audible latency.
Therefore I started to look into other solutions like MIDI over USB (1.5 Mbits/s), MIDI over Ethernet (400 kbits/s)… and I’ve read a lot… and I saw a lot of libriaries code… and one thing didn’t give me a peacefull state: everywhere, even in Arduino MIDI over USB library I saw that Serial.Open(31250)
And here goes the real question: is it true, that even though we use higher bandwidth protocols, when it’s down to MIDI we still need to use the 31250 bps rate which is there in MIDI specification for a given MIDI port?
Even though we can’t be sure the DAW, like Ableton Live doesn’t use that 31250 bandwith to send the MIDI out, right?
@ DeathBloom - I am not familiar with MIDI stuff. But, it seems that you are having trouble reading a serial stream to your Panda? If so, it might be worthwhile to show us how you are doing your serial port reading.
Not like I have troubles, since I am able to read the data and analyze it. I use exactly this library for my application:
You can see that the serial port bandwidth is 31250, which is the problem for my particular case as I understand. I am sending Note On/Off messages, which are 24 bits each. I am able to read all of them btw, but the time they are read by is not something which can be satisfying for my needs.
Another question I want to raise here: what is the fastest way to transfer data to Fez Panda 2? What of the connections it has may give me the fastest speed of transferring file/data from PC to the board itself?
@ DeathBloom - the library you posted is reading serial data one byte at a time. This is a slow way of doing it.
I would use a datareceived event handler, read all the data in the internal buffer with one read, and then queue the data for processing by another thread.
that’s true, however, what does it mean DataReceived? The MIDI data is kinda not going to end. It’s flowing constantly. And taking into account the timing constraints I am thinking on whether it’s reasonable to implement any kind of buffer here?
- Midi notes are coming one by one or as a chord (it will be also sent one by one data-wise)
- The audible latency is 10ms
The above means that if you start reading into the buffer, in order to not have an audible latency, you have to process the buffer not later than 10ms after the first byte is received.
@ DeathBloom - the micro frame work is not real-time. there are ways to minimize delay, but no guarantee. I am getting ready to get on a plane, so not enough time to explain.
You may want to research minimization of garbage collection, and the data received event of serial port.
I am not familiar with MIDI as well. However I think that it would be good if you have a kind of decoupling between receiving the MIDI data and making them to tones (hearable). This could be done by writing the data (combined with a timestamp) into a queue as Mike already suggested. I don’t know, but I would suppose, that the data are written to the serial line from the DAW in a time synchronized manner (every packet separated from the next with a fixed time interval). So the timestamp for each set of data in the queue would be always adding this time interval to the timestamp of the last set of data. In one thread you write the data to the queue and in another thread you have a loop which always reads the next set of data from the queue. The queue should be prefilled with received data to some extend (some 100 ms) befor you read the data so that the queue never gets empty. When you read the data from the queue you compare the system time of your Panda with the timestamp of the set of data in the queue. Only when the right time has elapsed, you read the data from the queue and make them hearable. I used a mechanism like this to display ECG Data sampled with a FEZ Board on a PC.