First MIDI Input Test:
Attempted to set up a sketch that would read MIDI bytes and display them on the computer via the Serial Monitor. The problem encountered here was that the display in the Serial Monitor was garbage when I expected to see a single repeating byte for the MIDI Clock being sent from the Elektron Machinedrum. I think this was a conflict with the MIDI Ports using the Arduino’s Serial pins. Those same Serial lines are used to communicate up the USB to the computer. And since I was running the Serial port at 31250 baud as required by MIDI, I couldn’t get reliable USB streaming since the same baud rate was not selectable in the Serial Monitor.
Decided to switch to MIDI Out Test instead.
Connected MIDI Out to Machinedrum and programmed Arduino to transmit the MIDI note corresponding to Track 1 (Bass Drum) on the Machinedrum. I transmitted a Note On followed by a 1 second delay. I then sent a Note Off followed by a 2 second delay. When I uploaded and ran the program, it successfully triggered the BD on Machinedrum once every three seconds. There was no visual or audible indication that the Note Off (actually a Note On with velocity 0×00), so I removed the Note Off and the 2 second delay from the program and ran it again. Now I heard the BD once every second as expected. The Machinedrum evidently does not need Note Off commands to be sent after Note Ons.
MIDI Output Test successful, return to MIDI Input Test.
During my MIDI Out experiment, I realized that the RUN/PROG switch on the MIDI Shield was in the PROG position. I’d realized it had been there since the start of the first MIDI Input test instead of being in the RUN position. Having realized that I cannot upload firmware while the switch is set to RUN, I figured the switch had something to do with Serial communication. Thinking that this may have been the source of the first failed test, I re-ran that program remembering to set the switch to RUN after the upload. Same results–gibberish. Suspect baud mis-match again.
Change of tactics: now listen for a single MIDI message and light L when received.
I chose to listen to the MIDI Clock pulse since this was going to be the most important message for me to receive. I configured the program to continually perform Serial Reads followed by an if-statement comparing the received byte to the MIDI Clock value (0xF8). If the match was found, the if-statement would execute which involved an analogRead of Knob 1 on the MIDI Shield, switching Pin 13 to high, a delay of the amount read from Knob 1 divided by 10, finished off with writing Pin 13 low again. Repeat.
I loaded the firmware and L turned on rather than blinking. This was expected as the Machinedrum tempo was set to 126BPM–sending 24ppq at that tempo, I expected persistence of vision to make it look like the LED was lit constantly. I also realized that Knob 1 was all the way down which, according to last night’s experiments, meant that the analogRead value was actually 1023 rather than 0. So the delay was lasting long enough so that there was very little time when the LED was off.
I proceeded to turn “up” Knob 1 and, understandably, the LED turned off. At this setting, the delay value was 0 so the LED wasn’t on long enough to be seen (in fact, the pulse from the Arduino may have been too short for the LED to even illuminate). But as I slowly turned up Knob 1, the LED turned back on, dimly at first, then brighter. I then turned down the tempo of the Machinedrum to its minimum: 30 BPM. At this point, I could now clearly see the LED blinking, especially with slight tweaks to Knob 1 to optimized the on-time of the LED. I could see the blinking increase to the point where the blinking became imperceptible as I turned up the tempo on the Machinedrum.
MIDI Input test a success. All functions of the MIDI Shield have now been verified.
For shits, I decided to “refine” my LED blink code for I did not like the fact that the program was stalled on the delay command between the high and low writes to the Pin 13. My concern was that, at higher delay settings (turning Knob 1 “up”), the program was actually missing incoming MIDI Clock pulses–I figured it was better to fix this behavior now and be mindful of it moving forward rather than developing a bad programming habit.
So I removed the delay statement and split the high and low writes into two separate if-statements. The first if-statement remained unchanged to check for 0xF8, but the executable part now included the capturing of a timestamp from the millis() function and setting an led_state variable to 1. The command to take Pin 13 low was now in a separate if-statement that first checked if the specified delay time had elapsed by comparing the difference of the current millis() reading to the time_stamp value. This was && with a statement that checked if led_state was 1. If both were true, then Pin 13 was written low and (in the process of writing this) the led_state was set back to 0. I configured it this way so that the digital writes and analog reads would only occur when a Clock was received or when the delay time had elapsed. Without the use of the led_state clause, the Arduino would continually write Pin 13 low once the delay was exceeded which I feared could waste a cycle that should be used for listening to the Serial port.
When I first ran this, it appeared to work like my first version. However, the thing stopped working after I did some knob tweaking. I reset the board and it worked again for a little while until I tweaked the tempo on the Machinedrum. It turns out that none of my tweaks was the culprit–I had actually used an int for the time_stamp variable and it was overflowing after a few minutes. I then remembered that the millis() function returns a long–once I made time_stamp a long as well, it worked perfectly (and by perfect, I mean it will work properly for about 50 days until the long overflows. But playing music for 50 days straight is unlikely for me…I’ll be power-cycling the thing some time before that).
I was also a bit miffed with the performance when I increased the tempo on the Machinedrum. I expected the blinking rate to increase and slowly become imperceptible. Instead, I started seeing a pattern in brightness. The LED would get bright and then dim, then bright again. I’m afraid that what I’m seeing is sampling error–that the operating rate of the Arduino is not an even multiple of the incoming MIDI Clock pulses. This is sort of like a moire pattern where the print resolution and scan resolution don’t match.
This has me concerned for two reasons. Well, three actualy:
The first is that I don’t know at which stage this pattern is appearing. Is this a result of incoming sampling error, or is this more on the output stage of the Arduino?
If it is on the input side, then I’m concerned my device will be jittery beyond use. I know there are plenty of MIDI projects out there based on Arduino, but I don’t know how many of them attempt to handle MIDI Clock. Perhaps the Arduino can only process the “thin” data of notes and CCs. Well, that’s bullshit–a CC should be able to flood the MIDI pipe with more data than this clock pulse, and nobody has complained about crappy CC response that I know of.
If it’s on the output side, then I may not be able to regenerate the clock for the Elektron boxes reliably–same for the 5V DIN Sync. My downstream items may jitter too much to be useable.
It would therefore be prudent to test this jitter right now, but I believe a test would be inconclusive at this time. I think this will only be testable over time because, as the size of my firmware grows, the cycle rate of my app will decrease, potentially increasing the sampling error/moire or making the output too coarse to be accurate.
If the above occurs, I’ll have no choice but to result to a multi-processor configuration where MIDI functions are split onto different boards. This could potentially reduce the load on the system to the point where both boards could reliably receive and output data–the trick would then be to synchronize their timings either by I2C or by some raw data pins (data pin interconnection might actually be more accurate than I2C now that I think about it). I’m really hoping it doesn’t come to that. This Arduino board is supposed to be running at 16Mhz. My first PC was 25Mhz, and I think my mom’s was 16Mhz! Those machines were more than capable of handing MIDI communication. Shit, even older, slower Ataris could do it.
And let’s do the math. 16Mhz vs 31,250 baud MIDI communication…OH SHIT! That means there are only 512 CPU cycles for each byte that can be transmitted/received on the MIDI ports. I didn’t think it would be that low! Now while it’s true I’ll never be trying to send 31,250 bytes per second over the MIDI Port, it does suggest that I could experience some more sampling error once my program requires more than 512 CPU cycles to complete the entire loop() procedure. If 31,250 bytes per second were being thrown at the Arduino, that would require the input to be buffered since two bytes may arrive within the time the loop() completes one cycle. Those two bytes then loose their timing significance. Not such a problem with normal MIDI messages which can be between 2-3 bytes long–buffering 3 bytes would still be OK since the bytes need to be processed in groups of 3. But this is a problem with MIDI Clock where the timing of its arrival is the significant datapoint.
This also suggest that, if I cannot process those three bytes within 1,536 CPU cycles, then there will be potential for CPU overload and dropped bytes. Again, all of this assumes 31,250 bytes are being sent continuously to the Arduino which in practical terms is not as likely (even when tweaking CCs). But the possibility is there–if a bunch of MIDI data arrives at once, the Serial buffer will catch it all, but the Arduino will still have to process them at the only rate it can. This will further distort the timing of incoming messages.
From what I know, the Arduino does not support any sort of threading as this is an advanced programming feature (it’s worth noting that, when I say “Arduino”, I’m talking about the whole development platform including the bootloader and the IDE–it’s possible that I could find threading in AVR Studio, but I would also loose all the convenience of the Arduino libraries [or could I still link them?]).
I may therefore have to build my own sort of “time-serving” code where I can keep polling the inputs and writing to the outputs frequently. I’ll need to investigate interrupts as these might be the trick for triggering read/writes at constant intervals regardless of what the program is trying to do at that moment.
Leave Your Response