[time-nuts] Re: metronome

Keelan Lightfoot keelanlightfoot at gmail.com
Sun Jul 4 01:36:17 UTC 2021


At the risk of sounding like an old fart: one of the ye olde fashioned 18 pin PIC microcontrollers can easily do what you’re trying to do without having to resort to a full blown RTOS. 

For the longest time my “logic analyzer” was a PIC with a bit banged 57600 baud serial port. To get the sample rate up to the maximum 46,080 samples per second possible with the 57600 baud port, I ended up writing an unrolled input read/serial write loop that interleaved sampling the digital input every 22us with writing to the serial port every 17us. My goal was minimum buffering, so some of the bits in the transmitted byte were sampled while start bit and earlier bits were being transmitted. 

Sometimes it’s nice to be able to turn of interrupts and get the CPU all to yourself! 

- Keelan

> On Jul 3, 2021, at 1:01 PM, folkert <folkert at vanheusden.com> wrote:
> 
> 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
> <1783.png>
> <1783-wifi.png>
> _______________________________________________
> time-nuts mailing list -- time-nuts at lists.febo.com -- To unsubscribe send an email to time-nuts-leave at lists.febo.com
> To unsubscribe, go to and follow the instructions there.




More information about the Time-nuts_lists.febo.com mailing list