vanheusden.com

PPS synced MIDI metronome over BLE

The idea is as follows: I let an ESP32-C3 listen for a PPS (pulse per second) signal from a GPS and then let a metronome sync on that. The result would be send as MIDI messages of BLE (bluetooth-low-energy).

If it would've worked, I would have added a nice web-interface via which you could configure the beats-per-minute. Maybe make it configurable via MIDI messages as well, but:

TL;DR it doesn't work: the jitter of MIDI-BLE is around 100 milliseconds, more than 5 milliseconds is audible (for the average listener).

step one: connect a GPS to an ESP32-C3

This is simple enough. You only need the PPS pin of the GPS receiver (only interval is relevant, not the exact point in time). Cheap GPS modules (less than 3 Euro) can be obtained from e.g. aliexpress.

Next, in the software of the thing, attach an interrupt-handler to the pin on which the GPS is connected for a rising edge.

step two: measure the ESP32 C3 clock

My goal was to have an accurate metronome, like around 1 microsecond precision. The ESP32 SDK has a esp_timer_get_time function returning the the number of microseconds that ticked since the ESP32 was powered up (well and the timer functionality started). I then simply measure how my of those ticks ticked during a PPS interval. Then maybe pull the result through a Kalman filter, divide by a value to get the 'BPM' wanted (beats per minute) and sleep that duration between each MIDI message (compensate for the time it takes to send a message of course).

step three: send MIDI of BLE

Luckily someone had implemented a library for that: https://github.com/max22-/ESP32-BLE-MIDI.

step four: measure

ESP32 clockticks in a second interval

I added code to the Arduino-script that would print the measured clockticks-per-second each time a note was sent. This looked quite good:

S999974
S999974
S999974
S999974
S999974
S999974
S999975
S999973
S999974
S999974
S999975
S999973
S999975
S999974
S999974
...
(the 'S' means that the GPS-receiver is locked onto the GPS satellites).

MIDI over BLE

For this, I connected my laptop (over BLE) to the ESP32 (using the MIDI profile) and connected the virtual MIDI-port created on the Linux system to 'pw-mididump' (part of pipewire - the Linux audio system) using helvum (helvum is a software patchbay/router). pw-mididump shows the note played and also the timestamp where it was received - very convenient. Unfortunately this was the point where the ship beached - the jitter is horrible:

 833: track: 0 sec:1630.550659 Note On    (channel 10): note   A0, velocity 127
 834: track: 0 sec:1631.574707 Note On    (channel 10): note   A0, velocity 127
 528: track: 0 sec:1632.549683 Note On    (channel 10): note   A0, velocity 127
 526: track: 0 sec:1633.573608 Note On    (channel 10): note   A0, velocity 127
 534: track: 0 sec:1634.597778 Note On    (channel 10): note   A0, velocity 127
 226: track: 0 sec:1635.572632 Note On    (channel 10): note   A0, velocity 127
 946: track: 0 sec:1636.547607 Note On    (channel 10): note   A0, velocity 127
 950: track: 0 sec:1637.571777 Note On    (channel 10): note   A0, velocity 127
 638: track: 0 sec:1638.546631 Note On    (channel 10): note   A0, velocity 127
 590: track: 0 sec:1639.569702 Note On    (channel 10): note   A0, velocity 127
 284: track: 0 sec:1640.544678 Note On    (channel 10): note   A0, velocity 127
 338: track: 0 sec:1641.569702 Note On    (channel 10): note   A0, velocity 127
...
(look for the 'SEC:...' part).

Earlier I had tried to do this over MIDI-over-RTP (also called "Apple-MIDI", which is in this case MIDI over WIFI in RTP packets) but the jitter over WiFi was also dramatic. Anyway at this point I gave up.

picture

Click on the photo for higher resolution

source code

ubermetronome.src.zip (Arduino code)

Teensy 4.1 uC

Of course with a Teensy 4.1 microcontroller all problems disappear. Ok no BLE nor MIDI over WiFi, but MIDI over USB works very well!

Not synced to PPS:

  83: track: 0 sec:856.428406 Note On    (channel  1): note   C8, velocity  55
 600: track: 0 sec:857.420471 Note On    (channel  1): note  A#6, velocity  55
 638: track: 0 sec:858.424011 Note On    (channel  1): note  A#6, velocity  55
 453: track: 0 sec:859.422729 Note On    (channel  1): note  F#0, velocity  55
 378: track: 0 sec:860.423828 Note On    (channel  1): note  D#6, velocity  55
 398: track: 0 sec:861.427002 Note On    (channel  1): note   D2, velocity  55
 318: track: 0 sec:862.427979 Note On    (channel  1): note  A#0, velocity  55
 100: track: 0 sec:863.426086 Note On    (channel  1): note  C#6, velocity  55
  61: track: 0 sec:864.427917 Note On    (channel  1): note   B8, velocity  55

Teensy 4.1 clockticks in a second interval

S999992
S999992
S999993
S999992
S999992
S999992
S999992
S999992
S999992
S999992
S999992
S999992
S999992
S999993
S999992
S999992
S999992
S999992
Closer to the second.

MIDI timing over USB

 861: track: 0 sec:28627.666016 Note On    (channel 10): note   A0, velocity 127
 733: track: 0 sec:28628.666016 Note On    (channel 10): note   A0, velocity 127
 607: track: 0 sec:28629.666016 Note On    (channel 10): note   A0, velocity 127
 481: track: 0 sec:28630.666016 Note On    (channel 10): note   A0, velocity 127
 352: track: 0 sec:28631.666016 Note On    (channel 10): note   A0, velocity 127
 224: track: 0 sec:28632.666016 Note On    (channel 10): note   A0, velocity 127
  92: track: 0 sec:28633.666016 Note On    (channel 10): note   A0, velocity 127
 990: track: 0 sec:28634.666016 Note On    (channel 10): note   A0, velocity 127
 862: track: 0 sec:28635.666016 Note On    (channel 10): note   A0, velocity 127
 733: track: 0 sec:28636.666016 Note On    (channel 10): note   A0, velocity 127
 605: track: 0 sec:28637.666016 Note On    (channel 10): note   A0, velocity 127




For contact info, see this page.


bad crawlers