<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">I'm no Arduino coder, but I just had a dig through the code for the Arduino MIDI library and couldn't see any reference to interrupts anywhere.<div class=""><br class=""></div><div class="">...which it seems to me is the root of the problem!</div><div class=""><br class=""></div><div class="">I very much doubt this is a "hard limitation of 5 pin MIDI" as you put it. MIDI was *designed* specifically to work on 8-bit processors running at probably only 4 or 8MHz if you were lucky. However, in order to do that, certain things were assumed. One of those assumptions was that Realtime bytes would be dealt with directly in the Rx interrupt, which is why they're easy to filter, and why it doesn't matter that they can appear anywhere: the assumption is that by the time the parser sees the string of incoming bytes, Realtime will already have been removed.</div><div class=""><br class=""></div><div class="">If a Z80 in 1984 can do it, there's no way it's not possible in 2021 on an Arduino. The problem is only the coding, and in this case, it seems like you're fighting against the Arduino MIDI library. The test with the Teensy basically proves that to me.</div><div class=""><br class=""></div><div class="">Tom<br class=""><div class="">
<div><br class=""></div>
</div>
<div><br class=""><blockquote type="cite" class=""><div class="">On 20 Dec 2021, at 12:46, Benjamin Tremblay via Synth-diy <<a href="mailto:synth-diy@synth-diy.org" class="">synth-diy@synth-diy.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">@Roman<div class="">Yes I believe your theory is correct; it’s an issue with not handling a tangled bunch of messages. But I can’t prove it, and I if it’s true I don’t know what to do about.</div><div class=""><br class=""></div><div class="">The history of this goes back to the middle of the summer. </div><div class="">I was working on MIDI interface for a Roland CR-5000 and experienced these problems while trying to generate the 24ppq clock.</div><div class="">This is when I first experienced this issue while testing using the DR-202.</div><div class="">After spending many hours twiddling the code, I decided I wanted to try this with a Teensy 4, so I could see if it was a speed issue, and also so I could get good logging over the USB port.</div><div class="">The issue was exactly the same on the Teensy. I was surprised it was not an Arduino speed issue at all.</div><div class="">The logs showed the code I was using to measure the time between MIDI clock events was varying wildly when I played a house music or latin groove on the 202. </div><div class="">As if the MIDI parser was choking on nearly-simultaneous events.</div><div class="">My code’s pretty simple, it looks like a boilerplate Arduino MIDI Library code example using MIDI clock, start/stop/resume.</div><div class="">I simply measure microseconds and generate the clock pulses when micros() exceeds the estimated clock pulse duration.</div><div class=""><br class=""></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">#define CLOCK_LENGTH 3333 // microseconds</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""><br class=""></span></font></div><div class=""><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">void setupMidi() {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> if (USE_SERIAL) {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> Serial.println("setupMidi");</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> }</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.begin(RECEIVE_CHANNEL);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.setHandleNoteOn(handleNoteOnMidi);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.setHandleClock(myClock);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.setHandleStart(onClockStart);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.setHandleContinue(onClockStart);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.setHandleStop(onClockStop);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> if (USE_SERIAL) {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> Serial.println("setupMidi DONE");</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> }</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">}</span></font></div></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""><br class=""></span></font></div><div class=""><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">void myClock() {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> if (CLOCK_RUNNING) {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> digitalWrite(CLOCK_OUT, LOW);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> clockFuture = micros(); // *</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> }</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">}</span></font></div></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""><br class=""></span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">// *In previous iterations I tired to recalculate CLOCK_LENGTH by averaging, etc. It simply won’t work if its’ far from 3000µs.</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""><br class=""></span></font></div><div class=""><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class="">void loop() {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> MIDI.read();</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> if (CLOCK_RUNNING) {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> if (clockFuture > 0 && (micros() - clockFuture) > CLOCK_LENGTH) {</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> digitalWrite(CLOCK_OUT, HIGH);</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> clockFuture = 0;</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> }</span></font></div><div class=""><font face="Courier New" class=""><span style="font-style: normal;" class=""> } … etc</span></font></div></div><div class=""><br class=""></div><div class="">// ** If I subtract micros() from clockFuture, this number goes crazy when I play a thick loop on the 202.</div><div class=""><br class=""></div><div class="">In spite of my avoidance of delayMicroseconds(), this code is sensitive to timing because CLOCK_LENGTH (is a constant here, but I have tried to make it dynamic in other builds) is inflexible.</div><div class=""><br class=""></div><div class="">I have seen some GitHub projects that use interrupts for the MIDI clock and time calculations. I have never written my own interrupt code but would gladly go that way if I was certain it could fix this problem. But, it seems like I am hitting a hard limitation of 5 pin MIDI… The folks who write fast code with MIDI clock seem to skip ahead to using USB for real-time messages, etc.</div><div class=""><br class=""></div><div class="">When I was playing with the awesome <a href="http://cheerful.nl/" class="">cheerful.nl</a> OPL2 Audio Board, the author provided some lean MIDI parsing code and skipped the MIDI library. (Especially a no-op for sysex.) So I forked that and tried a lean implementation. Same problem! Lag when the 202 go busy with CC messages and snare rolls.</div><div class=""><br class=""></div><div class="">So I reverted my code back to Arduino MIDI Library, cleaned up the source, removed dead code, and tested it using everything I learned. It runs OK when I use a dumb drum machine like an SR-16. It chokes on the floofy beats of 1998 in my DR-202. </div><div class=""><br class=""></div><div class="">Finally after months, I ported the code back to Arduino Mega and runs virtually the same as on the Teensy 4.</div><div class=""><br class=""></div><div class="">What I don’t know is, when the 202 gets busy, how can I ditch all the MIDI events I don’t care about without waiting a long time to get the ones I do care about? As bad as the DR-202’s MIDI implementation may be, I have to assume there are many boxes (including a Yamaha QY-22 I was also testing) which send out these swooshing sweeping resonant filter CC events and sysex param tweaks in their drum-and-bass patterns.</div><div class=""><br class=""></div><div class="">I am assuming that someone, somewhere has mitigated this problem. I want to know how she or he did it.</div><div class=""><br class=""></div><div class="">Ben</div><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 20, 2021, at 5:30 AM, Roman Sowa <<a href="mailto:modular@go2.pl" class="">modular@go2.pl</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">When you say "complex pattern" I see a lot of MIDI messages, and then the clock messages like to be trapped between bytes of single note message. So maybe, just maybe your Arduino code, or library you've used are not capable to see a MIDI clock message trapped inside a note message, or simply get overloaded.<br class=""><br class="">Is it Arduino doing or KPR itself is best to check on a scope with trigger set to timeout on decoded clock byte.<br class=""><br class="">Roman<br class=""><br class="">W dniu 2021-12-18 o 21:12, Benjamin Tremblay via Synth-diy pisze:<br class=""><blockquote type="cite" class="">Interesting topic!<br class="">I have been wanting to write some code like this for a KPR-77. Goal would be MIDI clock in, TTL-ish clock out. 24ppq>48ppq.<br class="">The first challenge is converting 24ppq computer signals to 24 HIGH/LOW pin state transitions per quarter note.<br class="">One thing that discouraged me was MIDI clock coming from my Boss DR-202. When I play a complex pattern on that thing, I start losing clock steps. I could not figure out why, so I gave up on multiplying the clock.<br class="">If I use a plain vanilla drum machine (as opposed to a groove box), it seems to work okay.<br class="">I wrote this code for Arduino Mega, and then tried it with Teensy, but either way it has the same problems.<br class="">So, two different problems.<br class="">1) MIDI clock dropping out on groove boxes.<br class="">2) I wish I understood the theory of clock multipliers. I have seen code that measures the period between clock pulses and dead reckons the double-time pulse as an average of the recent periods. But why? Why can’t I just fire another extra HIGH-LOW pulse whenever I get a MIDI clock event? Why does timing of the extra ticks matter? I’m assuming 48 PPQ divides the clock down to individual sequencer steps on the KPR-77. As long as the divided clock is coming in on the beat, what does it matter if some of the synthetic pulses are a little off? (They’re just shadows of the main tempo clock). It’s not like the KPR-77 is inferring something or trying to calculate BPM from the external clock… So… Anyway I just wish I knew what I was aiming for, and then maybe I could hit the target.<br class=""></blockquote></div></div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">Synth-diy mailing list<br class=""><a href="mailto:Synth-diy@synth-diy.org" class="">Synth-diy@synth-diy.org</a><br class="">http://synth-diy.org/mailman/listinfo/synth-diy<br class="">Selling or trading? Use marketplace@synth-diy.org<br class=""></div></blockquote></div><br class=""></div></body></html>