Hello, As an aspiring musician I decided to build my own metronome.
Musical devices (keyboards, synthesizers) were and even are connected via a MIDI interface. MIDI is a current loop, 5v, can be implemented with an Arduino (or ESP8266 running Arduino) with only a resistor (and a levelshifter in case of the ESP8266). MIDI then transmits and receives serial data (1 start bit, 8 data bits and a stop bit) at the lightning speed of 31250 bps (yes: this is 1981 technology). This all takes place over thick cables connected to DIN-5 connectors. As my musical undertakings only happen on electronic devices with MIDI, I thought it would be fun to create a MIDI metronome. That's supposedly only two hours works. I picked the ESP8266 (in a Wemos D1 mini setup) so that I could add a nice little WiFi enabled configuration interface. My metronome emits every beat two types of messages: - a clock message (0xf8) - a touch message (0x99 instrument velocity, where 0x99 means: play a tone on channel 9 which is usually the percussion channel (MIDI has 16 channels)) Then I remembered that there's also MIDI-over-networks which uses multicast UDP. Half an hour hacking and that was also implemented and worked - nice! Because I wanted to keep the regular ESP8266 UART for the ESP SDK debug messages (and my own), I used the SoftwareSerial library to produce a serial bit-stream on one of the other GPIO pins. So then it was all finished I thought: maybe I can make it very precise. Maybe even extremely precise. I doubt a regular human can notice delays or jitter of less than, say, a few milliseconds but that doesn't stop me. To see how well it behaved (it sounded good (for my untrained ears)). I took 4000 samples of 120bpm (beats per minute), calculated average and standard deviation and an allan deviation plot: n: 4065, average: 0.517166, std.dev.: 0.001250 (time is in seconds) This is HORRIBLE. After 4k beats, the timing was a bit more than 17ms off! (on average) I won't even bother show how the Allan plot looks. Luckily that was only a stupid bug and overcomplicated way of tracking when the next beat was due (I did not use a timer but determed how long the main-loop iteration took (more on that later) and compensating for rounding errors). Next version used a regular timer on the ESP8266. With only the DIN-5 connection used (no multicast UDP over WiFi): n: 4357, average: 0.500010, std.dev.: 0.000131 Looks promising! Even the graph looks what I hoped for (see attached 1783.png). But now I switched on the WiFi output, and took a bit more samples (as I fell asleep behind the keyboard): n: 152199, average: 0.520018, std.dev.: 0.040506 Not so good anymore (1783-wifi.png). The problem here is that Arduino has a void loop() { } in which you constantly should do your things but not in a loop: the loop() function is your loop. This allows the Arduino environment to check if the WiFi subsystem needs attention or that e.g. the serial ports need to be read. The developer unfortunately has not control over what happens when outside that 'loop()' function. You need to transmit the beat-messages in the loop-function (can't do (software-)serial nor wifi in the timer interrupt handler) so if you're unlucky, the moment that you 'see' that a flag was set in the timer interrupt function might be sometimes delayed milliseconds. On average that is 0.02 seconds or 20 milliseconds! My next step will be: move to the ESP32 platform. That platform can still do everything the Arduino way, but the ESP32 also exports an RTOS SDK and has 2 processors to spread your processing over. This implementation will take a bit due to circumstances so don't hold your breath. I wrote this just to share my enthusiasm. I expected it to be maybe 2 hours of soldering and coding fun, but with this timing-optimizing this promises fun for at least a week! Maybe after reading this you have any suggestions? Noticed anything silly? Please let me know. Oh for the graphs I used "AllanTools" for Python: https://pypi.org/project/AllanTools/ I used the example at the bottom of that page put replaced mdev (modified allan deviation) by adev (the supposedly regular one) as I only have a vague notion how to interprete the regular one. The sampling of the DIN-5 midi is performed by connecting my device to a "ESI Audiotechnik GmbH ESI MIDIMATE eX" MIDI-to-USB interface and then dumping the messages with a modified 'amidi' from 'alsa-utils' (I added code to output timestamps with milliseconds resolution). The WiFi output is sampled using a raspberry pi 4 with tcpdump (with name resolving disasbled). Regards, Folkert van Heusden
_______________________________________________ time-nuts mailing list -- time-nuts@lists.febo.com -- To unsubscribe send an email to time-nuts-le...@lists.febo.com To unsubscribe, go to and follow the instructions there.